Version 0.5.4.0 .
svn merge -r 22222:22342 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@22349 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index 1abc0ef..c4b0ddc 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -110,7 +110,6 @@
'target_name': 'dart2js',
'type': 'none',
'dependencies': [
- 'third_party/v8/src/d8.gyp:d8',
'utils/compiler/compiler.gyp:dart2js',
],
},
@@ -150,7 +149,6 @@
'target_name': 'dart2js_bot',
'type': 'none',
'dependencies': [
- 'third_party/v8/src/d8.gyp:d8',
'create_sdk',
'packages',
],
diff --git a/pkg/http/test/safe_http_server.dart b/pkg/http/test/safe_http_server.dart
index b6e1c83..25d57ee 100644
--- a/pkg/http/test/safe_http_server.dart
+++ b/pkg/http/test/safe_http_server.dart
@@ -21,9 +21,9 @@
class SafeHttpServer extends StreamView<HttpRequest> implements HttpServer {
final HttpServer _inner;
- static Future<SafeHttpServer> bind([String host = "127.0.0.1",
+ static Future<SafeHttpServer> bind([String host = "localhost",
int port = 0, int backlog = 0]) {
- return HttpServer.bind(host, port, backlog)
+ return HttpServer.bind(host, port, backlog: backlog)
.then((server) => new SafeHttpServer(server));
}
diff --git a/pkg/scheduled_test/lib/scheduled_server.dart b/pkg/scheduled_test/lib/scheduled_server.dart
index cb17268..1e4e633 100644
--- a/pkg/scheduled_test/lib/scheduled_server.dart
+++ b/pkg/scheduled_test/lib/scheduled_server.dart
@@ -48,7 +48,7 @@
var scheduledServer;
scheduledServer = new ScheduledServer._(schedule(() {
- return SafeHttpServer.bind("127.0.0.1", 0).then((server) {
+ return SafeHttpServer.bind("localhost", 0).then((server) {
server.listen(scheduledServer._handleRequest,
onError: (e) => currentSchedule.signalError(e));
currentSchedule.onComplete.schedule(server.close);
diff --git a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
index b6e1c83..25d57ee 100644
--- a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
@@ -21,9 +21,9 @@
class SafeHttpServer extends StreamView<HttpRequest> implements HttpServer {
final HttpServer _inner;
- static Future<SafeHttpServer> bind([String host = "127.0.0.1",
+ static Future<SafeHttpServer> bind([String host = "localhost",
int port = 0, int backlog = 0]) {
- return HttpServer.bind(host, port, backlog)
+ return HttpServer.bind(host, port, backlog: backlog)
.then((server) => new SafeHttpServer(server));
}
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index 6e4c636..4bd4505 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -35,6 +35,7 @@
/// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
/// first line is prefixed with that instead.
String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
+ if (text == null) return '';
var lines = text.split('\n');
if (firstPrefix == null) {
return lines.map((line) => '$prefix$line').join('\n');
diff --git a/pkg/stack_trace/lib/src/frame.dart b/pkg/stack_trace/lib/src/frame.dart
index f05b469..cb7d656 100644
--- a/pkg/stack_trace/lib/src/frame.dart
+++ b/pkg/stack_trace/lib/src/frame.dart
@@ -85,7 +85,7 @@
throw new FormatException("Couldn't parse stack trace line '$frame'.");
}
- var uri = new Uri.fromString(match[2]);
+ var uri = Uri.parse(match[2]);
var member = match[1].replaceAll("<anonymous closure>", "<fn>");
return new Frame(uri, int.parse(match[3]), int.parse(match[4]), member);
}
diff --git a/pkg/stack_trace/test/frame_test.dart b/pkg/stack_trace/test/frame_test.dart
index 02bec68..826bad7 100644
--- a/pkg/stack_trace/test/frame_test.dart
+++ b/pkg/stack_trace/test/frame_test.dart
@@ -31,8 +31,7 @@
test('parses a stack frame correctly', () {
var frame = new Frame.parse("#1 Foo._bar "
"(file:///home/nweiz/code/stuff.dart:42:21)");
- expect(frame.uri,
- equals(new Uri.fromString("file:///home/nweiz/code/stuff.dart")));
+ expect(frame.uri, equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
expect(frame.line, equals(42));
expect(frame.column, equals(21));
expect(frame.member, equals('Foo._bar'));
diff --git a/pkg/stack_trace/test/trace_test.dart b/pkg/stack_trace/test/trace_test.dart
index cbbf90b..d3fa56e 100644
--- a/pkg/stack_trace/test/trace_test.dart
+++ b/pkg/stack_trace/test/trace_test.dart
@@ -41,10 +41,10 @@
''');
expect(trace.frames[0].uri,
- equals(new Uri.fromString("file:///home/nweiz/code/stuff.dart")));
- expect(trace.frames[1].uri, equals(new Uri.fromString("dart:async")));
+ equals(Uri.parse("file:///home/nweiz/code/stuff.dart")));
+ expect(trace.frames[1].uri, equals(Uri.parse("dart:async")));
expect(trace.frames[2].uri,
- equals(new Uri.fromString("http://pub.dartlang.org/thing.dart")));
+ equals(Uri.parse("http://pub.dartlang.org/thing.dart")));
});
test('parses a real stack trace correctly', () {
diff --git a/runtime/bin/filter.cc b/runtime/bin/filter.cc
index a423651..2193603 100644
--- a/runtime/bin/filter.cc
+++ b/runtime/bin/filter.cc
@@ -166,9 +166,10 @@
Dart_Handle Filter::SetFilterPointerNativeField(Dart_Handle filter,
Filter* filter_pointer) {
- return Dart_SetNativeInstanceField(filter,
- kFilterPointerNativeField,
- (intptr_t)filter_pointer);
+ return Dart_SetNativeInstanceField(
+ filter,
+ kFilterPointerNativeField,
+ reinterpret_cast<intptr_t>(filter_pointer));
}
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index ddaf345..38bc31a 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -41,7 +41,7 @@
V(Process_Exit, 1) \
V(Process_Sleep, 1) \
V(Process_Pid, 1) \
- V(ServerSocket_CreateBindListen, 4) \
+ V(ServerSocket_CreateBindListen, 5) \
V(ServerSocket_Accept, 2) \
V(Socket_CreateConnect, 3) \
V(Socket_Available, 1) \
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 851104a..1134889 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -383,12 +383,15 @@
Dart_Handle result = GetSockAddr(host_obj, &addr);
Dart_Handle port_obj = Dart_GetNativeArgument(args, 2);
Dart_Handle backlog_obj = Dart_GetNativeArgument(args, 3);
+ Dart_Handle v6_only_obj = Dart_GetNativeArgument(args, 4);
+ bool v6_only = DartUtils::GetBooleanValue(v6_only_obj);
int64_t port = 0;
int64_t backlog = 0;
if (!Dart_IsError(result) &&
DartUtils::GetInt64Value(port_obj, &port) &&
DartUtils::GetInt64Value(backlog_obj, &backlog)) {
- intptr_t socket = ServerSocket::CreateBindListen(addr, port, backlog);
+ intptr_t socket = ServerSocket::CreateBindListen(
+ addr, port, backlog, v6_only);
OSError error;
Dart_TypedDataReleaseData(host_obj);
if (socket >= 0) {
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 99a0078..5c191a0 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -176,7 +176,8 @@
// -5: invalid bindAddress
static intptr_t CreateBindListen(RawAddr addr,
intptr_t port,
- intptr_t backlog);
+ intptr_t backlog,
+ bool v6_only = false);
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(ServerSocket);
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index e4b99bd..8bb8f07 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -195,7 +195,8 @@
intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
- intptr_t backlog) {
+ intptr_t backlog,
+ bool v6_only) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
@@ -208,7 +209,7 @@
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
- optval = 0;
+ optval = v6_only ? 1 : 0;
TEMP_FAILURE_RETRY(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index e881f5d..cfc9b12 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -207,7 +207,8 @@
intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
- intptr_t backlog) {
+ intptr_t backlog,
+ bool v6_only) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
@@ -220,7 +221,7 @@
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
- optval = 0;
+ optval = v6_only ? 1 : 0;
TEMP_FAILURE_RETRY(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index bf17056..94363fb 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -207,7 +207,8 @@
intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
- intptr_t backlog) {
+ intptr_t backlog,
+ bool v6_only) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
@@ -220,7 +221,7 @@
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
- optval = 0;
+ optval = v6_only ? 1 : 0;
VOID_TEMP_FAILURE_RETRY(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index 1515403..d10f3ae 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -3,10 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
patch class RawServerSocket {
- /* patch */ static Future<RawServerSocket> bind([address = "127.0.0.1",
- int port = 0,
- int backlog = 0]) {
- return _RawServerSocket.bind(address, port, backlog);
+ /* patch */ static Future<RawServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false}) {
+ return _RawServerSocket.bind(address, port, backlog, v6Only);
}
}
@@ -36,7 +37,7 @@
}
/* patch */ static Future<List<InternetAddress>> lookup(
- String host, {InternetAddressType type: InternetAddressType.IP_V4}) {
+ String host, {InternetAddressType type: InternetAddressType.ANY}) {
return _NativeSocket.lookup(host, type: type);
}
}
@@ -158,7 +159,7 @@
static SendPort socketService;
static Future<List<InternetAddress>> lookup(
- String host, {InternetAddressType type: InternetAddressType.IP_V4}) {
+ String host, {InternetAddressType type: InternetAddressType.ANY}) {
ensureSocketService();
return socketService.call([HOST_NAME_LOOKUP, host, type._value])
.then((response) {
@@ -215,7 +216,8 @@
static Future<_NativeSocket> bind(host,
int port,
- int backlog) {
+ int backlog,
+ bool v6Only) {
return new Future.value(host)
.then((host) {
if (host is _InternetAddress) return host;
@@ -232,7 +234,8 @@
socket.address = address;
var result = socket.nativeCreateBindListen(address._sockaddr_storage,
port,
- backlog);
+ backlog,
+ v6Only);
if (result is OSError) {
throw new SocketIOException(
"Failed to create server socket", result);
@@ -526,7 +529,7 @@
native "Socket_WriteList";
nativeCreateConnect(List<int> addr,
int port) native "Socket_CreateConnect";
- nativeCreateBindListen(List<int> addr, int port, int backlog)
+ nativeCreateBindListen(List<int> addr, int port, int backlog, bool v6Only)
native "ServerSocket_CreateBindListen";
nativeAccept(_NativeSocket socket) native "ServerSocket_Accept";
int nativeGetPort() native "Socket_GetPort";
@@ -545,11 +548,12 @@
static Future<_RawServerSocket> bind(address,
int port,
- int backlog) {
+ int backlog,
+ bool v6Only) {
if (port < 0 || port > 0xFFFF)
throw new ArgumentError("Invalid port $port");
if (backlog < 0) throw new ArgumentError("Invalid backlog $backlog");
- return _NativeSocket.bind(address, port, backlog)
+ return _NativeSocket.bind(address, port, backlog, v6Only)
.then((socket) => new _RawServerSocket(socket));
}
@@ -602,6 +606,7 @@
close();
}
}
+
void _onPauseStateChange() {
if (_controller.isPaused) {
_pause();
@@ -737,10 +742,11 @@
patch class ServerSocket {
- /* patch */ static Future<ServerSocket> bind([address = "127.0.0.1",
- int port = 0,
- int backlog = 0]) {
- return _ServerSocket.bind(address, port, backlog);
+ /* patch */ static Future<ServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false}) {
+ return _ServerSocket.bind(address, port, backlog, v6Only);
}
}
@@ -750,8 +756,9 @@
static Future<_ServerSocket> bind(address,
int port,
- int backlog) {
- return _RawServerSocket.bind(address, port, backlog)
+ int backlog,
+ bool v6Only) {
+ return _RawServerSocket.bind(address, port, backlog, v6Only)
.then((socket) => new _ServerSocket(socket));
}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index 12b76d8..e8b0d47 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -239,7 +239,8 @@
intptr_t ServerSocket::CreateBindListen(RawAddr addr,
intptr_t port,
- intptr_t backlog) {
+ intptr_t backlog,
+ bool v6_only) {
SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET) {
return -1;
@@ -259,7 +260,7 @@
}
if (addr.ss.ss_family == AF_INET6) {
- optval = false;
+ optval = v6_only;
setsockopt(s,
IPPROTO_IPV6,
IPV6_V6ONLY,
diff --git a/runtime/embedders/openglui/build_skia.sh b/runtime/embedders/openglui/build_skia.sh
index 9eca1dc..5190f10 100755
--- a/runtime/embedders/openglui/build_skia.sh
+++ b/runtime/embedders/openglui/build_skia.sh
@@ -72,7 +72,7 @@
if [ ${CLEAN} != 0 ] ; then
../android/bin/android_make -d $TARGET_ARCH -j clean
else
- env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j
+ env -i BUILDTYPE=$BUILD ANDROID_SDK_ROOT="${ANDROID_SDK_ROOT}" PATH="${PATH}:${DART_DIR}/third_party/gsutil" ../android/bin/android_make BUILDTYPE=$BUILD -d $TARGET_ARCH -j --debug=j
fi
else
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index 8ee9dd3..55d3626 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -221,6 +221,32 @@
int operator ~() native "Smi_bitNegate";
int _shrFromInt(int other) native "Smi_shrFromInt";
int _shlFromInt(int other) native "Smi_shlFromInt";
+
+ String toString() {
+ if (this == 0) return "0";
+ var reversed = new List();
+ var val = this < 0 ? -this : this;
+ while (val > 0) {
+ reversed.add((val % 10) + 0x30);
+ val = val ~/ 10;
+ }
+ final int numDigits = reversed.length;
+ List digits;
+ int i;
+ if (this < 0) {
+ digits = new List(numDigits + 1);
+ digits[0] = 0x2D; // '-'.
+ i = 1;
+ } else {
+ digits = new List(numDigits);
+ i = 0;
+ }
+ int ri = reversed.length - 1;
+ for (; i < digits.length; i++, ri--) {
+ digits[i] = reversed[ri];
+ }
+ return _StringBase.createFromCharCodes(digits);
+ }
}
// Represents integers that cannot be represented by Smi but fit into 64bits.
diff --git a/runtime/lib/string.cc b/runtime/lib/string.cc
index 9a06b24..761541a 100644
--- a/runtime/lib/string.cc
+++ b/runtime/lib/string.cc
@@ -19,7 +19,6 @@
args.SetAt(0, list);
Exceptions::ThrowByType(Exceptions::kArgument, args);
}
- // TODO(srdjan): Check that parameterized type is an int.
Array& a = Array::Handle();
intptr_t array_len;
diff --git a/runtime/lib/string_patch.dart b/runtime/lib/string_patch.dart
index 2d148ec..f20f8b0 100644
--- a/runtime/lib/string_patch.dart
+++ b/runtime/lib/string_patch.dart
@@ -27,9 +27,13 @@
* [codePoints].
*/
static String createFromCharCodes(Iterable<int> charCodes) {
- if (charCodes is! _ObjectArray && charCodes is! _GrowableObjectArray) {
+ // TODO(srdjan): Also skip copying of typed arrays.
+ if (charCodes is! _ObjectArray &&
+ charCodes is! _GrowableObjectArray &&
+ charCodes is! _ImmutableArray) {
charCodes = new List<int>.from(charCodes, growable: false);
}
+
return _createFromCodePoints(charCodes);
}
@@ -314,7 +318,7 @@
*/
static String _interpolate(List values) {
int numValues = values.length;
- var stringList = new List(numValues);
+ _ObjectArray stringList = new List(numValues);
for (int i = 0; i < numValues; i++) {
stringList[i] = values[i].toString();
}
@@ -428,7 +432,7 @@
return _concatAll(stringsArray);
}
- static String _concatAll(List<String> strings)
+ static String _concatAll(_ObjectArray<String> strings)
native "Strings_concatAll";
}
diff --git a/runtime/tests/vm/dart/inline_stack_frame_test.dart b/runtime/tests/vm/dart/inline_stack_frame_test.dart
index f8592ac..62fa819 100644
--- a/runtime/tests/vm/dart/inline_stack_frame_test.dart
+++ b/runtime/tests/vm/dart/inline_stack_frame_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.
+// VMOptions=--optimization_counter_threshold=10
+
import "package:expect/expect.dart";
// This test tries to verify that we produce the correct stack trace when
@@ -50,7 +52,7 @@
return result;
}
int func5(var i) {
- if (i >= 1030) throw "show me inlined functions";
+ if (i >= 520) throw "show me inlined functions";
return i;
}
}
@@ -64,7 +66,7 @@
Expect.isTrue(result.contains("Test.func3"));
Expect.isTrue(result.contains("Test.func4"));
Expect.isTrue(result.contains("Test.func"));
- for (var i = 0; i <= 200; i++) {
+ for (var i = 0; i <= 10; i++) {
result = x.func1(i);
}
Expect.isTrue(result.contains("show me inlined functions"));
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 26005da..529a615 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -61,8 +61,9 @@
# Tests missing code generation support.
cc/Dart2JSCompileAll: Skip
cc/CorelibCompileAll: Skip
-# Tests needing Dart execution.
-dart/*: Skip
+dart/byte_array_test: Skip
+dart/byte_array_optimized_test: Skip
+dart/inline_stack_frame_test: Skip
[ $arch == mips ]
*: Skip
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 49d0db2..d55fab9 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -100,10 +100,14 @@
uint32_t Address::encoding3() const {
- ASSERT(kind_ == Immediate);
- uint32_t offset = encoding_ & kOffset12Mask;
- ASSERT(offset < 256);
- return (encoding_ & ~kOffset12Mask) | ((offset & 0xf0) << 4) | (offset & 0xf);
+ if (kind_ == Immediate) {
+ uint32_t offset = encoding_ & kOffset12Mask;
+ ASSERT(offset < 256);
+ return (encoding_ & ~kOffset12Mask) | B22 |
+ ((offset & 0xf0) << 4) | (offset & 0xf);
+ }
+ ASSERT(kind_ == IndexRegister);
+ return encoding_;
}
@@ -192,7 +196,6 @@
ASSERT(rd != kNoRegister);
ASSERT(cond != kNoCondition);
int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B22 |
mode |
(static_cast<int32_t>(rd) << kRdShift) |
ad.encoding3();
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 7039d8b..849b644 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -216,7 +216,8 @@
public:
enum OffsetKind {
Immediate,
- ShiftedRegister,
+ IndexRegister,
+ ScaledIndexRegister,
};
// Memory operand addressing mode
@@ -255,7 +256,11 @@
Shift shift = LSL, uint32_t shift_imm = 0, Mode am = Offset) {
ShifterOperand so(rm, shift, shift_imm);
- kind_ = ShiftedRegister;
+ if ((shift == LSL) && (shift_imm == 0)) {
+ kind_ = IndexRegister;
+ } else {
+ kind_ = ScaledIndexRegister;
+ }
encoding_ = so.encoding() | am | (static_cast<uint32_t>(rn) << kRnShift);
}
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index a7e8f2b..7a18568 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -789,9 +789,7 @@
ASSEMBLER_TEST_GENERATE(Ldrh, assembler) {
- Label Test1;
- Label Test2;
- Label Done;
+ Label Test1, Test2, Test3, Done;
__ mov(R1, ShifterOperand(0x11));
__ mov(R2, ShifterOperand(SP));
@@ -803,16 +801,26 @@
__ b(&Done);
__ Bind(&Test1);
- __ mov(R0, ShifterOperand(0));
+ __ mov(R0, ShifterOperand(0x22));
__ strh(R0, Address(R2, (-kWordSize * 30)));
__ ldrh(R1, Address(R2, (-kWordSize * 30)));
- __ cmp(R1, ShifterOperand(0));
+ __ cmp(R1, ShifterOperand(0x22));
__ b(&Test2, EQ);
__ mov(R0, ShifterOperand(1));
__ b(&Done);
__ Bind(&Test2);
__ mov(R0, ShifterOperand(0));
+ __ AddImmediate(R2, (-kWordSize * 30));
+ __ strh(R0, Address(R2));
+ __ ldrh(R1, Address(R2));
+ __ cmp(R1, ShifterOperand(0));
+ __ b(&Test3, EQ);
+ __ mov(R0, ShifterOperand(1));
+ __ b(&Done);
+ __ Bind(&Test3);
+
+ __ mov(R0, ShifterOperand(0));
__ Bind(&Done);
__ ldr(R1, Address(SP, (kWordSize * 30), Address::PostIndex));
__ mov(PC, ShifterOperand(LR));
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index d4029ce..3f496db 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -81,7 +81,7 @@
void Assembler::AdduDetectOverflow(Register rd, Register rs, Register rt,
- Register ro) {
+ Register ro, Register scratch) {
ASSERT(rd != ro);
ASSERT(rd != TMP1);
ASSERT(ro != TMP1);
@@ -89,12 +89,14 @@
ASSERT(ro != rt);
if ((rs == rt) && (rd == rs)) {
- ASSERT(rd != TMP2);
- ASSERT(ro != TMP2);
- ASSERT(rs != TMP2);
- ASSERT(rt != TMP2);
- mov(TMP2, rt);
- rt = TMP2;
+ ASSERT(scratch != kNoRegister);
+ ASSERT(scratch != TMP1);
+ ASSERT(rd != scratch);
+ ASSERT(ro != scratch);
+ ASSERT(rs != scratch);
+ ASSERT(rt != scratch);
+ mov(scratch, rt);
+ rt = scratch;
}
if (rd == rs) {
@@ -236,8 +238,8 @@
sll(TMP1, value, kObjectAlignmentLog2 - 1);
and_(TMP1, value, TMP1);
// And the result with the negated space bit of the object.
- nor(TMP2, ZR, object);
- and_(TMP1, TMP1, TMP2);
+ nor(CMPRES, ZR, object);
+ and_(TMP1, TMP1, CMPRES);
andi(TMP1, TMP1, Immediate(kNewObjectAlignmentOffset));
beq(TMP1, ZR, no_update);
}
@@ -371,6 +373,24 @@
}
+void Assembler::LeaveStubFrameAndReturn(Register ra, bool uses_pp) {
+ if (uses_pp) {
+ addiu(SP, FP, Immediate(-1 * kWordSize));
+ lw(RA, Address(SP, 2 * kWordSize));
+ lw(FP, Address(SP, 1 * kWordSize));
+ lw(PP, Address(SP, 0 * kWordSize));
+ jr(ra);
+ delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize));
+ } else {
+ mov(SP, FP);
+ lw(RA, Address(SP, 1 * kWordSize));
+ lw(FP, Address(SP, 0 * kWordSize));
+ jr(ra);
+ delay_slot()->addiu(SP, SP, Immediate(3 * kWordSize));
+ }
+}
+
+
void Assembler::CallRuntime(const RuntimeEntry& entry) {
entry.Call(this);
}
@@ -420,15 +440,16 @@
}
-void Assembler::LeaveDartFrame() {
+void Assembler::LeaveDartFrameAndReturn() {
addiu(SP, FP, Immediate(-kWordSize));
lw(RA, Address(SP, 2 * kWordSize));
lw(FP, Address(SP, 1 * kWordSize));
lw(PP, Address(SP, 0 * kWordSize));
- // Adjust SP for PC pushed in EnterDartFrame.
- addiu(SP, SP, Immediate(4 * kWordSize));
+ // Adjust SP for PC pushed in EnterDartFrame, and return.
+ Ret();
+ delay_slot()->addiu(SP, SP, Immediate(4 * kWordSize));
}
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 8269737..07d19bc 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -171,6 +171,9 @@
// a stub frame.
void EnterStubFrame(bool uses_pp = false);
void LeaveStubFrame(bool uses_pp = false);
+ // A separate macro for when a Ret immediately follows, so that we can use
+ // the branch delay slot.
+ void LeaveStubFrameAndReturn(Register ra = RA, bool uses_pp = false);
// Instruction pattern from entrypoint is used in dart frame prologs
// to set up the frame and save a PC which can be used to figure out the
@@ -571,16 +574,21 @@
// Addition of rs and rt with the result placed in rd.
// After, ro < 0 if there was signed overflow, ro >= 0 otherwise.
- // rd and ro must not be TMP1 or TMP2.
+ // rd and ro must not be TMP1.
// ro must be different from all the other registers.
- void AdduDetectOverflow(Register rd, Register rs, Register rt, Register ro);
+ // If rd, rs, and rt are the same register, then a scratch register different
+ // from the other registers is needed.
+ void AdduDetectOverflow(Register rd, Register rs, Register rt, Register ro,
+ Register scratch = kNoRegister);
// ro must be different from rd and rs.
- // rd and ro must not be TMP1 or TMP2
+ // rd and ro must not be TMP1.
+ // If rd and rs are the same, a scratch register different from the other
+ // registers is needed.
void AddImmediateDetectOverflow(Register rd, Register rs, int32_t imm,
- Register ro) {
+ Register ro, Register scratch = kNoRegister) {
LoadImmediate(rd, imm);
- AdduDetectOverflow(rd, rs, rd, ro);
+ AdduDetectOverflow(rd, rs, rd, ro, scratch);
}
// Subtraction of rt from rs (rs - rt) with the result placed in rd.
@@ -845,7 +853,7 @@
// enable easy access to the RawInstruction object of code corresponding
// to this frame.
void EnterDartFrame(intptr_t frame_size);
- void LeaveDartFrame();
+ void LeaveDartFrameAndReturn();
private:
AssemblerBuffer buffer_;
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index be5c939..f4cdcdc 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -1060,6 +1060,7 @@
Register right = T1;
Register result = T2;
Register overflow = T3;
+ Register scratch = T4;
Label error, done;
__ LoadImmediate(V0, 1); // Success value.
@@ -1094,7 +1095,7 @@
__ bgez(overflow, &error); // INT_MIN - 1 overflows.
// result has 0x7fffffff.
- __ AdduDetectOverflow(result, result, result, overflow);
+ __ AdduDetectOverflow(result, result, result, overflow, scratch);
__ bgez(overflow, &error); // INT_MAX + INT_MAX overflows.
__ LoadImmediate(left, 0x80000000);
diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index d88e130..c0d1172 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -287,7 +287,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::FinalizePendingClasses());
@@ -334,7 +334,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::FinalizePendingClasses());
@@ -521,7 +521,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = MakeTestLibrary("TestLib");
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::FinalizePendingClasses());
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index dc2e042..60af119 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -170,7 +170,7 @@
// Collect all instance fields that are loaded in the graph and
// have non-generic type feedback attached to them that can
// potentially affect optimizations.
- GrowableArray<Field*> guarded_fields(10);
+ GrowableArray<const Field*> guarded_fields(10);
if (optimized) {
TimerScope timer(FLAG_compiler_stats,
&CompilerStats::graphoptimizer_timer,
@@ -291,7 +291,14 @@
propagator.Propagate();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
}
- optimizer.Canonicalize();
+ if (optimizer.Canonicalize()) {
+ // To fully remove redundant boxing (e.g. BoxDouble used only in
+ // environments and UnboxDouble instructions) instruction we
+ // first need to replace all their uses and then fold them away.
+ // For now we just repeat Canonicalize twice to do that.
+ // TODO(vegorov): implement a separate representation folding pass.
+ optimizer.Canonicalize();
+ }
DEBUG_ASSERT(flow_graph->VerifyUseLists());
// Perform register allocation on the SSA graph.
diff --git a/runtime/vm/compiler_test.cc b/runtime/vm/compiler_test.cc
index 0058593..2287be2 100644
--- a/runtime/vm/compiler_test.cc
+++ b/runtime/vm/compiler_test.cc
@@ -25,7 +25,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = Library::Handle(Library::CoreLibrary());
EXPECT(CompilerTest::TestCompileScript(lib, script));
}
@@ -43,7 +43,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = Library::Handle(Library::CoreLibrary());
EXPECT(CompilerTest::TestCompileScript(lib, script));
EXPECT(ClassFinalizer::FinalizePendingClasses());
diff --git a/runtime/vm/constants_mips.h b/runtime/vm/constants_mips.h
index 0668062..5859800 100644
--- a/runtime/vm/constants_mips.h
+++ b/runtime/vm/constants_mips.h
@@ -139,7 +139,6 @@
// Register aliases.
const Register TMP1 = AT; // Used as scratch register by assembler.
-const Register TMP2 = T9; // Used as scratch register by assembler.
const Register TMP = TMP1; // Arch independent flow graph compiler needs a
// Register called TMP.
const Register CTX = S6; // Caches current context in generated code.
@@ -147,10 +146,17 @@
const Register SPREG = SP; // Stack pointer register.
const Register FPREG = FP; // Frame pointer register.
+// NULLREG holds reinterpret_cast<intptr_t>(Object::null()).
+// TODO(zra): Is it worthwhile to devote a register to this? Investigate
+// performance effects when we are running on real hardware. Same with
+// CMPRES. Try moving CTX and PP to T8 and T9 and shifting kLastCpuRegister
+// down to S7.
+const Register NULLREG = T8;
+
// The code that generates a comparison can be far away from the code that
// generates the branch that uses the result of that comparison. In this case,
// CMPRES is used for the result of the comparison.
-const Register CMPRES = T8;
+const Register CMPRES = T9;
// Exception object is passed in this register to the catch handlers when an
// exception is thrown.
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index f79c008..6008c9c 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -5653,7 +5653,7 @@
const char* kLibrary1Chars =
"library library1_name;";
const char* kSourceChars =
- "// Something innocuous";
+ "part of library1_name;\n// Something innocuous";
const char* kBadSourceChars =
")";
Dart_Handle error = Dart_Error("incoming error");
@@ -5739,6 +5739,7 @@
" foo() => 'foo';\n"
"}\n";
const char* kSourceChars =
+ "part of library1_name;\n"
"class NewClass extends OldClass{\n"
" bar() => 'bar';\n"
"}\n";
@@ -5781,6 +5782,7 @@
const char* kLibrary1Chars =
"library library1_name;";
const char* kSourceChars =
+ "part of library1_name;\n"
"external int foo();";
const char* kPatchChars =
"patch int foo() => 42;";
@@ -7515,6 +7517,7 @@
TEST_CASE(LazyLoadDeoptimizes) {
const char* kLoadFirst =
+ "library L;\n"
"start(a) {\n"
" var obj = (a == 1) ? createB() : new A();\n"
" for (int i = 0; i < 4000; i++) {\n"
@@ -7531,6 +7534,7 @@
" goo() => 2;\n"
"}\n";
const char* kLoadSecond =
+ "part of L;"
"class B extends A {\n"
" goo() => 1;\n"
"}\n";
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 0692ef5..c125731 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -900,38 +900,34 @@
Code& code = Code::Handle(isolate);
StackFrameIterator iterator(false);
StackFrame* frame = iterator.NextFrame();
+ ActivationFrame* callee_activation = NULL;
bool optimized_frame_found = false;
while (frame != NULL) {
ASSERT(frame->IsValid());
if (frame->IsDartFrame()) {
code = frame->LookupDartCode();
- ActivationFrame* activation = new ActivationFrame(frame->pc(),
- frame->fp(),
- frame->sp(),
- code);
+ ActivationFrame* activation =
+ new ActivationFrame(frame->pc(), frame->fp(), frame->sp(), code);
// If this activation frame called a closure, the function has
// saved its context before the call.
- if (stack_trace->Length() > 0) {
- ActivationFrame* callee_frame =
- stack_trace->ActivationFrameAt(stack_trace->Length() - 1);
- if (callee_frame->function().IsClosureFunction()) {
- ctx = activation->GetSavedCurrentContext();
- if (FLAG_verbose_debug && ctx.IsNull()) {
- const Function& caller = activation->function();
- const Function& callee = callee_frame->function();
- const Script& script =
- Script::Handle(Class::Handle(caller.Owner()).script());
- intptr_t line, col;
- script.GetTokenLocation(activation->TokenPos(), &line, &col);
- printf("CollectStackTrace error: no saved context in function "
- "'%s' which calls closure '%s' "
- " in line %"Pd" column %"Pd"\n",
- caller.ToFullyQualifiedCString(),
- callee.ToFullyQualifiedCString(),
- line, col);
- }
- ASSERT(!ctx.IsNull());
+ if ((callee_activation != NULL) &&
+ (callee_activation->function().IsClosureFunction())) {
+ ctx = activation->GetSavedCurrentContext();
+ if (FLAG_verbose_debug && ctx.IsNull()) {
+ const Function& caller = activation->function();
+ const Function& callee = callee_activation->function();
+ const Script& script =
+ Script::Handle(Class::Handle(caller.Owner()).script());
+ intptr_t line, col;
+ script.GetTokenLocation(activation->TokenPos(), &line, &col);
+ OS::Print("CollectStackTrace error: no saved context in function "
+ "'%s' which calls closure '%s' "
+ " in line %"Pd" column %"Pd"\n",
+ caller.ToFullyQualifiedCString(),
+ callee.ToFullyQualifiedCString(),
+ line, col);
}
+ ASSERT(!ctx.IsNull());
}
if (optimized_frame_found || code.is_optimized()) {
// Set context to null, to avoid returning bad context variable values.
@@ -941,10 +937,12 @@
activation->SetContext(ctx);
}
stack_trace->AddActivation(activation);
+ callee_activation = activation;
// Get caller's context if this function saved it on entry.
ctx = activation->GetSavedEntryContext(ctx);
} else if (frame->IsEntryFrame()) {
ctx = reinterpret_cast<EntryFrame*>(frame)->SavedContext();
+ callee_activation = NULL;
}
frame = iterator.NextFrame();
}
@@ -961,7 +959,7 @@
Dart_ExceptionPauseInfo Debugger::GetExceptionPauseInfo() {
- return (Dart_ExceptionPauseInfo)exc_pause_info_;
+ return exc_pause_info_;
}
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index cef4502..9291b91 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -378,7 +378,7 @@
// be run as a side effect of getting values of fields.
bool ignore_breakpoints_;
- intptr_t exc_pause_info_;
+ Dart_ExceptionPauseInfo exc_pause_info_;
static BreakpointHandler* bp_handler_;
static EventHandler* event_handler_;
diff --git a/runtime/vm/debugger_mips.cc b/runtime/vm/debugger_mips.cc
index a234dcd..dcf7df6 100644
--- a/runtime/vm/debugger_mips.cc
+++ b/runtime/vm/debugger_mips.cc
@@ -31,21 +31,19 @@
void CodeBreakpoint::PatchFunctionReturn() {
- Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
- Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
- Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
- Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
- Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
- Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
+ Instr* instr1 = Instr::At(pc_ - 5 * Instr::kInstrSize);
+ Instr* instr2 = Instr::At(pc_ - 4 * Instr::kInstrSize);
+ Instr* instr3 = Instr::At(pc_ - 3 * Instr::kInstrSize);
+ Instr* instr4 = Instr::At(pc_ - 2 * Instr::kInstrSize);
+ Instr* instr5 = Instr::At(pc_ - 1 * Instr::kInstrSize);
#if defined(DEBUG)
instr1->AssertIsImmInstr(LW, SP, RA, 2 * kWordSize);
instr2->AssertIsImmInstr(LW, SP, FP, 1 * kWordSize);
instr3->AssertIsImmInstr(LW, SP, PP, 0 * kWordSize);
- instr4->AssertIsImmInstr(ADDIU, SP, SP, 4 * kWordSize);
- instr5->AssertIsSpecialInstr(JR, RA, ZR, ZR);
- ASSERT(instr6->InstructionBits() == Instr::kNopInstruction);
+ instr4->AssertIsSpecialInstr(JR, RA, ZR, ZR);
+ instr5->AssertIsImmInstr(ADDIU, SP, SP, 4 * kWordSize);
#endif // defined(DEBUG)
// Smash code with call instruction and target address.
@@ -57,34 +55,31 @@
// than the sequence we are replacing. We pad at the top with nops so that
// the end of the new sequence is lined up with the code descriptor.
instr1->SetInstructionBits(Instr::kNopInstruction);
- instr2->SetInstructionBits(Instr::kNopInstruction);
- instr3->SetImmInstrBits(LUI, ZR, TMP1, target_hi);
- instr4->SetImmInstrBits(ORI, TMP1, TMP1, target_lo);
- instr5->SetSpecialInstrBits(JALR, TMP1, ZR, RA);
- instr6->SetInstructionBits(Instr::kNopInstruction);
+ instr2->SetImmInstrBits(LUI, ZR, TMP1, target_hi);
+ instr3->SetImmInstrBits(ORI, TMP1, TMP1, target_lo);
+ instr4->SetSpecialInstrBits(JALR, TMP1, ZR, RA);
+ instr5->SetInstructionBits(Instr::kNopInstruction);
- CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
+ CPU::FlushICache(pc_ - 5 * Instr::kInstrSize, 5 * Instr::kInstrSize);
}
void CodeBreakpoint::RestoreFunctionReturn() {
- Instr* instr1 = Instr::At(pc_ - 6 * Instr::kInstrSize);
- Instr* instr2 = Instr::At(pc_ - 5 * Instr::kInstrSize);
- Instr* instr3 = Instr::At(pc_ - 4 * Instr::kInstrSize);
- Instr* instr4 = Instr::At(pc_ - 3 * Instr::kInstrSize);
- Instr* instr5 = Instr::At(pc_ - 2 * Instr::kInstrSize);
- Instr* instr6 = Instr::At(pc_ - 1 * Instr::kInstrSize);
+ Instr* instr1 = Instr::At(pc_ - 5 * Instr::kInstrSize);
+ Instr* instr2 = Instr::At(pc_ - 4 * Instr::kInstrSize);
+ Instr* instr3 = Instr::At(pc_ - 3 * Instr::kInstrSize);
+ Instr* instr4 = Instr::At(pc_ - 2 * Instr::kInstrSize);
+ Instr* instr5 = Instr::At(pc_ - 1 * Instr::kInstrSize);
- ASSERT(instr3->OpcodeField() == LUI && instr3->RtField() == TMP1);
+ ASSERT(instr2->OpcodeField() == LUI && instr2->RtField() == TMP1);
instr1->SetImmInstrBits(LW, SP, RA, 2 * kWordSize);
instr2->SetImmInstrBits(LW, SP, FP, 1 * kWordSize);
instr3->SetImmInstrBits(LW, SP, PP, 0 * kWordSize);
- instr4->SetImmInstrBits(ADDIU, SP, SP, 4 * kWordSize);
- instr5->SetSpecialInstrBits(JR, RA, ZR, ZR);
- instr6->SetInstructionBits(Instr::kNopInstruction);
+ instr4->SetSpecialInstrBits(JR, RA, ZR, ZR);
+ instr5->SetImmInstrBits(ADDIU, SP, SP, 4 * kWordSize);
- CPU::FlushICache(pc_ - 6 * Instr::kInstrSize, 6 * Instr::kInstrSize);
+ CPU::FlushICache(pc_ - 5 * Instr::kInstrSize, 5 * Instr::kInstrSize);
}
} // namespace dart
diff --git a/runtime/vm/find_code_object_test.cc b/runtime/vm/find_code_object_test.cc
index 94fee57..3200439 100644
--- a/runtime/vm/find_code_object_test.cc
+++ b/runtime/vm/find_code_object_test.cc
@@ -56,7 +56,7 @@
}
OS::SNPrint((scriptChars + written), (kScriptSize - written), "}");
source = String::New(scriptChars);
- script = Script::New(url, source, RawScript::kSourceTag);
+ script = Script::New(url, source, RawScript::kScriptTag);
EXPECT(CompilerTest::TestCompileScript(lib, script));
clsA = lib.LookupClass(String::Handle(Symbols::New("A")));
EXPECT(!clsA.IsNull());
@@ -104,7 +104,7 @@
OS::SNPrint((scriptChars + written), (kScriptSize - written), "}");
url = String::New("dart-test:FindCodeObject");
source = String::New(scriptChars);
- script = Script::New(url, source, RawScript::kSourceTag);
+ script = Script::New(url, source, RawScript::kScriptTag);
EXPECT(CompilerTest::TestCompileScript(lib, script));
clsB = lib.LookupClass(String::Handle(Symbols::New("B")));
EXPECT(!clsB.IsNull());
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index b4b833a..a1d6e6b 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -2634,6 +2634,7 @@
for_instance.value(),
node->field().Offset(),
AbstractType::ZoneHandle(node->field().type()));
+ load->set_field(&node->field());
ReturnDefinition(load);
}
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 2c286f1..6451979 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -91,14 +91,19 @@
const SubtypeTestCache& type_test_cache =
SubtypeTestCache::ZoneHandle(SubtypeTestCache::New());
__ LoadObject(A2, type_test_cache);
+ intptr_t null = reinterpret_cast<intptr_t>(Object::null());
+ uint16_t null_lo = Utils::Low16Bits(null);
+ uint16_t null_hi = Utils::High16Bits(null);
if (test_kind == kTestTypeOneArg) {
ASSERT(type_arguments_reg == kNoRegister);
- __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null()));
+ __ lui(A1, Immediate(null_hi));
__ BranchLink(&StubCode::Subtype1TestCacheLabel());
+ __ delay_slot()->ori(A1, A1, Immediate(null_lo));
} else if (test_kind == kTestTypeTwoArgs) {
ASSERT(type_arguments_reg == kNoRegister);
- __ LoadImmediate(A1, reinterpret_cast<intptr_t>(Object::null()));
+ __ lui(A1, Immediate(null_hi));
__ BranchLink(&StubCode::Subtype2TestCacheLabel());
+ __ delay_slot()->ori(A1, A1, Immediate(null_lo));
} else if (test_kind == kTestTypeThreeArgs) {
ASSERT(type_arguments_reg == A1);
__ BranchLink(&StubCode::Subtype3TestCacheLabel());
@@ -469,10 +474,11 @@
// Preserve instantiator and its type arguments.
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(A2, Address(SP, 1 * kWordSize));
- __ sw(A1, Address(SP, 0 * kWordSize));
+
// A null object is always assignable and is returned as result.
Label is_assignable, runtime_call;
__ BranchEqual(A0, reinterpret_cast<int32_t>(Object::null()), &is_assignable);
+ __ delay_slot()->sw(A1, Address(SP, 0 * kWordSize));
if (!FLAG_eliminate_type_checks) {
// If type checks are not eliminated during the graph building then
@@ -626,20 +632,17 @@
__ AddImmediate(T0, FP, (kFirstLocalSlotIndex + 1) * kWordSize);
__ sll(T2, T2, 1); // T2 is a Smi.
- Label loop, loop_condition;
- __ b(&loop_condition);
+ Label loop, loop_exit;
+ __ blez(T2, &loop_exit);
__ delay_slot()->subu(T0, T0, T2);
- // We do not use the final allocation index of the variable here, i.e.
- // scope->VariableAt(i)->index(), because captured variables still need
- // to be copied to the context that is not yet allocated.
__ Bind(&loop);
__ addu(T4, T1, T2);
- __ addu(T5, T0, T2);
- __ lw(T3, Address(T4));
- __ sw(T3, Address(T5));
- __ Bind(&loop_condition);
+ __ lw(T3, Address(T4, -kWordSize));
__ addiu(T2, T2, Immediate(-kWordSize));
- __ bgez(T2, &loop);
+ __ addu(T5, T0, T2);
+ __ bgtz(T2, &loop);
+ __ delay_slot()->sw(T3, Address(T5));
+ __ Bind(&loop_exit);
// Copy or initialize optional named arguments.
Label all_arguments_processed;
@@ -782,8 +785,7 @@
0); // No registers.
}
// The noSuchMethod call may return.
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
__ Bind(&all_arguments_processed);
// Nullify originally passed arguments only after they have been copied and
@@ -792,23 +794,21 @@
// implicitly final, since garbage collecting the unmodified value is not
// an issue anymore.
+ __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
+
// S4 : arguments descriptor array.
__ lw(T2, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
__ sll(T2, T2, 1); // T2 is a Smi.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
- Label null_args_loop, null_args_loop_condition;
-
- __ b(&null_args_loop_condition);
+ Label null_args_loop, null_args_loop_exit;
+ __ blez(T2, &null_args_loop_exit);
__ delay_slot()->addiu(T1, FP, Immediate(kLastParamSlotIndex * kWordSize));
-
__ Bind(&null_args_loop);
- __ addu(T3, T1, T2);
- __ sw(T0, Address(T3));
-
- __ Bind(&null_args_loop_condition);
__ addiu(T2, T2, Immediate(-kWordSize));
- __ bgez(T2, &null_args_loop);
+ __ addu(T3, T1, T2);
+ __ bgtz(T2, &null_args_loop);
+ __ delay_slot()->sw(T0, Address(T3));
+ __ Bind(&null_args_loop_exit);
}
@@ -830,8 +830,12 @@
__ lw(T0, Address(SP, 1 * kWordSize)); // Receiver.
__ lw(T1, Address(SP, 0 * kWordSize)); // Value.
__ StoreIntoObject(T0, FieldAddress(T0, offset), T1);
- __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
+ intptr_t null = reinterpret_cast<intptr_t>(Object::null());
+ uint16_t null_lo = Utils::Low16Bits(null);
+ uint16_t null_hi = Utils::High16Bits(null);
+ __ lui(V0, Immediate(null_hi));
__ Ret();
+ __ delay_slot()->ori(V0, V0, Immediate(null_lo));
}
@@ -994,8 +998,7 @@
0); // No registers.
}
// The noSuchMethod call may return.
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
} else {
__ Stop("Wrong number of arguments");
}
@@ -1205,8 +1208,8 @@
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(reg, Address(SP, 1 * kWordSize));
__ LoadObject(TMP1, obj);
- __ sw(TMP1, Address(SP, 0 * kWordSize));
__ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ __ delay_slot()->sw(TMP1, Address(SP, 0 * kWordSize));
__ lw(reg, Address(SP, 1 * kWordSize)); // Restore 'reg'.
__ addiu(SP, SP, Immediate(2 * kWordSize)); // Discard constant.
return;
@@ -1222,8 +1225,8 @@
if (needs_number_check) {
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(left, Address(SP, 1 * kWordSize));
- __ sw(right, Address(SP, 0 * kWordSize));
__ BranchLink(&StubCode::IdenticalWithNumberCheckLabel());
+ __ delay_slot()->sw(right, Address(SP, 0 * kWordSize));
__ TraceSimMsg("EqualityRegRegCompare return");
// Stub returns result in CMPRES. If it is 0, then left and right are equal.
__ lw(right, Address(SP, 0 * kWordSize));
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index fab2e96..af3f6e2 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -24,7 +24,7 @@
// Flags for inlining heuristics.
DEFINE_FLAG(int, inlining_depth_threshold, 3,
"Inline function calls up to threshold nesting depth");
-DEFINE_FLAG(int, inlining_size_threshold, 20,
+DEFINE_FLAG(int, inlining_size_threshold, 22,
"Always inline functions that have threshold or fewer instructions");
DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1,
"Always inline functions containing threshold or fewer calls.");
@@ -292,7 +292,8 @@
class CallSiteInliner : public ValueObject {
public:
- CallSiteInliner(FlowGraph* flow_graph, GrowableArray<Field*>* guarded_fields)
+ CallSiteInliner(FlowGraph* flow_graph,
+ GrowableArray<const Field*>* guarded_fields)
: caller_graph_(flow_graph),
inlined_(false),
initial_size_(flow_graph->InstructionCount()),
@@ -869,7 +870,7 @@
CallSites* collected_call_sites_;
CallSites* inlining_call_sites_;
GrowableArray<ParsedFunction*> function_cache_;
- GrowableArray<Field*>* guarded_fields_;
+ GrowableArray<const Field*>* guarded_fields_;
DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
};
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index fd8c518..57318e3 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -15,7 +15,8 @@
class FlowGraphInliner : ValueObject {
public:
- FlowGraphInliner(FlowGraph* flow_graph, GrowableArray<Field*>* guarded_fields)
+ FlowGraphInliner(FlowGraph* flow_graph,
+ GrowableArray<const Field*>* guarded_fields)
: flow_graph_(flow_graph), guarded_fields_(guarded_fields) {}
// The flow graph is destructively updated upon inlining.
@@ -25,7 +26,7 @@
private:
FlowGraph* flow_graph_;
- GrowableArray<Field*>* guarded_fields_;
+ GrowableArray<const Field*>* guarded_fields_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
};
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 555b859..3182806 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -302,7 +302,8 @@
}
-void FlowGraphOptimizer::Canonicalize() {
+bool FlowGraphOptimizer::Canonicalize() {
+ bool changed = false;
for (intptr_t i = 0; i < block_order_.length(); ++i) {
BlockEntryInstr* entry = block_order_[i];
entry->Accept(this);
@@ -314,9 +315,11 @@
// this.
ASSERT((replacement == NULL) || current->IsDefinition());
ReplaceCurrentInstruction(&it, current, replacement, flow_graph_);
+ changed = true;
}
}
}
+ return changed;
}
@@ -1240,17 +1243,17 @@
}
-void FlowGraphOptimizer::AddToGuardedFields(Field* field) {
- if ((field->guarded_cid() == kDynamicCid) ||
- (field->guarded_cid() == kIllegalCid)) {
+void FlowGraphOptimizer::AddToGuardedFields(const Field& field) {
+ if ((field.guarded_cid() == kDynamicCid) ||
+ (field.guarded_cid() == kIllegalCid)) {
return;
}
for (intptr_t j = 0; j < guarded_fields_->length(); j++) {
- if ((*guarded_fields_)[j]->raw() == field->raw()) {
+ if ((*guarded_fields_)[j]->raw() == field.raw()) {
return;
}
}
- guarded_fields_->Add(field);
+ guarded_fields_->Add(&field);
}
@@ -1264,7 +1267,7 @@
// Inline implicit instance getter.
const String& field_name =
String::Handle(Field::NameFromGetter(call->function_name()));
- const Field& field = Field::Handle(GetField(class_ids[0], field_name));
+ const Field& field = Field::ZoneHandle(GetField(class_ids[0], field_name));
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(call)) {
@@ -1275,13 +1278,12 @@
field.Offset(),
AbstractType::ZoneHandle(field.type()),
field.is_final());
+ load->set_field(&field);
if (field.guarded_cid() != kIllegalCid) {
if (!field.is_nullable() || (field.guarded_cid() == kNullCid)) {
load->set_result_cid(field.guarded_cid());
}
- Field* the_field = &Field::ZoneHandle(field.raw());
- load->set_field(the_field);
- AddToGuardedFields(the_field);
+ AddToGuardedFields(field);
}
load->set_field_name(String::Handle(field.name()).ToCString());
@@ -1738,88 +1740,163 @@
}
if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
- switch (recognized_kind) {
- case MethodRecognizer::kFloat32x4Equal:
- case MethodRecognizer::kFloat32x4GreaterThan:
- case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
- case MethodRecognizer::kFloat32x4LessThan:
- case MethodRecognizer::kFloat32x4LessThanOrEqual:
- case MethodRecognizer::kFloat32x4NotEqual: {
- Definition* left = call->ArgumentAt(0);
- Definition* right = call->ArgumentAt(1);
- // Type check left.
- AddCheckClass(left,
- ICData::ZoneHandle(
- call->ic_data()->AsUnaryClassChecksForArgNr(0)),
- call->deopt_id(),
- call->env(),
- call);
- // Replace call.
- Float32x4ComparisonInstr* cmp =
- new Float32x4ComparisonInstr(recognized_kind, new Value(left),
- new Value(right), call);
- ReplaceCall(call, cmp);
- return true;
- }
- case MethodRecognizer::kFloat32x4Min:
- case MethodRecognizer::kFloat32x4Max: {
- Definition* left = call->ArgumentAt(0);
- Definition* right = call->ArgumentAt(1);
- // Type check left.
- AddCheckClass(left,
- ICData::ZoneHandle(
- call->ic_data()->AsUnaryClassChecksForArgNr(0)),
- call->deopt_id(),
- call->env(),
- call);
- Float32x4MinMaxInstr* minmax =
- new Float32x4MinMaxInstr(recognized_kind, new Value(left),
- new Value(right), call);
- ReplaceCall(call, minmax);
- return true;
- }
- case MethodRecognizer::kFloat32x4Scale: {
- Definition* left = call->ArgumentAt(0);
- Definition* right = call->ArgumentAt(1);
- // Type check left.
- AddCheckClass(left,
- ICData::ZoneHandle(
- call->ic_data()->AsUnaryClassChecksForArgNr(0)),
- call->deopt_id(),
- call->env(),
- call);
- // Left and right values are swapped when handed to the instruction,
- // this is done so that the double value is loaded into the output
- // register and can be destroyed.
- Float32x4ScaleInstr* scale =
- new Float32x4ScaleInstr(recognized_kind, new Value(right),
- new Value(left), call);
- ReplaceCall(call, scale);
- return true;
- }
- case MethodRecognizer::kFloat32x4Sqrt:
- case MethodRecognizer::kFloat32x4ReciprocalSqrt:
- case MethodRecognizer::kFloat32x4Reciprocal: {
- Definition* left = call->ArgumentAt(0);
- AddCheckClass(left,
- ICData::ZoneHandle(
- call->ic_data()->AsUnaryClassChecksForArgNr(0)),
- call->deopt_id(),
- call->env(),
- call);
- Float32x4SqrtInstr* sqrt =
- new Float32x4SqrtInstr(recognized_kind, new Value(left), call);
- ReplaceCall(call, sqrt);
- return true;
- }
- default:
- return false;
- }
+ return TryInlineFloat32x4Method(call, recognized_kind);
}
return false;
}
+bool FlowGraphOptimizer::TryInlineFloat32x4Method(
+ InstanceCallInstr* call,
+ MethodRecognizer::Kind recognized_kind) {
+ ASSERT(call->HasICData());
+ switch (recognized_kind) {
+ case MethodRecognizer::kFloat32x4Equal:
+ case MethodRecognizer::kFloat32x4GreaterThan:
+ case MethodRecognizer::kFloat32x4GreaterThanOrEqual:
+ case MethodRecognizer::kFloat32x4LessThan:
+ case MethodRecognizer::kFloat32x4LessThanOrEqual:
+ case MethodRecognizer::kFloat32x4NotEqual: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ // Replace call.
+ Float32x4ComparisonInstr* cmp =
+ new Float32x4ComparisonInstr(recognized_kind, new Value(left),
+ new Value(right), call);
+ ReplaceCall(call, cmp);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4Min:
+ case MethodRecognizer::kFloat32x4Max: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4MinMaxInstr* minmax =
+ new Float32x4MinMaxInstr(recognized_kind, new Value(left),
+ new Value(right), call);
+ ReplaceCall(call, minmax);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4Scale: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ // Left and right values are swapped when handed to the instruction,
+ // this is done so that the double value is loaded into the output
+ // register and can be destroyed.
+ Float32x4ScaleInstr* scale =
+ new Float32x4ScaleInstr(recognized_kind, new Value(right),
+ new Value(left), call);
+ ReplaceCall(call, scale);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4Sqrt:
+ case MethodRecognizer::kFloat32x4ReciprocalSqrt:
+ case MethodRecognizer::kFloat32x4Reciprocal: {
+ Definition* left = call->ArgumentAt(0);
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4SqrtInstr* sqrt =
+ new Float32x4SqrtInstr(recognized_kind, new Value(left), call);
+ ReplaceCall(call, sqrt);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4WithX:
+ case MethodRecognizer::kFloat32x4WithY:
+ case MethodRecognizer::kFloat32x4WithZ:
+ case MethodRecognizer::kFloat32x4WithW: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4WithInstr* with = new Float32x4WithInstr(recognized_kind,
+ new Value(left),
+ new Value(right),
+ call);
+ ReplaceCall(call, with);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4Absolute:
+ case MethodRecognizer::kFloat32x4Negate: {
+ Definition* left = call->ArgumentAt(0);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4ZeroArgInstr* zeroArg =
+ new Float32x4ZeroArgInstr(recognized_kind, new Value(left), call);
+ ReplaceCall(call, zeroArg);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4Clamp: {
+ Definition* left = call->ArgumentAt(0);
+ Definition* lower = call->ArgumentAt(1);
+ Definition* upper = call->ArgumentAt(2);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4ClampInstr* clamp = new Float32x4ClampInstr(new Value(left),
+ new Value(lower),
+ new Value(upper),
+ call);
+ ReplaceCall(call, clamp);
+ return true;
+ }
+ case MethodRecognizer::kFloat32x4ToUint32x4: {
+ Definition* left = call->ArgumentAt(0);
+ // Type check left.
+ AddCheckClass(left,
+ ICData::ZoneHandle(
+ call->ic_data()->AsUnaryClassChecksForArgNr(0)),
+ call->deopt_id(),
+ call->env(),
+ call);
+ Float32x4ToUint32x4Instr* cast =
+ new Float32x4ToUint32x4Instr(new Value(left), call);
+ ReplaceCall(call, cast);
+ return true;
+ }
+ default:
+ return false;
+ }
+}
+
+
bool FlowGraphOptimizer::BuildByteArrayViewLoad(
InstanceCallInstr* call,
intptr_t receiver_cid,
@@ -3215,22 +3292,23 @@
return Alias(kIndexesAlias);
}
- // Field load/stores alias each other when field offset matches.
- // TODO(vegorov): use field information to disambiguate load/stores into
- // different fields that by accident share offset.
- static Alias Field(intptr_t offset_in_bytes) {
+ // Field load/stores alias each other only when they access the same field.
+ // AliasedSet assigns ids to a combination of instance and field during
+ // the optimization phase.
+ static Alias Field(intptr_t id) {
+ ASSERT(id >= kFirstFieldAlias);
+ return Alias(id * 2 + 1);
+ }
+
+ // VMField load/stores alias each other when field offset matches.
+ // TODO(vegorov) storing a context variable does not alias loading array
+ // length.
+ static Alias VMField(intptr_t offset_in_bytes) {
const intptr_t idx = offset_in_bytes / kWordSize;
ASSERT(idx >= kFirstFieldAlias);
return Alias(idx * 2);
}
- // Static field load/stores alias each other.
- // AliasedSet assigns ids to static fields during optimization phase.
- static Alias StaticField(intptr_t id) {
- ASSERT(id >= kFirstFieldAlias);
- return Alias(id * 2 + 1);
- }
-
// Current context load/stores alias each other.
static Alias CurrentContext() {
return Alias(kCurrentContextAlias);
@@ -3283,7 +3361,12 @@
LoadFieldInstr* load_field = defn->AsLoadField();
if (load_field != NULL) {
- return Alias::Field(load_field->offset_in_bytes());
+ if (load_field->field() != NULL) {
+ Definition* instance = load_field->instance()->definition();
+ return Alias::Field(GetInstanceFieldId(instance, *load_field->field()));
+ } else {
+ return Alias::VMField(load_field->offset_in_bytes());
+ }
}
if (defn->IsCurrentContext()) {
@@ -3292,7 +3375,7 @@
LoadStaticFieldInstr* load_static_field = defn->AsLoadStaticField();
if (load_static_field != NULL) {
- return Alias::StaticField(GetFieldId(load_static_field->field()));
+ return Alias::Field(GetFieldId(kAnyInstance, load_static_field->field()));
}
UNREACHABLE();
@@ -3307,12 +3390,14 @@
StoreInstanceFieldInstr* store_instance_field =
instr->AsStoreInstanceField();
if (store_instance_field != NULL) {
- return Alias::Field(store_instance_field->field().Offset());
+ Definition* instance = store_instance_field->instance()->definition();
+ return Alias::Field(GetInstanceFieldId(instance,
+ store_instance_field->field()));
}
StoreVMFieldInstr* store_vm_field = instr->AsStoreVMField();
if (store_vm_field != NULL) {
- return Alias::Field(store_vm_field->offset_in_bytes());
+ return Alias::VMField(store_vm_field->offset_in_bytes());
}
if (instr->IsStoreContext() || instr->IsChainContext()) {
@@ -3321,7 +3406,7 @@
StoreStaticFieldInstr* store_static_field = instr->AsStoreStaticField();
if (store_static_field != NULL) {
- return Alias::StaticField(GetFieldId(store_static_field->field()));
+ return Alias::Field(GetStaticFieldId(store_static_field->field()));
}
return Alias::None();
@@ -3363,18 +3448,86 @@
// Get id assigned to the given field. Assign a new id if the field is seen
// for the first time.
- intptr_t GetFieldId(const Field& field) {
- intptr_t id = field_ids_.Lookup(&field);
+ intptr_t GetFieldId(intptr_t instance_id, const Field& field) {
+ intptr_t id = field_ids_.Lookup(FieldIdPair::Key(instance_id, &field));
if (id == 0) {
id = ++max_field_id_;
- field_ids_.Insert(FieldIdPair(&field, id));
+ field_ids_.Insert(FieldIdPair(FieldIdPair::Key(instance_id, &field), id));
}
return id;
}
+ enum {
+ kAnyInstance = -1
+ };
+
+ // Get or create an identifier for an instance field belonging to the
+ // given instance.
+ // The space of identifiers assigned to instance fields is split into
+ // parts based on the instance that contains the field.
+ // If compiler can prove that instance has a single SSA name in the compiled
+ // function then we use that SSA name to distinguish fields of this object
+ // from the same fields in other objects.
+ // If multiple SSA names can point to the same object then we use
+ // kAnyInstance instead of a concrete SSA name.
+ intptr_t GetInstanceFieldId(Definition* defn, const Field& field) {
+ ASSERT(!field.is_static());
+
+ intptr_t instance_id = kAnyInstance;
+
+ AllocateObjectInstr* alloc = defn->AsAllocateObject();
+ if ((alloc != NULL) && !CanBeAliased(alloc)) {
+ instance_id = alloc->ssa_temp_index();
+ ASSERT(instance_id != kAnyInstance);
+ }
+
+ return GetFieldId(instance_id, field);
+ }
+
+ // Get or create an identifier for a static field.
+ intptr_t GetStaticFieldId(const Field& field) {
+ ASSERT(field.is_static());
+ return GetFieldId(kAnyInstance, field);
+ }
+
+ // Returns true if the result of AllocateObject can be aliased by some
+ // other SSA variable and false otherwise. Currently simply checks if
+ // this value is stored in a field, escapes to another function or
+ // participates in a phi.
+ bool CanBeAliased(AllocateObjectInstr* alloc) {
+ if (alloc->identity() == AllocateObjectInstr::kUnknown) {
+ bool escapes = false;
+ for (Value* use = alloc->input_use_list();
+ use != NULL;
+ use = use->next_use()) {
+ Instruction* instr = use->instruction();
+ if (instr->IsPushArgument() ||
+ (instr->IsStoreVMField() && (use->use_index() != 0)) ||
+ (instr->IsStoreInstanceField() && (use->use_index() != 0)) ||
+ (instr->IsStoreStaticField()) ||
+ (instr->IsPhi())) {
+ escapes = true;
+ break;
+ }
+
+ alloc->set_identity(escapes ? AllocateObjectInstr::kAliased
+ : AllocateObjectInstr::kNotAliased);
+ }
+ }
+
+ return alloc->identity() != AllocateObjectInstr::kNotAliased;
+ }
+
class FieldIdPair {
public:
- typedef const Field* Key;
+ struct Key {
+ Key(intptr_t instance_id, const Field* field)
+ : instance_id_(instance_id), field_(field) { }
+
+ intptr_t instance_id_;
+ const Field* field_;
+ };
+
typedef intptr_t Value;
typedef FieldIdPair Pair;
@@ -3389,11 +3542,12 @@
}
static intptr_t Hashcode(Key key) {
- return String::Handle(key->name()).Hash();
+ return String::Handle(key.field_->name()).Hash();
}
static inline bool IsKeyEqual(Pair kv, Key key) {
- return KeyOf(kv)->raw() == key->raw();
+ return (KeyOf(kv).field_->raw() == key.field_->raw()) &&
+ (KeyOf(kv).instance_id_ == key.instance_id_);
}
private:
@@ -3466,7 +3620,7 @@
location = store_indexed->index()->definition()->ssa_temp_index();
} else if (key->IsLoadField()) {
LoadFieldInstr* load_field = key->AsLoadField();
- object = load_field->value()->definition()->ssa_temp_index();
+ object = load_field->instance()->definition()->ssa_temp_index();
location = load_field->offset_in_bytes();
} else if (key->IsStoreInstanceField()) {
StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
@@ -3522,11 +3676,11 @@
LoadFieldInstr* load_field = kv->AsLoadField();
if (key->IsStoreVMField()) {
StoreVMFieldInstr* store_field = key->AsStoreVMField();
- return load_field->value()->Equals(store_field->dest()) &&
+ return load_field->instance()->Equals(store_field->dest()) &&
(load_field->offset_in_bytes() == store_field->offset_in_bytes());
} else if (key->IsStoreInstanceField()) {
StoreInstanceFieldInstr* store_field = key->AsStoreInstanceField();
- return load_field->value()->Equals(store_field->instance()) &&
+ return load_field->instance()->Equals(store_field->instance()) &&
(load_field->offset_in_bytes() == store_field->field().Offset());
}
@@ -4652,16 +4806,16 @@
void ConstantPropagator::VisitLoadField(LoadFieldInstr* instr) {
if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
- (instr->value()->definition()->IsCreateArray())) {
+ (instr->instance()->definition()->IsCreateArray())) {
const intptr_t length =
- instr->value()->definition()->AsCreateArray()->num_elements();
+ instr->instance()->definition()->AsCreateArray()->num_elements();
const Object& result = Smi::ZoneHandle(Smi::New(length));
SetValue(instr, result);
return;
}
if (instr->IsImmutableLengthLoad()) {
- ConstantInstr* constant = instr->value()->definition()->AsConstant();
+ ConstantInstr* constant = instr->instance()->definition()->AsConstant();
if (constant != NULL) {
if (constant->value().IsString()) {
SetValue(instr, Smi::ZoneHandle(
@@ -4937,6 +5091,27 @@
}
+void ConstantPropagator::VisitFloat32x4ZeroArg(Float32x4ZeroArgInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4Clamp(Float32x4ClampInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4With(Float32x4WithInstr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
+void ConstantPropagator::VisitFloat32x4ToUint32x4(
+ Float32x4ToUint32x4Instr* instr) {
+ SetValue(instr, non_constant_);
+}
+
+
void ConstantPropagator::VisitMathSqrt(MathSqrtInstr* instr) {
const Object& value = instr->value()->definition()->constant_value();
if (IsNonConstant(value)) {
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 980890b..5b2bfa6 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -17,7 +17,7 @@
class FlowGraphOptimizer : public FlowGraphVisitor {
public:
FlowGraphOptimizer(FlowGraph* flow_graph,
- GrowableArray<Field*>* guarded_fields)
+ GrowableArray<const Field*>* guarded_fields)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
flow_graph_(flow_graph),
guarded_fields_(guarded_fields) { }
@@ -35,7 +35,8 @@
// shift can be a truncating Smi shift-left and result is always Smi.
void TryOptimizeLeftShiftWithBitAndPattern();
- void Canonicalize();
+ // Returns true if any instructions were canonicalized away.
+ bool Canonicalize();
void EliminateDeadPhis();
@@ -81,6 +82,8 @@
const ICData& unary_ic_data);
bool TryInlineInstanceMethod(InstanceCallInstr* call);
+ bool TryInlineFloat32x4Method(InstanceCallInstr* call,
+ MethodRecognizer::Kind recognized_kind);
void ReplaceWithInstanceOf(InstanceCallInstr* instr);
void ReplaceWithTypeCast(InstanceCallInstr* instr);
@@ -168,10 +171,10 @@
Definition* left_instr,
Definition* right_instr);
- void AddToGuardedFields(Field* field);
+ void AddToGuardedFields(const Field& field);
FlowGraph* flow_graph_;
- GrowableArray<Field*>* guarded_fields_;
+ GrowableArray<const Field*>* guarded_fields_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphOptimizer);
};
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 253697a..2b5f1a4 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -891,7 +891,7 @@
return CompileType::FromAbstractType(type());
}
- if (field_ != NULL) {
+ if (field_ != NULL && (field_->guarded_cid() != kIllegalCid)) {
return CompileType::CreateNullable(field_->is_nullable(),
field_->guarded_cid());
}
@@ -1011,6 +1011,26 @@
}
+CompileType Float32x4ZeroArgInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4ClampInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4WithInstr::ComputeType() const {
+ return CompileType::FromCid(kFloat32x4Cid);
+}
+
+
+CompileType Float32x4ToUint32x4Instr::ComputeType() const {
+ return CompileType::FromCid(kUint32x4Cid);
+}
+
+
CompileType MathSqrtInstr::ComputeType() const {
return CompileType::FromCid(kDoubleCid);
}
diff --git a/runtime/vm/heap_profiler.cc b/runtime/vm/heap_profiler.cc
index 6503b6e..781ef5b 100644
--- a/runtime/vm/heap_profiler.cc
+++ b/runtime/vm/heap_profiler.cc
@@ -336,9 +336,11 @@
uint32_t size = htonl(kObjectIdSize);
Write(&size, sizeof(size));
uint64_t milliseconds = OS::GetCurrentTimeMillis();
- uint32_t hi = htonl((uint32_t)((milliseconds >> 32) & 0x00000000FFFFFFFF));
+ uint32_t hi = htonl(
+ static_cast<uint32_t>((milliseconds >> 32) & 0x00000000FFFFFFFF));
Write(&hi, sizeof(hi));
- uint32_t lo = htonl((uint32_t)(milliseconds & 0x00000000FFFFFFFF));
+ uint32_t lo = htonl(
+ static_cast<uint32_t>(milliseconds & 0x00000000FFFFFFFF));
Write(&lo, sizeof(lo));
}
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index bf50596..406c445 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -514,7 +514,7 @@
void LoadFieldInstr::PrintOperandsTo(BufferFormatter* f) const {
- value()->PrintTo(f);
+ instance()->PrintTo(f);
f->Print(", %"Pd, offset_in_bytes());
if (field_name_ != NULL) {
@@ -664,6 +664,32 @@
}
+void Float32x4ZeroArgInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("%s, ", MethodRecognizer::KindToCString(op_kind()));
+ left()->PrintTo(f);
+}
+
+
+void Float32x4ClampInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("Float32x4.clamp, ");
+ left()->PrintTo(f);
+}
+
+
+void Float32x4WithInstr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("%s, ", MethodRecognizer::KindToCString(op_kind()));
+ left()->PrintTo(f);
+ f->Print(", ");
+ replacement()->PrintTo(f);
+}
+
+
+void Float32x4ToUint32x4Instr::PrintOperandsTo(BufferFormatter* f) const {
+ f->Print("Float32x4.toUint32x4 ");
+ left()->PrintTo(f);
+}
+
+
void BinaryMintOpInstr::PrintOperandsTo(BufferFormatter* f) const {
f->Print("%s, ", Token::Str(op_kind()));
left()->PrintTo(f);
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index db49612..bb57209 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1196,7 +1196,7 @@
// For fixed length arrays if the array is the result of a known constructor
// call we can replace the length load with the length argument passed to
// the constructor.
- StaticCallInstr* call = value()->definition()->AsStaticCall();
+ StaticCallInstr* call = instance()->definition()->AsStaticCall();
if ((call != NULL) &&
call->is_known_list_constructor() &&
IsFixedLengthArrayCid(call->Type()->ToCid())) {
@@ -1245,6 +1245,29 @@
}
+Definition* BoxDoubleInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+ if (input_use_list() == NULL) {
+ // Environments can accomodate any representation. No need to box.
+ return value()->definition();
+ }
+
+ // Fold away BoxDouble(UnboxDouble(v)) if value is known to be double.
+ UnboxDoubleInstr* defn = value()->definition()->AsUnboxDouble();
+ if ((defn != NULL) && (defn->value()->Type()->ToCid() == kDoubleCid)) {
+ return defn->value()->definition();
+ }
+
+ return this;
+}
+
+
+Definition* UnboxDoubleInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
+ // Fold away UnboxDouble(BoxDouble(v)).
+ BoxDoubleInstr* defn = value()->definition()->AsBoxDouble();
+ return (defn != NULL) ? defn->value()->definition() : this;
+}
+
+
Instruction* BranchInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
// Only handle strict-compares.
if (comparison()->IsStrictCompare()) {
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 6b560f6..dc33a3f 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -94,6 +94,15 @@
V(_Float32x4, _sqrt, Float32x4Sqrt, 42621627) \
V(_Float32x4, _reciprocalSqrt, Float32x4ReciprocalSqrt, 42621627) \
V(_Float32x4, _reciprocal, Float32x4Reciprocal, 42621627) \
+ V(_Float32x4, _negate, Float32x4Negate, 42621627) \
+ V(_Float32x4, _abs, Float32x4Absolute, 42621627) \
+ V(_Float32x4, _clamp, Float32x4Clamp, 615895313) \
+ V(_Float32x4, withX, Float32x4WithX, 219466242) \
+ V(_Float32x4, withY, Float32x4WithY, 219466242) \
+ V(_Float32x4, withZ, Float32x4WithZ, 219466242) \
+ V(_Float32x4, withW, Float32x4WithW, 219466242) \
+ V(_Float32x4, _toUint32x4, Float32x4ToUint32x4, 1044409108) \
+
// Class that recognizes the name and owner of a function and returns the
// corresponding enum. See RECOGNIZED_LIST above for list of recognizable
@@ -571,6 +580,10 @@
M(Float32x4MinMax) \
M(Float32x4Scale) \
M(Float32x4Sqrt) \
+ M(Float32x4ZeroArg) \
+ M(Float32x4Clamp) \
+ M(Float32x4With) \
+ M(Float32x4ToUint32x4) \
#define FORWARD_DECLARATION(type) class type##Instr;
@@ -835,6 +848,10 @@
friend class Float32x4MinMaxInstr;
friend class Float32x4ScaleInstr;
friend class Float32x4SqrtInstr;
+ friend class Float32x4ZeroArgInstr;
+ friend class Float32x4ClampInstr;
+ friend class Float32x4WithInstr;
+ friend class Float32x4ToUint32x4Instr;
friend class BinaryMintOpInstr;
friend class BinarySmiOpInstr;
friend class UnarySmiOpInstr;
@@ -3408,7 +3425,8 @@
ZoneGrowableArray<PushArgumentInstr*>* arguments)
: ast_node_(*node),
arguments_(arguments),
- cid_(Class::Handle(node->constructor().Owner()).id()) {
+ cid_(Class::Handle(node->constructor().Owner()).id()),
+ identity_(kUnknown) {
// Either no arguments or one type-argument and one instantiator.
ASSERT(arguments->is_empty() || (arguments->length() == 2));
}
@@ -3430,10 +3448,23 @@
virtual EffectSet Effects() const { return EffectSet::None(); }
+ // If the result of the allocation is not stored into any field, passed
+ // as an argument or used in a phi then it can't alias with any other
+ // SSA value.
+ enum Identity {
+ kUnknown,
+ kAliased,
+ kNotAliased
+ };
+
+ Identity identity() const { return identity_; }
+ void set_identity(Identity identity) { identity_ = identity; }
+
private:
const ConstructorCallNode& ast_node_;
ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
const intptr_t cid_;
+ Identity identity_;
DISALLOW_COPY_AND_ASSIGN(AllocateObjectInstr);
};
@@ -3575,7 +3606,7 @@
class LoadFieldInstr : public TemplateDefinition<1> {
public:
- LoadFieldInstr(Value* value,
+ LoadFieldInstr(Value* instance,
intptr_t offset_in_bytes,
const AbstractType& type,
bool immutable = false)
@@ -3587,10 +3618,10 @@
field_name_(NULL),
field_(NULL) {
ASSERT(type.IsZoneHandle()); // May be null if field is not an instance.
- SetInputAt(0, value);
+ SetInputAt(0, instance);
}
- Value* value() const { return inputs_[0]; }
+ Value* instance() const { return inputs_[0]; }
intptr_t offset_in_bytes() const { return offset_in_bytes_; }
const AbstractType& type() const { return type_; }
void set_result_cid(intptr_t value) { result_cid_ = value; }
@@ -3599,8 +3630,8 @@
void set_field_name(const char* name) { field_name_ = name; }
const char* field_name() const { return field_name_; }
- Field* field() const { return field_; }
- void set_field(Field* field) { field_ = field; }
+ const Field* field() const { return field_; }
+ void set_field(const Field* field) { field_ = field; }
void set_recognized_kind(MethodRecognizer::Kind kind) {
recognized_kind_ = kind;
@@ -3641,7 +3672,7 @@
MethodRecognizer::Kind recognized_kind_;
const char* field_name_;
- Field* field_;
+ const Field* field_;
DISALLOW_COPY_AND_ASSIGN(LoadFieldInstr);
};
@@ -3939,6 +3970,8 @@
virtual EffectSet Dependencies() const { return EffectSet::None(); }
virtual bool AttributesEqual(Instruction* other) const { return true; }
+ Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxDoubleInstr);
};
@@ -4054,6 +4087,8 @@
virtual EffectSet Dependencies() const { return EffectSet::None(); }
virtual bool AttributesEqual(Instruction* other) const { return true; }
+ Definition* Canonicalize(FlowGraphOptimizer* optimizer);
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxDoubleInstr);
};
@@ -4688,6 +4723,195 @@
};
+class Float32x4ZeroArgInstr : public TemplateDefinition<1> {
+ public:
+ Float32x4ZeroArgInstr(MethodRecognizer::Kind op_kind, Value* left,
+ InstanceCallInstr* instance_call) : op_kind_(op_kind) {
+ SetInputAt(0, left);
+ deopt_id_ = instance_call->deopt_id();
+ }
+
+ Value* left() const { return inputs_[0]; }
+
+ MethodRecognizer::Kind op_kind() const { return op_kind_; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx == 0);
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4ZeroArg)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const {
+ return op_kind() == other->AsFloat32x4ZeroArg()->op_kind();
+ }
+
+ private:
+ const MethodRecognizer::Kind op_kind_;
+
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ZeroArgInstr);
+};
+
+
+class Float32x4ClampInstr : public TemplateDefinition<3> {
+ public:
+ Float32x4ClampInstr(Value* left, Value* lower, Value* upper,
+ InstanceCallInstr* instance_call) {
+ SetInputAt(0, left);
+ SetInputAt(1, lower);
+ SetInputAt(2, upper);
+ deopt_id_ = instance_call->deopt_id();
+ }
+
+ Value* left() const { return inputs_[0]; }
+ Value* lower() const { return inputs_[1]; }
+ Value* upper() const { return inputs_[2]; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT((idx == 0) || (idx == 1) || (idx == 2));
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4Clamp)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ClampInstr);
+};
+
+
+class Float32x4WithInstr : public TemplateDefinition<2> {
+ public:
+ Float32x4WithInstr(MethodRecognizer::Kind op_kind, Value* left,
+ Value* replacement, InstanceCallInstr* instance_call)
+ : op_kind_(op_kind) {
+ SetInputAt(0, replacement);
+ SetInputAt(1, left);
+ deopt_id_ = instance_call->deopt_id();
+ }
+
+ Value* left() const { return inputs_[1]; }
+ Value* replacement() const { return inputs_[0]; }
+
+ MethodRecognizer::Kind op_kind() const { return op_kind_; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kUnboxedFloat32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT((idx == 0) || (idx == 1));
+ if (idx == 0) {
+ return kUnboxedDouble;
+ }
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4With)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const {
+ return op_kind() == other->AsFloat32x4With()->op_kind();
+ }
+
+ private:
+ const MethodRecognizer::Kind op_kind_;
+
+ DISALLOW_COPY_AND_ASSIGN(Float32x4WithInstr);
+};
+
+
+class Float32x4ToUint32x4Instr : public TemplateDefinition<1> {
+ public:
+ Float32x4ToUint32x4Instr(Value* left, InstanceCallInstr* instance_call) {
+ SetInputAt(0, left);
+ deopt_id_ = instance_call->deopt_id();
+ }
+
+ Value* left() const { return inputs_[0]; }
+
+ virtual void PrintOperandsTo(BufferFormatter* f) const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual Representation representation() const {
+ return kUnboxedUint32x4;
+ }
+
+ virtual Representation RequiredInputRepresentation(intptr_t idx) const {
+ ASSERT(idx == 0);
+ return kUnboxedFloat32x4;
+ }
+
+ virtual intptr_t DeoptimizationTarget() const {
+ // Direct access since this instruction cannot deoptimize, and the deopt-id
+ // was inherited from another instruction that could deoptimize.
+ return deopt_id_;
+ }
+
+ DECLARE_INSTRUCTION(Float32x4ToUint32x4)
+ virtual CompileType ComputeType() const;
+
+ virtual bool AllowsCSE() const { return true; }
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+ virtual bool AttributesEqual(Instruction* other) const { return true; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Float32x4ToUint32x4Instr);
+};
+
+
class BinaryMintOpInstr : public TemplateDefinition<2> {
public:
BinaryMintOpInstr(Token::Kind op_kind,
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 60f959f..9361168 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -2085,6 +2085,50 @@
}
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ClampInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4WithInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ToUint32x4Instr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ToUint32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index b085eed..20095ed 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -3166,6 +3166,139 @@
}
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == left);
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4Negate:
+ __ negateps(left);
+ break;
+ case MethodRecognizer::kFloat32x4Absolute:
+ __ absps(left);
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 3;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_in(2, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ClampInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+ XmmRegister lower = locs()->in(1).fpu_reg();
+ XmmRegister upper = locs()->in(2).fpu_reg();
+ ASSERT(locs()->out().fpu_reg() == left);
+ __ minps(left, upper);
+ __ maxps(left, lower);
+}
+
+
+LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+void Float32x4WithInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister replacement = locs()->in(0).fpu_reg();
+ XmmRegister value = locs()->in(1).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == replacement);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4WithX:
+ __ cvtsd2ss(replacement, replacement);
+ __ subl(ESP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(ESP, -16), value);
+ // Write over X value.
+ __ movss(Address(ESP, -16), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(ESP, -16));
+ __ addl(ESP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithY:
+ __ cvtsd2ss(replacement, replacement);
+ __ subl(ESP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(ESP, -16), value);
+ // Write over Y value.
+ __ movss(Address(ESP, -12), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(ESP, -16));
+ __ addl(ESP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithZ:
+ __ cvtsd2ss(replacement, replacement);
+ __ subl(ESP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(ESP, -16), value);
+ // Write over Z value.
+ __ movss(Address(ESP, -8), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(ESP, -16));
+ __ addl(ESP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithW:
+ __ cvtsd2ss(replacement, replacement);
+ __ subl(ESP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(ESP, -16), value);
+ // Write over W value.
+ __ movss(Address(ESP, -4), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(ESP, -16));
+ __ addl(ESP, Immediate(16));
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
+LocationSummary* Float32x4ToUint32x4Instr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ToUint32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // NOP.
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 21ba210..c3ffa5b 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -102,8 +102,7 @@
// This sequence is patched by a debugger breakpoint. There is no need for
// extra NOP instructions here because the sequence patched in for a
// breakpoint is shorter than the sequence here.
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
compiler->AddCurrentDescriptor(PcDescriptors::kReturn,
Isolate::kNoDeoptId,
token_pos());
@@ -1247,13 +1246,13 @@
} else if (value_cid == kNullCid) {
// TODO(regis): TMP1 may conflict. Revisit.
__ lw(TMP1, field_nullability_operand);
- __ LoadImmediate(TMP2, value_cid);
- __ subu(CMPRES, TMP1, TMP2);
+ __ LoadImmediate(CMPRES, value_cid);
+ __ subu(CMPRES, TMP1, CMPRES);
} else {
// TODO(regis): TMP1 may conflict. Revisit.
__ lw(TMP1, field_cid_operand);
- __ LoadImmediate(TMP2, value_cid);
- __ subu(CMPRES, TMP1, TMP2);
+ __ LoadImmediate(CMPRES, value_cid);
+ __ subu(CMPRES, TMP1, CMPRES);
}
__ beq(CMPRES, ZR, &ok);
@@ -1502,9 +1501,9 @@
// A runtime call to instantiate the type arguments is required.
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ LoadObject(TMP1, Object::ZoneHandle());
- __ LoadObject(TMP2, type_arguments());
__ sw(TMP1, Address(SP, 2 * kWordSize)); // Make room for the result.
- __ sw(TMP2, Address(SP, 1 * kWordSize));
+ __ LoadObject(TMP1, type_arguments());
+ __ sw(TMP1, Address(SP, 1 * kWordSize));
// Push instantiator type arguments.
__ sw(instantiator_reg, Address(SP, 0 * kWordSize));
@@ -1678,10 +1677,10 @@
Address(FP, stacktrace_var().index() * kWordSize));
Label next;
- __ mov(TMP1, RA); // Save return adress.
+ __ mov(T0, RA); // Save return adress.
// Restore the pool pointer.
__ bal(&next); // Branch and link to next instruction to get PC in RA.
- __ delay_slot()->mov(TMP2, RA); // Save PC of the following mov.
+ __ delay_slot()->mov(T1, RA); // Save PC of the following mov.
// Calculate offset of pool pointer from the PC.
const intptr_t object_pool_pc_dist =
@@ -1689,8 +1688,8 @@
compiler->assembler()->CodeSize();
__ Bind(&next);
- __ mov(RA, TMP1); // Restore return address.
- __ lw(PP, Address(TMP2, -object_pool_pc_dist));
+ __ mov(RA, T0); // Restore return address.
+ __ lw(PP, Address(T1, -object_pool_pc_dist));
}
@@ -1758,6 +1757,10 @@
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
summary->set_in(0, Location::RequiresRegister());
summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ if (op_kind() == Token::kADD) {
+ // Need an extra temp for the overflow detection code.
+ summary->set_temp(0, Location::RequiresRegister());
+ }
// We make use of 3-operand instructions by not requiring result register
// to be identical to first input register as on Intel.
summary->set_out(Location::RequiresRegister());
@@ -1799,7 +1802,8 @@
if (deopt == NULL) {
__ AddImmediate(result, left, imm);
} else {
- __ AddImmediateDetectOverflow(result, left, imm, CMPRES);
+ Register temp = locs()->temp(0).reg();
+ __ AddImmediateDetectOverflow(result, left, imm, CMPRES, temp);
__ bltz(CMPRES, deopt);
}
break;
@@ -1825,8 +1829,8 @@
__ mflo(result);
__ mfhi(TMP1);
}
- __ sra(TMP2, result, 31);
- __ bne(TMP1, TMP2, deopt);
+ __ sra(CMPRES, result, 31);
+ __ bne(TMP1, CMPRES, deopt);
}
break;
}
@@ -1882,7 +1886,8 @@
if (deopt == NULL) {
__ addu(result, left, right);
} else {
- __ AdduDetectOverflow(result, left, right, CMPRES);
+ Register temp = locs()->temp(0).reg();
+ __ AdduDetectOverflow(result, left, right, CMPRES, temp);
__ bltz(CMPRES, deopt);
}
break;
@@ -2140,6 +2145,50 @@
}
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ClampInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4WithInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
+LocationSummary* Float32x4ToUint32x4Instr::MakeLocationSummary() const {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Float32x4ToUint32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ UNIMPLEMENTED();
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
UNIMPLEMENTED();
return NULL;
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index ac9d6f8..989c41b 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -3173,6 +3173,139 @@
}
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ZeroArgInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == left);
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4Negate:
+ __ negateps(left);
+ break;
+ case MethodRecognizer::kFloat32x4Absolute:
+ __ absps(left);
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 3;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_in(2, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ClampInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister left = locs()->in(0).fpu_reg();
+ XmmRegister lower = locs()->in(1).fpu_reg();
+ XmmRegister upper = locs()->in(2).fpu_reg();
+ ASSERT(locs()->out().fpu_reg() == left);
+ __ minps(left, upper);
+ __ maxps(left, lower);
+}
+
+
+LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+void Float32x4WithInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ XmmRegister replacement = locs()->in(0).fpu_reg();
+ XmmRegister value = locs()->in(1).fpu_reg();
+
+ ASSERT(locs()->out().fpu_reg() == replacement);
+
+ switch (op_kind()) {
+ case MethodRecognizer::kFloat32x4WithX:
+ __ cvtsd2ss(replacement, replacement);
+ __ subq(RSP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(RSP, -16), value);
+ // Write over X value.
+ __ movss(Address(RSP, -16), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(RSP, -16));
+ __ addq(RSP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithY:
+ __ cvtsd2ss(replacement, replacement);
+ __ subq(RSP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(RSP, -16), value);
+ // Write over Y value.
+ __ movss(Address(RSP, -12), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(RSP, -16));
+ __ addq(RSP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithZ:
+ __ cvtsd2ss(replacement, replacement);
+ __ subq(RSP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(RSP, -16), value);
+ // Write over Z value.
+ __ movss(Address(RSP, -8), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(RSP, -16));
+ __ addq(RSP, Immediate(16));
+ break;
+ case MethodRecognizer::kFloat32x4WithW:
+ __ cvtsd2ss(replacement, replacement);
+ __ subq(RSP, Immediate(16));
+ // Move value to stack.
+ __ movups(Address(RSP, -16), value);
+ // Write over W value.
+ __ movss(Address(RSP, -4), replacement);
+ // Move updated value into output register.
+ __ movups(replacement, Address(RSP, -16));
+ __ addq(RSP, Immediate(16));
+ break;
+ default: UNREACHABLE();
+ }
+}
+
+
+LocationSummary* Float32x4ToUint32x4Instr::MakeLocationSummary() const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::SameAsFirstInput());
+ return summary;
+}
+
+
+void Float32x4ToUint32x4Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // NOP.
+}
+
+
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
diff --git a/runtime/vm/object_mips_test.cc b/runtime/vm/object_mips_test.cc
index 750f65c..76b9871 100644
--- a/runtime/vm/object_mips_test.cc
+++ b/runtime/vm/object_mips_test.cc
@@ -37,8 +37,7 @@
const String& string_object =
String::ZoneHandle(String::New(str, Heap::kOld));
__ LoadObject(V0, string_object);
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index 56e8aeb..4b027c9 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -1963,7 +1963,7 @@
const String& source = String::Handle(String::New(source_chars));
const Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
EXPECT(!script.IsNull());
EXPECT(script.IsScript());
String& str = String::Handle(script.url());
@@ -2018,7 +2018,7 @@
const String& url = String::Handle(String::New(url_chars));
const String& source = String::Handle(String::New(src_chars));
const Script& script = Script::Handle(
- Script::New(url, source, RawScript::kSourceTag));
+ Script::New(url, source, RawScript::kScriptTag));
script.SetLocationOffset(line_offset, col_offset);
String& str = String::Handle();
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index b7814db..10adced 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -4439,28 +4439,23 @@
void Parser::ParsePartHeader() {
- intptr_t metadata_pos = TokenPos();
SkipMetadata();
- // TODO(hausner): Once support for old #source directive is removed
- // from the compiler, add an error message here if we don't find
- // a 'part of' directive.
- if (CurrentToken() == Token::kPART) {
- ConsumeToken();
- if (!IsLiteral("of")) {
- ErrorMsg("'part of' expected");
- }
- ConsumeToken();
- // The VM is not required to check that the library name matches the
- // name of the current library, so we ignore it.
- ExpectIdentifier("library name expected");
- while (CurrentToken() == Token::kPERIOD) {
- ConsumeToken();
- ExpectIdentifier("malformed library name");
- }
- ExpectSemicolon();
- } else {
- SetPosition(metadata_pos);
+ if (CurrentToken() != Token::kPART) {
+ ErrorMsg("'part of' expected");
}
+ ConsumeToken();
+ if (!IsLiteral("of")) {
+ ErrorMsg("'part of' expected");
+ }
+ ConsumeToken();
+ // The VM is not required to check that the library name matches the
+ // name of the current library, so we ignore it.
+ ExpectIdentifier("library name expected");
+ while (CurrentToken() == Token::kPERIOD) {
+ ConsumeToken();
+ ExpectIdentifier("malformed library name");
+ }
+ ExpectSemicolon();
}
diff --git a/runtime/vm/parser_test.cc b/runtime/vm/parser_test.cc
index f04eef1..2e4c4b7 100644
--- a/runtime/vm/parser_test.cc
+++ b/runtime/vm/parser_test.cc
@@ -117,7 +117,7 @@
String& source = String::Handle(String::New(script_chars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
@@ -152,7 +152,7 @@
String& source = String::Handle(String::New(script_chars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index 2bdca58..66e90c9 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -815,7 +815,7 @@
String& source = String::Handle(String::New(kScriptChars));
Script& script = Script::Handle(Script::New(url,
source,
- RawScript::kSourceTag));
+ RawScript::kScriptTag));
const String& lib_url = String::Handle(Symbols::New("TestLib"));
Library& lib = Library::Handle(Library::New(lib_url));
lib.Register();
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 1174f54..852768a 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -517,7 +517,7 @@
__ cmp(R1, ShifterOperand(R7));
__ str(IP, Address(R1, 0), CC); // Store if unsigned lower.
__ AddImmediate(R1, kWordSize, CC);
- __ b(&loop, CS);
+ __ b(&loop, CC); // Loop until R1 == R7.
// Done allocating and initializing the array.
// R0: new object.
@@ -1595,7 +1595,6 @@
__ LoadClass(R3, R0, R4);
// Compute instance type arguments into R4.
Label has_no_type_arguments;
- __ LoadImmediate(R4, reinterpret_cast<intptr_t>(Object::null()));
__ ldr(R5, FieldAddress(R3,
Class::type_arguments_field_offset_in_words_offset()));
__ CompareImmediate(R5, Class::kNoTypeArguments);
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index a50383d..b475ae7 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -81,10 +81,11 @@
__ addiu(A2, A2, Immediate(kWordSize)); // Set argv in NativeArguments.
ASSERT(retval_offset == 3 * kWordSize);
- __ addiu(A3, A2, Immediate(kWordSize)); // Retval is next to 1st argument.
// Call runtime or redirection via simulator.
__ jalr(S5);
+ // Retval is next to 1st argument.
+ __ delay_slot()->addiu(A3, A2, Immediate(kWordSize));
__ TraceSimMsg("CallToRuntimeStub return");
// Reset exit frame information in Isolate structure.
@@ -93,9 +94,11 @@
// Load Context pointer from Isolate structure into A2.
__ lw(A2, Address(CTX, Isolate::top_context_offset()));
+ // Reload NULLREG.
+ __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
+
// Reset Context pointer in Isolate structure.
- __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(A3, Address(CTX, Isolate::top_context_offset()));
+ __ sw(NULLREG, Address(CTX, Isolate::top_context_offset()));
// Cache Context pointer into CTX while executing Dart code.
__ mov(CTX, A2);
@@ -175,10 +178,9 @@
__ sw(A1, Address(SP, 1 * kWordSize));
__ sw(A0, Address(SP, 0 * kWordSize));
- __ mov(A0, SP); // Pass the pointer to the NativeArguments.
-
// Call native function or redirection via simulator.
__ jalr(T5);
+ __ delay_slot()->mov(A0, SP); // Pass the pointer to the NativeArguments.
__ TraceSimMsg("CallNativeCFunctionStub return");
// Reset exit frame information in Isolate structure.
@@ -187,9 +189,11 @@
// Load Context pointer from Isolate structure into A2.
__ lw(A2, Address(CTX, Isolate::top_context_offset()));
+ // Reload NULLREG.
+ __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
+
// Reset Context pointer in Isolate structure.
- __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(A3, Address(CTX, Isolate::top_context_offset()));
+ __ sw(NULLREG, Address(CTX, Isolate::top_context_offset()));
// Cache Context pointer into CTX while executing Dart code.
__ mov(CTX, A2);
@@ -208,11 +212,10 @@
__ TraceSimMsg("CallStaticFunctionStub");
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S4, Address(SP, 1 * kWordSize));
- __ sw(T0, Address(SP, 0 * kWordSize));
+ __ sw(NULLREG, Address(SP, 0 * kWordSize));
__ CallRuntime(kPatchStaticCallRuntimeEntry);
__ TraceSimMsg("CallStaticFunctionStub return");
@@ -222,12 +225,11 @@
__ lw(S4, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
- // Remove the stub frame as we are about to jump to the dart function.
- __ LeaveStubFrame();
-
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
__ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
- __ jr(T0);
+
+ // Remove the stub frame as we are about to jump to the dart function.
+ __ LeaveStubFrameAndReturn(T0);
}
@@ -239,21 +241,21 @@
// calling into the runtime.
__ EnterStubFrame();
// Setup space on stack for return value and preserve arguments descriptor.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S4, Address(SP, 1 * kWordSize));
- __ sw(T0, Address(SP, 0 * kWordSize));
+ __ sw(NULLREG, Address(SP, 0 * kWordSize));
__ CallRuntime(kFixCallersTargetRuntimeEntry);
// Get Code object result and restore arguments descriptor array.
__ lw(T0, Address(SP, 0 * kWordSize));
__ lw(S4, Address(SP, 1 * kWordSize));
__ addiu(SP, SP, Immediate(2 * kWordSize));
- // Remove the stub frame.
- __ LeaveStubFrame();
+
// Jump to the dart function.
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
__ AddImmediate(T0, T0, Instructions::HeaderSize() - kHeapObjectTag);
- __ jr(T0);
+
+ // Remove the stub frame.
+ __ LeaveStubFrameAndReturn(T0);
}
@@ -263,7 +265,7 @@
static void PushArgumentsArray(Assembler* assembler) {
__ TraceSimMsg("PushArgumentsArray");
// Allocate array to store arguments of caller.
- __ LoadImmediate(A0, reinterpret_cast<intptr_t>(Object::null()));
+ __ mov(A0, NULLREG);
// A0: Null element type for raw Array.
// A1: Smi-tagged argument count, may be zero.
__ BranchLink(&StubCode::AllocateArrayLabel());
@@ -274,19 +276,21 @@
__ sll(T1, A1, 1);
__ addu(T1, FP, T1);
__ AddImmediate(T1, (kLastParamSlotIndex - 1) * kWordSize);
- __ AddImmediate(T2, V0, Array::data_offset() - kHeapObjectTag);
// T1: address of first argument on stack.
// T2: address of first argument in array.
- Label loop, loop_condition;
- __ b(&loop_condition);
+
+ Label loop, loop_exit;
+ __ blez(A1, &loop_exit);
+ __ delay_slot()->addiu(T2, V0,
+ Immediate(Array::data_offset() - kHeapObjectTag));
__ Bind(&loop);
__ lw(TMP, Address(T1));
- __ sw(TMP, Address(T2));
- __ AddImmediate(T1, -kWordSize);
- __ AddImmediate(T2, kWordSize);
- __ Bind(&loop_condition);
- __ AddImmediate(A1, -Smi::RawValue(1)); // A1 is Smi.
- __ BranchSignedGreaterEqual(A1, ZR, &loop);
+ __ addiu(A1, A1, Immediate(-Smi::RawValue(1)));
+ __ addiu(T1, T1, Immediate(-kWordSize));
+ __ addiu(T2, T2, Immediate(kWordSize));
+ __ bgez(A1, &loop);
+ __ delay_slot()->sw(TMP, Address(T2, -kWordSize));
+ __ Bind(&loop_exit);
}
@@ -310,9 +314,8 @@
// Push the receiver.
// Push TMP1 data object.
// Push arguments descriptor array.
- __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
__ addiu(SP, SP, Immediate(-4 * kWordSize));
- __ sw(TMP1, Address(SP, 3 * kWordSize));
+ __ sw(NULLREG, Address(SP, 3 * kWordSize));
__ sw(T1, Address(SP, 2 * kWordSize));
__ sw(S5, Address(SP, 1 * kWordSize));
__ sw(S4, Address(SP, 0 * kWordSize));
@@ -333,11 +336,11 @@
// TOS + 8: last argument of caller.
// ....
__ CallRuntime(kInstanceFunctionLookupRuntimeEntry);
- // Remove arguments.
- __ lw(V0, Address(SP, 4 * kWordSize));
- __ addiu(SP, SP, Immediate(5 * kWordSize)); // Get result into V0.
- __ LeaveStubFrame();
- __ Ret();
+
+ __ lw(V0, Address(SP, 4 * kWordSize)); // Get result into V0.
+ __ addiu(SP, SP, Immediate(5 * kWordSize)); // Remove arguments.
+
+ __ LeaveStubFrameAndReturn();
}
@@ -452,8 +455,8 @@
if (preserve_result) {
__ Pop(V0); // Restore result.
}
- __ LeaveStubFrame();
- __ Ret();
+
+ __ LeaveStubFrameAndReturn();
}
@@ -554,11 +557,11 @@
// T3: array size.
const intptr_t shift = RawObject::kSizeTagBit - kObjectAlignmentLog2;
// If no size tag overflow, shift T3 left, else set T3 to zero.
- __ LoadImmediate(TMP2, RawObject::SizeTag::kMaxSizeTag);
- __ sltu(CMPRES, TMP2, T3); // CMPRES = TMP2 < T3 ? 1 : 0
+ __ LoadImmediate(T4, RawObject::SizeTag::kMaxSizeTag);
+ __ sltu(CMPRES, T4, T3); // CMPRES = T4 < T3 ? 1 : 0
__ sll(TMP1, T3, shift); // TMP1 = T3 << shift;
- __ movz(T3, TMP1, CMPRES); // T3 = TMP2 >= T3 ? 0 : T3
- __ movn(T3, ZR, CMPRES); // T3 = TMP2 < T3 ? TMP1 : T3
+ __ movz(T3, TMP1, CMPRES); // T3 = T4 >= T3 ? 0 : T3
+ __ movn(T3, ZR, CMPRES); // T3 = T4 < T3 ? TMP1 : T3
// Get the class index and insert it into the tags.
__ LoadImmediate(TMP1, RawObject::ClassIdTag::encode(kArrayCid));
@@ -570,17 +573,16 @@
// T2: new object end address.
// A1: Array length as Smi.
__ AddImmediate(T3, V0, Array::data_offset() - kHeapObjectTag);
- // R1: iterator which initially points to the start of the variable
+ // T3: iterator which initially points to the start of the variable
// data area to be initialized.
- __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
- Label loop, test;
- __ b(&test);
+
+ Label loop, loop_exit;
+ __ BranchUnsignedGreaterEqual(T3, T2, &loop_exit);
__ Bind(&loop);
- // TODO(cshapiro): StoreIntoObjectNoBarrier
- __ sw(TMP1, Address(T3, 0));
- __ AddImmediate(T3, kWordSize);
- __ Bind(&test);
+ __ addiu(T3, T3, Immediate(kWordSize));
__ bne(T3, T2, &loop);
+ __ delay_slot()->sw(NULLREG, Address(T3, -kWordSize));
+ __ Bind(&loop_exit);
// Done allocating and initializing the array.
// V0: new object.
@@ -594,11 +596,10 @@
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
- __ LoadImmediate(TMP1, reinterpret_cast<intptr_t>(Object::null()));
// Setup space on stack for return value.
// Push array length as Smi and element type.
__ addiu(SP, SP, Immediate(-3 * kWordSize));
- __ sw(TMP1, Address(SP, 2 * kWordSize));
+ __ sw(NULLREG, Address(SP, 2 * kWordSize));
__ sw(A1, Address(SP, 1 * kWordSize));
__ sw(T3, Address(SP, 0 * kWordSize));
__ CallRuntime(kAllocateArrayRuntimeEntry);
@@ -609,8 +610,8 @@
__ lw(T3, Address(SP, 0 * kWordSize));
__ addiu(SP, SP, Immediate(3 * kWordSize));
__ mov(V0, TMP1);
- __ LeaveStubFrame();
- __ Ret();
+
+ __ LeaveStubFrameAndReturn();
}
@@ -637,9 +638,8 @@
// Verify that T1 is a closure by checking its class.
Label not_closure;
- __ LoadImmediate(T7, reinterpret_cast<intptr_t>(Object::null()));
// See if it is not a closure, but null object.
- __ beq(T1, T7, ¬_closure);
+ __ beq(T1, NULLREG, ¬_closure);
__ andi(CMPRES, T1, Immediate(kSmiTagMask));
__ beq(CMPRES, ZR, ¬_closure); // Not a closure, but a smi.
@@ -650,7 +650,7 @@
__ lw(T0, FieldAddress(T0, Class::signature_function_offset()));
// See if actual class is not a closure class.
- __ beq(T0, T7, ¬_closure);
+ __ beq(T0, NULLREG, ¬_closure);
// T0 is just the signature function. Load the actual closure function.
__ lw(T2, FieldAddress(T1, Closure::function_offset()));
@@ -661,7 +661,7 @@
Label function_compiled;
// Load closure function code in T0.
__ lw(T0, FieldAddress(T2, Function::code_offset()));
- __ bne(T0, T7, &function_compiled);
+ __ bne(T0, NULLREG, &function_compiled);
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
@@ -704,7 +704,8 @@
// Setup space on stack for result from error reporting.
__ addiu(SP, SP, Immediate(2 * kWordSize));
- __ sw(T7, Address(SP, 1 * kWordSize)); // Arguments descriptor and raw null.
+ // Arguments descriptor and raw null.
+ __ sw(NULLREG, Address(SP, 1 * kWordSize));
__ sw(S4, Address(SP, 0 * kWordSize));
// Load smi-tagged arguments array length, including the non-closure.
@@ -725,8 +726,7 @@
__ addiu(SP, SP, Immediate(3 * kWordSize)); // Remove arguments.
// Remove the stub frame as we are about to return.
- __ LeaveStubFrame();
- __ Ret();
+ __ LeaveStubFrameAndReturn();
}
@@ -795,12 +795,16 @@
// Compute address of 'arguments array' data area into A2.
__ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
- __ AddImmediate(A2, Array::data_offset() - kHeapObjectTag);
+
+ // Load the null Object into NULLREG for easy comparisons.
+ __ LoadImmediate(NULLREG, reinterpret_cast<intptr_t>(Object::null()));
// Set up arguments for the Dart call.
Label push_arguments;
Label done_push_arguments;
__ beq(T1, ZR, &done_push_arguments); // check if there are arguments.
+ __ delay_slot()->addiu(A2, A2,
+ Immediate(Array::data_offset() - kHeapObjectTag));
__ mov(A1, ZR);
__ Bind(&push_arguments);
__ lw(A3, Address(A2));
@@ -843,8 +847,7 @@
__ addiu(SP, SP, Immediate((3 + kAbiPreservedCpuRegCount) * kWordSize));
// Restore the frame pointer and return.
- __ LeaveStubFrame();
- __ Ret();
+ __ LeaveStubFrameAndReturn();
}
@@ -905,7 +908,7 @@
__ LoadImmediate(TMP1, RawObject::SizeTag::kMaxSizeTag);
__ sltu(CMPRES, TMP1, T2); // CMPRES = T2 > TMP1 ? 1 : 0.
__ movn(T2, ZR, CMPRES); // T2 = CMPRES != 0 ? 0 : T2.
- __ sll(TMP1, T2, shift); // TMP2 = T2 << shift.
+ __ sll(TMP1, T2, shift); // TMP1 = T2 << shift.
__ movz(T2, TMP1, CMPRES); // T2 = CMPRES == 0 ? TMP1 : T2.
// Get the class index and insert it into the tags.
@@ -927,26 +930,21 @@
// T2: isolate, not an object.
__ sw(T2, FieldAddress(V0, Context::isolate_offset()));
- // Setup the parent field.
- // V0: new object.
- // T1: number of context variables.
- __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(T2, FieldAddress(V0, Context::parent_offset()));
-
// Initialize the context variables.
// V0: new object.
// T1: number of context variables.
- // T2: raw null.
- Label loop, loop_test;
+ Label loop, loop_exit;
+ __ blez(T1, &loop_exit);
+ // Setup the parent field.
+ __ delay_slot()->sw(NULLREG, FieldAddress(V0, Context::parent_offset()));
__ AddImmediate(T3, V0, Context::variable_offset(0) - kHeapObjectTag);
- __ b(&loop_test);
- __ delay_slot()->sll(T1, T1, 2);
+ __ sll(T1, T1, 2);
__ Bind(&loop);
- __ addu(TMP1, T3, T1);
- __ sw(T2, Address(TMP1));
- __ Bind(&loop_test);
__ addiu(T1, T1, Immediate(-kWordSize));
- __ bne(T1, ZR, &loop); // Loop if R1 not zero.
+ __ addu(TMP1, T3, T1);
+ __ bgtz(T1, &loop);
+ __ delay_slot()->sw(NULLREG, Address(TMP1));
+ __ Bind(&loop_exit);
// Done allocating and initializing the context.
// V0: new object.
@@ -958,10 +956,9 @@
// calling into the runtime.
__ EnterStubFrame();
// Setup space on stack for return value.
- __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null()));
__ SmiTag(T1);
__ addiu(SP, SP, Immediate(-2 * kWordSize));
- __ sw(T2, Address(SP, 1 * kWordSize));
+ __ sw(NULLREG, Address(SP, 1 * kWordSize));
__ sw(T1, Address(SP, 0 * kWordSize));
__ CallRuntime(kAllocateContextRuntimeEntry); // Allocate context.
__ lw(V0, Address(SP, 1 * kWordSize)); // Get the new context.
@@ -969,8 +966,7 @@
// V0: new object
// Restore the frame pointer.
- __ LeaveStubFrame();
- __ Ret();
+ __ LeaveStubFrameAndReturn();
}
@@ -1129,9 +1125,6 @@
__ sw(T0, Address(T2, Instance::tags_offset()));
// Initialize the remaining words of the object.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
-
- // T0: raw null.
// T2: new object start.
// T3: next object start.
// T1: new object type arguments (if is_cls_parameterized).
@@ -1142,24 +1135,22 @@
for (intptr_t current_offset = sizeof(RawObject);
current_offset < instance_size;
current_offset += kWordSize) {
- __ sw(T0, Address(T2, current_offset));
+ __ sw(NULLREG, Address(T2, current_offset));
}
} else {
__ addiu(T4, T2, Immediate(sizeof(RawObject)));
// Loop until the whole object is initialized.
- // T0: raw null.
// T2: new object.
// T3: next object start.
// T4: next word to be initialized.
// T1: new object type arguments (if is_cls_parameterized).
- Label init_loop;
- Label done;
- __ Bind(&init_loop);
- __ BranchUnsignedGreaterEqual(T4, T3, &done); // Done if T4 >= T3.
- __ sw(T0, Address(T4));
- __ AddImmediate(T4, kWordSize);
- __ b(&init_loop);
- __ Bind(&done);
+ Label loop, loop_exit;
+ __ BranchUnsignedGreaterEqual(T4, T3, &loop_exit);
+ __ Bind(&loop);
+ __ addiu(T4, T4, Immediate(kWordSize));
+ __ bne(T4, T3, &loop);
+ __ delay_slot()->sw(NULLREG, Address(T4, -kWordSize));
+ __ Bind(&loop_exit);
}
if (is_cls_parameterized) {
// R1: new object type arguments.
@@ -1180,11 +1171,11 @@
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime.
- __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(TMP1, cls);
__ addiu(SP, SP, Immediate(-4 * kWordSize));
- __ sw(T2, Address(SP, 3 * kWordSize)); // Space on stack for return value.
+ // Space on stack for return value.
+ __ sw(NULLREG, Address(SP, 3 * kWordSize));
__ sw(TMP1, Address(SP, 2 * kWordSize)); // Class of object to be allocated.
if (is_cls_parameterized) {
@@ -1194,7 +1185,7 @@
} else {
// Push null type arguments and kNoInstantiator.
__ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator));
- __ sw(T2, Address(SP, 1 * kWordSize));
+ __ sw(NULLREG, Address(SP, 1 * kWordSize));
__ sw(T1, Address(SP, 0 * kWordSize));
}
__ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object.
@@ -1203,9 +1194,8 @@
__ lw(V0, Address(SP, 3 * kWordSize));
__ addiu(SP, SP, Immediate(4 * kWordSize)); // Pop arguments.
// V0: new object
- // Restore the frame pointer.
- __ LeaveStubFrame(true);
- __ Ret();
+ // Restore the frame pointer and return.
+ __ LeaveStubFrameAndReturn(RA, true);
}
@@ -1299,8 +1289,7 @@
__ sw(T0, Address(T4, Context::isolate_offset()));
// Set the parent to null.
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(T0, Address(T4, Context::parent_offset()));
+ __ sw(NULLREG, Address(T4, Context::parent_offset()));
// Initialize the context variable to the receiver.
__ lw(T0, Address(FP, kReceiverFPOffset));
@@ -1320,8 +1309,8 @@
// Done allocating and initializing the instance.
// V0: new object.
__ addiu(V0, T2, Immediate(kHeapObjectTag));
- __ LeaveStubFrame(true);
- __ Ret();
+
+ __ LeaveStubFrameAndReturn(RA, true);
__ Bind(&slow_case);
}
@@ -1333,10 +1322,9 @@
num_slots = is_implicit_instance_closure ? 4 : 3;
}
__ addiu(SP, SP, Immediate(-num_slots * kWordSize));
- __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
__ LoadObject(TMP1, func);
// Setup space on stack for return value.
- __ sw(V0, Address(SP, (num_slots - 1) * kWordSize));
+ __ sw(NULLREG, Address(SP, (num_slots - 1) * kWordSize));
__ sw(TMP1, Address(SP, (num_slots - 2) * kWordSize));
if (is_implicit_static_closure) {
__ CallRuntime(kAllocateImplicitStaticClosureRuntimeEntry);
@@ -1345,7 +1333,7 @@
if (is_implicit_instance_closure) {
__ lw(T1, Address(FP, kReceiverFPOffset));
__ sw(T1, Address(SP, (num_slots - 3) * kWordSize)); // Receiver.
- __ sw(V0, Address(SP, (num_slots - 4) * kWordSize)); // Push null.
+ __ sw(NULLREG, Address(SP, (num_slots - 4) * kWordSize)); // Push null.
}
if (has_type_arguments) {
__ lw(V0, Address(FP, kTypeArgumentsFPOffset));
@@ -1367,8 +1355,7 @@
// V0: new object
// Restore the frame pointer.
- __ LeaveStubFrame(true);
- __ Ret();
+ __ LeaveStubFrameAndReturn(RA, true);
}
@@ -1544,14 +1531,13 @@
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
- __ LoadImmediate(T3, reinterpret_cast<intptr_t>(Object::null()));
// Preserve IC data object and arguments descriptor array and
// setup space on stack for result (target code object).
int num_slots = num_args + 5;
__ addiu(SP, SP, Immediate(-num_slots * kWordSize));
__ sw(S5, Address(SP, (num_slots - 1) * kWordSize));
__ sw(S4, Address(SP, (num_slots - 2) * kWordSize));
- __ sw(T3, Address(SP, (num_slots - 3) * kWordSize));
+ __ sw(NULLREG, Address(SP, (num_slots - 3) * kWordSize));
// Push call arguments.
for (intptr_t i = 0; i < num_args; i++) {
__ lw(TMP1, Address(T1, -i * kWordSize));
@@ -1581,14 +1567,14 @@
__ addiu(SP, SP, Immediate(num_slots * kWordSize));
__ LeaveStubFrame();
Label call_target_function;
- __ BranchNotEqual(T3, reinterpret_cast<intptr_t>(Object::null()),
- &call_target_function);
+ __ bne(T3, NULLREG, &call_target_function);
+
// NoSuchMethod or closure.
// Mark IC call that it may be a closure call that does not collect
// type feedback.
- __ LoadImmediate(TMP2, 1);
+ __ LoadImmediate(TMP1, 1);
__ Branch(&StubCode::InstanceFunctionLookupLabel());
- __ delay_slot()->sb(TMP2, FieldAddress(S5, ICData::is_closure_call_offset()));
+ __ delay_slot()->sb(TMP1, FieldAddress(S5, ICData::is_closure_call_offset()));
__ Bind(&found);
// T0: Pointer to an IC data check group.
@@ -1597,7 +1583,7 @@
__ lw(T3, Address(T0, target_offset));
__ lw(T4, Address(T0, count_offset));
- __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5);
+ __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5, T6);
__ bgez(T5, &call_target_function); // No overflow.
__ delay_slot()->sw(T4, Address(T0, count_offset));
@@ -1611,6 +1597,8 @@
__ lw(T3, FieldAddress(T3, Code::instructions_offset()));
__ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag);
__ jr(T3);
+ __ delay_slot()->addiu(T3, T3,
+ Immediate(Instructions::HeaderSize() - kHeapObjectTag));
// Instance in T3, return its class-id in T3 as Smi.
__ Bind(&get_class_id_as_smi);
@@ -1618,13 +1606,13 @@
// Test if Smi -> load Smi class for comparison.
__ andi(TMP1, T3, Immediate(kSmiTagMask));
__ bne(TMP1, ZR, ¬_smi);
- __ LoadImmediate(T3, Smi::RawValue(kSmiCid));
__ jr(RA);
+ __ delay_slot()->addiu(T3, ZR, Immediate(Smi::RawValue(kSmiCid)));
__ Bind(¬_smi);
__ LoadClassId(T3, T3);
- __ SmiTag(T3);
__ jr(RA);
+ __ delay_slot()->SmiTag(T3);
}
@@ -1695,11 +1683,10 @@
// Create a stub frame as we are pushing some objects on the stack before
// calling into the runtime.
__ EnterStubFrame();
- __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
// Preserve arguments descriptor and make room for result.
__ addiu(SP, SP, Immediate(-2 * kWordSize));
__ sw(S4, Address(SP, 1 * kWordSize));
- __ sw(T0, Address(SP, 0 * kWordSize));
+ __ sw(NULLREG, Address(SP, 0 * kWordSize));
__ CallRuntime(kBreakpointStaticHandlerRuntimeEntry);
// Pop code object result and restore arguments descriptor.
__ lw(T0, Address(SP, 0 * kWordSize));
@@ -1728,8 +1715,7 @@
// Instead of returning to the patched Dart function, emulate the
// smashed return code pattern and return to the function's caller.
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
}
@@ -1782,7 +1768,6 @@
__ LoadClass(T0, A0);
// Compute instance type arguments into R4.
Label has_no_type_arguments;
- __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null()));
__ lw(T2, FieldAddress(T0,
Class::type_arguments_field_offset_in_words_offset()));
__ BranchEqual(T2, Class::kNoTypeArguments, &has_no_type_arguments);
@@ -1807,7 +1792,7 @@
__ SmiTag(T0);
__ Bind(&loop);
__ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
- __ BranchEqual(T3, reinterpret_cast<intptr_t>(Object::null()), ¬_found);
+ __ beq(T3, NULLREG, ¬_found);
if (n == 1) {
__ beq(T3, T0, &found);
@@ -1825,12 +1810,13 @@
}
}
__ Bind(&next_iteration);
- __ AddImmediate(T2, kWordSize * SubtypeTestCache::kTestEntryLength);
__ b(&loop);
+ __ delay_slot()->addiu(T2, T2,
+ Immediate(kWordSize * SubtypeTestCache::kTestEntryLength));
// Fall through to not found.
__ Bind(¬_found);
- __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
__ Ret();
+ __ delay_slot()->mov(V0, NULLREG);
__ Bind(&found);
__ Ret();
@@ -1893,8 +1879,8 @@
__ mov(V0, A3); // Exception object.
__ lw(V1, Address(SP, 0)); // StackTrace object.
__ mov(FP, A2); // Frame_pointer.
- __ mov(SP, A1); // Stack pointer.
__ jr(A0); // Jump to the exception handler code.
+ __ delay_slot()->mov(SP, A1); // Stack pointer.
}
@@ -1939,8 +1925,14 @@
__ beq(T2, T3, &found); // Class id match?
__ Bind(&no_match);
// Next check group.
- __ AddImmediate(T6, kWordSize * ICData::TestEntryLengthFor(kNumArgsTested));
- __ BranchNotEqual(T3, Smi::RawValue(kIllegalCid), &loop); // Done?
+ intptr_t entry_bytes = kWordSize * ICData::TestEntryLengthFor(kNumArgsTested);
+ if (Utils::IsInt(kImmBits, entry_bytes)) {
+ __ BranchNotEqual(T3, Smi::RawValue(kIllegalCid), &loop); // Done?
+ __ delay_slot()->addiu(T6, T6, Immediate(entry_bytes));
+ } else {
+ __ AddImmediate(T6, entry_bytes);
+ __ BranchNotEqual(T3, Smi::RawValue(kIllegalCid), &loop); // Done?
+ }
Label update_ic_data;
__ b(&update_ic_data);
@@ -1950,7 +1942,7 @@
ICData::CountIndexFor(kNumArgsTested) * kWordSize;
Label no_overflow;
__ lw(T1, Address(T6, count_offset));
- __ AddImmediateDetectOverflow(T1, T1, Smi::RawValue(1), CMPRES);
+ __ AddImmediateDetectOverflow(T1, T1, Smi::RawValue(1), CMPRES, T6);
__ bgez(CMPRES, &no_overflow);
__ LoadImmediate(TMP1, Smi::RawValue(Smi::kMaxValue));
__ sw(TMP1, Address(T6, count_offset)); // If overflow.
@@ -1958,13 +1950,12 @@
Label compute_result;
__ Bind(&compute_result);
- __ LoadObject(TMP1, Bool::True());
- __ LoadObject(TMP2, Bool::False());
+ __ LoadObject(T4, Bool::True());
+ __ LoadObject(T5, Bool::False());
__ subu(CMPRES, A0, A1);
- __ movz(V0, TMP1, CMPRES);
- __ movn(V0, TMP2, CMPRES);
- __ LeaveStubFrame();
- __ Ret();
+ __ movz(V0, T4, CMPRES);
+ __ movn(V0, T5, CMPRES);
+ __ LeaveStubFrameAndReturn();
__ Bind(&get_class_id_as_smi);
// Test if Smi -> load Smi class for comparison.
@@ -2003,8 +1994,7 @@
__ addiu(SP, SP, Immediate(-3 * kWordSize));
__ sw(S4, Address(SP, 2 * kWordSize));
// Setup space on stack for return value.
- __ LoadImmediate(TMP, reinterpret_cast<intptr_t>(Object::null()));
- __ sw(TMP1, Address(SP, 1 * kWordSize));
+ __ sw(NULLREG, Address(SP, 1 * kWordSize));
__ sw(T0, Address(SP, 0 * kWordSize));
__ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry);
__ TraceSimMsg("OptimizeFunctionStub return");
@@ -2014,8 +2004,7 @@
__ lw(T0, FieldAddress(T0, Code::instructions_offset()));
__ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
- __ LeaveStubFrame();
- __ jr(T0);
+ __ LeaveStubFrameAndReturn(T0);
__ break_(0);
}
@@ -2037,8 +2026,8 @@
void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
__ TraceSimMsg("IdenticalWithNumberCheckStub");
const Register ret = CMPRES;
- const Register temp1 = TMP1;
- const Register temp2 = TMP2;
+ const Register temp1 = T2;
+ const Register temp2 = T3;
const Register left = T1;
const Register right = T0;
// Preserve left, right.
diff --git a/runtime/vm/stub_code_mips_test.cc b/runtime/vm/stub_code_mips_test.cc
index bbe5744..6fdbdfd 100644
--- a/runtime/vm/stub_code_mips_test.cc
+++ b/runtime/vm/stub_code_mips_test.cc
@@ -54,8 +54,7 @@
__ CallRuntime(kTestSmiSubRuntimeEntry); // Call SmiSub runtime func.
__ addiu(SP, SP, Immediate(argc * kWordSize));
__ Pop(V0); // Pop return value from return slot.
- __ LeaveDartFrame();
- __ Ret();
+ __ LeaveDartFrameAndReturn();
}
@@ -87,8 +86,7 @@
__ LoadObject(A0, smi1); // Set up argument 1 smi1.
__ LoadObject(A1, smi2); // Set up argument 2 smi2.
__ CallRuntime(kTestLeafSmiAddRuntimeEntry); // Call SmiAdd runtime func.
- __ LeaveDartFrame();
- __ Ret(); // Return value is in R0.
+ __ LeaveDartFrameAndReturn(); // Return value is in V0.
}
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index fd859af..78febab 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -43,7 +43,7 @@
isBinaryOperator,
isTernaryOperator,
isMinusOperator;
-export 'universe/universe.dart' show Selector;
+export 'universe/universe.dart' show Selector, TypedSelector;
part 'code_buffer.dart';
part 'compile_time_constants.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/js/builder.dart b/sdk/lib/_internal/compiler/implementation/js/builder.dart
index 1a22692..a1d4f41 100644
--- a/sdk/lib/_internal/compiler/implementation/js/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/builder.dart
@@ -10,19 +10,39 @@
class JsBuilder {
const JsBuilder();
- // Parse a bit of JS, and return an expression. See the MiniJsParser class.
+ // Parse a bit of JavaScript, and return an expression.
+ // See the MiniJsParser class.
// You can provide an expression or a list of expressions, which will be
// interpolated into the source at the '#' signs.
Expression call(String source, [var expression]) {
+ var result = new MiniJsParser(source).expression();
+ if (expression == null) return result;
+
List<Expression> expressions;
- if (expression != null) {
- if (expression is List) {
- expressions = expression;
- } else {
- expressions = <Expression>[expression];
- }
+ if (expression is List) {
+ expressions = expression;
+ } else {
+ expressions = <Expression>[expression];
}
- return new MiniJsParser(source, expressions).expression();
+ if (expressions.length != result.interpolatedExpressions.length) {
+ throw "Unmatched number of interpolated expressions";
+ }
+ for (int i = 0; i < expressions.length; i++) {
+ result.interpolatedExpressions[i].value = expressions[i];
+ }
+
+ return result.value;
+ }
+
+ // Parse JavaScript written in the JS foreign instruction.
+ Expression parseForeignJS(String source, [var expression]) {
+ // We can parse simple JS with the mini parser. At the moment we can't
+ // handle JSON literals and function literals, both of which contain "{".
+ if (source.contains("{") || source.startsWith("throw ")) {
+ assert(expression == null);
+ return new LiteralExpression(source);
+ }
+ return call(source, expression);
}
LiteralString string(String value) => new LiteralString('"$value"');
@@ -181,12 +201,11 @@
/// allowed in string and regexp literals because the machinery for checking
/// their correctness is rather involved.
class MiniJsParser {
- MiniJsParser(this.src, this.interpolatedValues)
+ MiniJsParser(this.src)
: lastCategory = NONE,
lastToken = null,
lastPosition = 0,
- position = 0,
- valuesUsed = 0 {
+ position = 0 {
getToken();
}
@@ -194,9 +213,9 @@
String lastToken;
int lastPosition;
int position;
- int valuesUsed;
String src;
- List<Expression> interpolatedValues;
+ final List<InterpolatedExpression> interpolatedValues =
+ <InterpolatedExpression>[];
static const NONE = -1;
static const ALPHA = 0;
@@ -459,11 +478,9 @@
Expression expression = new RegExpLiteral(regexp + flags);
return expression;
} else if (acceptCategory(HASH)) {
- if (interpolatedValues == null ||
- valuesUsed >= interpolatedValues.length) {
- error("Too few values for '#'s");
- }
- return interpolatedValues[valuesUsed++];
+ InterpolatedExpression expression = new InterpolatedExpression(null);
+ interpolatedValues.add(expression);
+ return expression;
} else {
error("Expected primary expression");
}
@@ -638,9 +655,141 @@
if (lastCategory != NONE || position != src.length) {
error("Unparsed junk: ${categoryToString(lastCategory)}");
}
- if (interpolatedValues != null && valuesUsed != interpolatedValues.length) {
- error("Too many values for #es");
+ if (!interpolatedValues.isEmpty) {
+ return new JSExpression(expression, interpolatedValues);
}
return expression;
}
}
+
+/**
+ * Clone a JSExpression node into an expression where all children
+ * have been cloned, and [InterpolatedExpression]s have been replaced
+ * with real [Expression].
+ */
+class UninterpolateJSExpression extends BaseVisitor<Node> {
+ final List<Expression> arguments;
+ int argumentIndex = 0;
+
+ UninterpolateJSExpression(this.arguments);
+
+ void error(message) {
+ throw message;
+ }
+
+ Node visitNode(Node node) {
+ error('Cannot handle $node');
+ }
+
+ Node copyPosition(Node oldNode, Node newNode) {
+ newNode.sourcePosition = oldNode.sourcePosition;
+ newNode.endSourcePosition = oldNode.endSourcePosition;
+ return newNode;
+ }
+
+ Node visit(Node node) {
+ return node == null ? null : node.accept(this);
+ }
+
+ List<Node> visitList(List<Node> list) {
+ return list.map((e) => visit(e)).toList();
+ }
+
+ Node visitLiteralString(LiteralString node) {
+ return node;
+ }
+
+ Node visitVariableUse(VariableUse node) {
+ return node;
+ }
+
+ Node visitAccess(PropertyAccess node) {
+ return copyPosition(node,
+ new PropertyAccess(visit(node.receiver), visit(node.selector)));
+ }
+
+ Node visitCall(Call node) {
+ return copyPosition(node,
+ new Call(visit(node.target), visitList(node.arguments)));
+ }
+
+ Node visitInterpolatedExpression(InterpolatedExpression expression) {
+ return arguments[argumentIndex++];
+ }
+
+ Node visitJSExpression(JSExpression expression) {
+ assert(argumentIndex == 0);
+ Node result = visit(expression.value);
+ if (argumentIndex != arguments.length) {
+ error("Invalid number of arguments");
+ }
+ assert(result is! JSExpression);
+ return result;
+ }
+
+ Node visitLiteralExpression(LiteralExpression node) {
+ assert(argumentIndex == 0);
+ return copyPosition(node,
+ new LiteralExpression.withData(node.template, arguments));
+ }
+
+ Node visitAssignment(Assignment node) {
+ return copyPosition(node,
+ new Assignment._internal(visit(node.leftHandSide),
+ visit(node.compoundTarget),
+ visit(node.value)));
+ }
+
+ Node visitRegExpLiteral(RegExpLiteral node) {
+ return node;
+ }
+
+ Node visitLiteralNumber(LiteralNumber node) {
+ return node;
+ }
+
+ Node visitBinary(Binary node) {
+ return copyPosition(node,
+ new Binary(node.op, visit(node.left), visit(node.right)));
+ }
+
+ Node visitPrefix(Prefix node) {
+ return copyPosition(node,
+ new Prefix(node.op, visit(node.argument)));
+ }
+
+ Node visitPostfix(Postfix node) {
+ return copyPosition(node,
+ new Postfix(node.op, visit(node.argument)));
+ }
+
+ Node visitNew(New node) {
+ return copyPosition(node,
+ new New(visit(node.target), visitList(node.arguments)));
+ }
+
+ Node visitArrayInitializer(ArrayInitializer node) {
+ return copyPosition(node,
+ new ArrayInitializer(node.length, visitList(node.elements)));
+ }
+
+ Node visitArrayElement(ArrayElement node) {
+ return copyPosition(node,
+ new ArrayElement(node.index, visit(node.value)));
+ }
+
+ Node visitConditional(Conditional node) {
+ return copyPosition(node,
+ new Conditional(visit(node.condition),
+ visit(node.then),
+ visit(node.otherwise)));
+ }
+
+ Node visitLiteralNull(LiteralNull node) {
+ return node;
+ }
+
+ Node visitLiteralBool(LiteralBool node) {
+ return node;
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/js/nodes.dart b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
index 5fe00a4..9f57b32 100644
--- a/sdk/lib/_internal/compiler/implementation/js/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/nodes.dart
@@ -61,6 +61,9 @@
T visitRegExpLiteral(RegExpLiteral node);
T visitComment(Comment node);
+
+ T visitInterpolatedExpression(InterpolatedExpression node);
+ T visitJSExpression(JSExpression node);
}
class BaseVisitor<T> implements NodeVisitor<T> {
@@ -144,6 +147,10 @@
T visitProperty(Property node) => visitNode(node);
T visitRegExpLiteral(RegExpLiteral node) => visitExpression(node);
+ T visitInterpolatedExpression(InterpolatedExpression node)
+ => visitExpression(node);
+ T visitJSExpression(JSExpression node) => visitExpression(node);
+
// Ignore comments by default.
T visitComment(Comment node) {}
}
@@ -569,9 +576,11 @@
final VariableReference compoundTarget;
final Expression value; // May be null, for [VariableInitialization]s.
- Assignment(this.leftHandSide, this.value) : compoundTarget = null;
- Assignment.compound(this.leftHandSide, String op, this.value)
- : compoundTarget = new VariableUse(op);
+ Assignment(leftHandSide, value)
+ : this._internal(leftHandSide, null, value);
+ Assignment.compound(leftHandSide, String op, value)
+ : this._internal(leftHandSide, new VariableUse(op), value);
+ Assignment._internal(this.leftHandSide, this.compoundTarget, this.value);
int get precedenceLevel => ASSIGNMENT;
@@ -917,6 +926,38 @@
}
}
+class InterpolatedExpression extends Expression {
+ Expression value;
+
+ InterpolatedExpression(this.value);
+
+ accept(NodeVisitor visitor) => visitor.visitInterpolatedExpression(this);
+
+ void visitChildren(NodeVisitor visitor) {
+ value.accept(visitor);
+ }
+
+ int get precedenceLevel => value.precedenceLevel;
+}
+
+class JSExpression extends Expression {
+ Expression value;
+ List<InterpolatedExpression> interpolatedExpressions;
+
+ JSExpression(this.value, this.interpolatedExpressions);
+
+ accept(NodeVisitor visitor) => visitor.visitJSExpression(this);
+
+ void visitChildren(NodeVisitor visitor) {
+ value.accept(visitor);
+ for (InterpolatedExpression expression in interpolatedExpressions) {
+ expression.accept(visitor);
+ }
+ }
+
+ int get precedenceLevel => value.precedenceLevel;
+}
+
/**
* [RegExpLiteral]s, despite being called "Literal", do not inherit from
* [Literal]. Indeed, regular expressions in JavaScript have a side-effect and
diff --git a/sdk/lib/_internal/compiler/implementation/js/printer.dart b/sdk/lib/_internal/compiler/implementation/js/printer.dart
index 91d46b5..2645362 100644
--- a/sdk/lib/_internal/compiler/implementation/js/printer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js/printer.dart
@@ -853,6 +853,14 @@
outLn(node.code);
}
+ visitJSExpression(JSExpression node) {
+ compiler.internalError('JSPrinter should never see a JSExpression');
+ }
+
+ visitInterpolatedExpression(InterpolatedExpression node) {
+ visit(node.value);
+ }
+
void visitComment(Comment node) {
if (shouldCompressOutput) return;
String comment = node.comment.trim();
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 1289c7f..1966691 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -351,7 +351,7 @@
return [
js('var $supportsProtoName = false'),
- js('var tmp = defineClass("c", "c", ["f?"], {}).prototype'),
+ js('var tmp = defineClass("c", "c", ["f<"], {}).prototype'),
js.if_(js('tmp.__proto__'), [
js('tmp.__proto__ = {}'),
@@ -1251,11 +1251,14 @@
// Add checks to the constructors of instantiated classes.
for (ClassElement cls in typeChecks) {
String holder = namer.isolateAccess(backend.getImplementationClass(cls));
- for (ClassElement check in typeChecks[cls]) {
- buffer.write('$holder.${namer.operatorIs(check)}$_=${_}true$N');
- String body = rti.getSupertypeSubstitution(cls, check);
- if (body != null) {
- buffer.write('$holder.${namer.substitutionName(check)}$_=${_}$body$N');
+ for (TypeCheck check in typeChecks[cls]) {
+ ClassElement cls = check.cls;
+ buffer.write('$holder.${namer.operatorIs(check.cls)}$_=${_}true$N');
+ buffer.write('$holder.${namer.operatorIs(cls)}$_=${_}true$N');
+ Substitution substitution = check.substitution;
+ if (substitution != null) {
+ String body = substitution.getCode(rti, false);
+ buffer.write('$holder.${namer.substitutionName(cls)}$_=${_}$body$N');
}
};
}
@@ -2233,32 +2236,16 @@
DartType objectType = objectClass.computeType(compiler);
for (Selector selector in selectors) {
- // Introduce a helper function that determines if the given
- // class has a member that matches the current name and
- // selector (grabbed from the scope).
- bool hasMatchingMember(ClassElement holder) {
- Element element = holder.lookupSelector(selector);
- return (element != null)
- ? selector.applies(element, compiler)
- : false;
- }
-
// If the selector is typed, we check to see if that type may
// have a user-defined noSuchMethod implementation. If not, we
// skip the selector altogether.
- // TODO(kasperl): This shouldn't depend on the internals of
- // the type mask. Move more of this code to the type mask.
- ClassElement receiverClass = objectClass;
TypeMask mask = selector.mask;
- if (mask != null) {
- // If the mask is empty it doesn't contain a noSuchMethod
- // handler -- not even if it is nullable.
- if (mask.isEmpty) continue;
- receiverClass = mask.base.element;
+ if (mask == null) {
+ mask = new TypeMask.subclass(compiler.objectClass.rawType);
}
- // If the receiver class is guaranteed to have a member that
+ // If the receiver is guaranteed to have a member that
// matches what we're looking for, there's no need to
// introduce a noSuchMethod handler. It will never be called.
//
@@ -2273,7 +2260,6 @@
// because objects of type B implement foo. On the other hand,
// if we end up calling foo on something of type C we have to
// add a handler for it.
- if (hasMatchingMember(receiverClass)) continue;
// If the holders of all user-defined noSuchMethod
// implementations that might be applicable to the receiver
@@ -2300,9 +2286,7 @@
// If we're calling bar on an object of type A we do need the
// handler because we may have to call B.noSuchMethod since B
// does not implement bar.
- Iterable<ClassElement> holders =
- compiler.world.locateNoSuchMethodHolders(selector);
- if (holders.every(hasMatchingMember)) continue;
+ if (mask.willHit(selector, compiler)) continue;
String jsName = namer.invocationMirrorInternalName(selector);
addedJsNames[jsName] = selector;
}
@@ -2597,37 +2581,53 @@
compiler.codegenWorld.instantiatedClasses.where(computeClassFilter())
.toSet();
- RuntimeTypes rti = backend.rti;
-
- // We need to generate classes that are instantiated or used as a type
- // arguments.
- neededClasses.addAll(instantiatedClasses);
- rti.allArguments.forEach((ClassElement c) {
- // Types that we represent with JS native types (like int and String) do
- // not need a class definition as we use the interceptor classes instead.
- if (!rti.isJsNative(c)) {
- neededClasses.add(c);
- }
- });
-
- // Then add all superclasses of these classes.
- for (ClassElement element in neededClasses.toList() /* copy */) {
- for (ClassElement superclass = element.superclass;
+ void addClassWithSuperclasses(ClassElement cls) {
+ neededClasses.add(cls);
+ for (ClassElement superclass = cls.superclass;
superclass != null;
superclass = superclass.superclass) {
- if (neededClasses.contains(superclass)) break;
neededClasses.add(superclass);
}
}
- // Then add all classes used as mixins.
+ void addClassesWithSuperclasses(Iterable<ClassElement> classes) {
+ for (ClassElement cls in classes) {
+ addClassWithSuperclasses(cls);
+ }
+ }
+
+ // 1. We need to generate all classes that are instantiated.
+ addClassesWithSuperclasses(instantiatedClasses);
+
+ // 2. Add all classes used as mixins.
Set<ClassElement> mixinClasses = neededClasses
.where((ClassElement element) => element.isMixinApplication)
.map(computeMixinClass)
.toSet();
neededClasses.addAll(mixinClasses);
- // Finally, sort the classes.
+ // 3a. Add classes that are referenced by type arguments or substitutions in
+ // argument checks.
+ // TODO(karlklose): merge this case with 3b when unifying argument and
+ // object checks.
+ RuntimeTypes rti = backend.rti;
+ backend.rti.getRequiredArgumentClasses(backend).forEach((ClassElement c) {
+ // Types that we represent with JS native types (like int and String) do
+ // not need a class definition as we use the interceptor classes instead.
+ if (!rti.isJsNative(c)) {
+ addClassWithSuperclasses(c);
+ }
+ });
+
+ // 3b. Add classes that are referenced by substitutions in object checks and
+ // their superclasses.
+ TypeChecks requiredChecks =
+ backend.rti.computeChecks(neededClasses, checkedClasses);
+ Set<ClassElement> classesUsedInSubstitutions =
+ rti.getClassesUsedInSubstitutions(backend, requiredChecks);
+ addClassesWithSuperclasses(classesUsedInSubstitutions);
+
+ // 4. Finally, sort the classes.
List<ClassElement> sortedClasses = Elements.sortedByPosition(neededClasses);
// If we need noSuchMethod support, we run through all needed
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
index 77ed6f4..81e68be 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/js_backend.dart
@@ -12,7 +12,7 @@
import '../elements/modelx.dart' show FunctionElementX;
// TODO(ahe): There seems to be a bug in the VM, so we have to hide "js".
-import '../dart2jslib.dart' hide Selector, js;
+import '../dart2jslib.dart' hide Selector, TypedSelector, js;
import '../dart_types.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js; // TODO(ahe): VM bug, see above.
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
index b3355b5..0c02e6e 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/runtime_types.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// 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.
@@ -7,11 +7,13 @@
/// For each class, stores the possible class subtype tests that could succeed.
abstract class TypeChecks {
/// Get the set of checks required for class [element].
- Iterable<ClassElement> operator[](ClassElement element);
+ Iterable<TypeCheck> operator[](ClassElement element);
/// Get the iterator for all classes that need type checks.
Iterator<ClassElement> get iterator;
}
+typedef String VariableSubstitution(TypeVariableType variable);
+
class RuntimeTypes {
final Compiler compiler;
final TypeRepresentationGenerator representationGenerator;
@@ -31,9 +33,9 @@
rtiDependencies = new Map<ClassElement, Set<ClassElement>>(),
classesUsingTypeVariableExpression = new Set<ClassElement>();
- /// Contains the classes of all arguments that have been used in
- /// instantiations and checks.
- Set<ClassElement> cachedAllArguments;
+ Set<ClassElement> directlyInstantiatedArguments;
+ Set<ClassElement> allInstantiatedArguments;
+ Set<ClassElement> checkedArguments;
bool isJsNative(Element element) {
return (element == compiler.intClass ||
@@ -44,14 +46,6 @@
element == compiler.listClass);
}
- Set<ClassElement> get allArguments {
- if (cachedRequiredChecks == null) {
- computeRequiredChecks();
- }
- assert(cachedAllArguments != null);
- return cachedAllArguments;
- }
-
void registerRtiDependency(Element element, Element dependency) {
// We're not dealing with typedef for now.
if (!element.isClass() || !dependency.isClass()) return;
@@ -174,42 +168,45 @@
TypeChecks cachedRequiredChecks;
TypeChecks get requiredChecks {
+ if (cachedRequiredChecks == null) {
+ computeRequiredChecks();
+ }
assert(cachedRequiredChecks != null);
return cachedRequiredChecks;
}
- void computeRequiredChecks() {
- // Get all types used in type arguments of instantiated types.
- Set<ClassElement> instantiatedArguments =
- getInstantiatedArguments(compiler.codegenWorld);
-
- // Collect all type arguments used in is-checks.
- Set<ClassElement> checkedArguments =
- getCheckedArguments(compiler.codegenWorld);
-
- // Precompute the set of all seen type arguments for use in the emitter.
- cachedAllArguments = new Set<ClassElement>.from(instantiatedArguments)
- ..addAll(checkedArguments);
-
- // Finally, run through the combination of instantiated and checked
+ /// Compute the required type checkes and substitutions for the given
+ /// instantitated and checked classes.
+ TypeChecks computeChecks(Set<ClassElement> instantiated,
+ Set<ClassElement> checked) {
+ // Run through the combination of instantiated and checked
// arguments and record all combination where the element of a checked
// argument is a superclass of the element of an instantiated type.
- TypeCheckMapping requiredChecks = new TypeCheckMapping();
- for (ClassElement element in instantiatedArguments) {
+ TypeCheckMapping result = new TypeCheckMapping();
+ for (ClassElement element in instantiated) {
if (element == compiler.dynamicClass) continue;
- if (checkedArguments.contains(element)) {
- requiredChecks.add(element, element);
+ if (checked.contains(element)) {
+ result.add(element, element, null);
}
- // Find all supertypes of [element] in [checkedArguments] and add checks.
+ // Find all supertypes of [element] in [checkedArguments] and add checks
+ // and precompute the substitutions for them.
for (DartType supertype in element.allSupertypes) {
ClassElement superelement = supertype.element;
- if (checkedArguments.contains(superelement)) {
- requiredChecks.add(element, superelement);
+ if (checked.contains(superelement)) {
+ Substitution substitution =
+ computeSubstitution(element, superelement);
+ result.add(element, superelement, substitution);
}
}
}
+ return result;
+ }
- cachedRequiredChecks = requiredChecks;
+ void computeRequiredChecks() {
+ computeInstantiatedArguments(compiler.codegenWorld);
+ computeCheckedArguments(compiler.codegenWorld);
+ cachedRequiredChecks =
+ computeChecks(allInstantiatedArguments, checkedArguments);
}
/**
@@ -219,30 +216,58 @@
* have a type check against this supertype that includes a check against
* the type arguments.
*/
- Set<ClassElement> getInstantiatedArguments(Universe universe) {
- ArgumentCollector collector = new ArgumentCollector(backend);
+ void computeInstantiatedArguments(Universe universe) {
+ ArgumentCollector superCollector = new ArgumentCollector(backend);
+ ArgumentCollector directCollector = new ArgumentCollector(backend);
for (DartType type in universe.instantiatedTypes) {
- collector.collect(type);
+ directCollector.collect(type);
ClassElement cls = type.element;
for (DartType supertype in cls.allSupertypes) {
- collector.collect(supertype);
+ superCollector.collect(supertype);
}
}
- for (ClassElement cls in collector.classes.toList()) {
+ for (ClassElement cls in superCollector.classes.toList()) {
for (DartType supertype in cls.allSupertypes) {
- collector.collect(supertype);
+ superCollector.collect(supertype);
}
}
- return collector.classes;
+ directlyInstantiatedArguments = directCollector.classes;
+ allInstantiatedArguments =
+ superCollector.classes..addAll(directlyInstantiatedArguments);
}
/// Collects all type arguments used in is-checks.
- Set<ClassElement> getCheckedArguments(Universe universe) {
+ void computeCheckedArguments(Universe universe) {
ArgumentCollector collector = new ArgumentCollector(backend);
for (DartType type in universe.isChecks) {
collector.collect(type);
}
- return collector.classes;
+ checkedArguments = collector.classes;
+ }
+
+ Set<ClassElement> getClassesUsedInSubstitutions(JavaScriptBackend backend,
+ TypeChecks checks) {
+ Set<ClassElement> instantiated = new Set<ClassElement>();
+ ArgumentCollector collector = new ArgumentCollector(backend);
+ for (ClassElement target in checks) {
+ instantiated.add(target);
+ for (TypeCheck check in checks[target]) {
+ Substitution substitution = check.substitution;
+ if (substitution != null) {
+ collector.collectAll(substitution.arguments);
+ }
+ }
+ }
+ return instantiated..addAll(collector.classes);
+ }
+
+ Set<ClassElement> getRequiredArgumentClasses(JavaScriptBackend backend) {
+ Set<ClassElement> requiredArgumentClasses =
+ new Set<ClassElement>.from(
+ getClassesUsedInSubstitutions(backend, requiredChecks));
+ return requiredArgumentClasses
+ ..addAll(directlyInstantiatedArguments)
+ ..addAll(checkedArguments);
}
/// Return the unique name for the element as an unquoted string.
@@ -314,9 +339,30 @@
*/
String getSupertypeSubstitution(ClassElement cls, ClassElement check,
{bool alwaysGenerateFunction: false}) {
+ Substitution substitution = getSubstitution(cls, check);
+ if (substitution != null) {
+ return substitution.getCode(this, alwaysGenerateFunction);
+ } else {
+ return null;
+ }
+ }
+
+ Substitution getSubstitution(ClassElement cls, ClassElement other) {
+ // Look for a precomputed check.
+ for (TypeCheck check in cachedRequiredChecks[cls]) {
+ if (check.cls == other) {
+ return check.substitution;
+ }
+ }
+ // There is no precomputed check for this pair (because the check is not
+ // done on type arguments only. Compute a new substitution.
+ return computeSubstitution(cls, other);
+ }
+
+ Substitution computeSubstitution(ClassElement cls, ClassElement check,
+ { bool alwaysGenerateFunction: false }) {
if (isTrivialSubstitution(cls, check)) return null;
- // TODO(karlklose): maybe precompute this value and store it in typeChecks?
bool usesTypeVariables = false;
String onVariable(TypeVariableType v) {
usesTypeVariables = true;
@@ -324,18 +370,21 @@
};
InterfaceType type = cls.computeType(compiler);
InterfaceType target = type.asInstanceOf(check);
- String substitution = target.typeArguments.toList()
- .map((type) => _getTypeRepresentation(type, onVariable))
- .join(', ');
- substitution = '[$substitution]';
- if (!usesTypeVariables && !alwaysGenerateFunction) {
- return substitution;
+ if (cls.typeVariables.isEmpty && !alwaysGenerateFunction) {
+ return new Substitution.list(target.typeArguments);
} else {
- String parameters = cls.typeVariables.toList().join(', ');
- return 'function ($parameters) { return $substitution; }';
+ return new Substitution.function(target.typeArguments, cls.typeVariables);
}
}
+ String getSubstitutionRepresentation(Link<DartType> types,
+ VariableSubstitution variableName) {
+ String code = types.toList(growable: false)
+ .map((type) => _getTypeRepresentation(type, variableName))
+ .join(', ');
+ return '[$code]';
+ }
+
String getTypeRepresentation(DartType type, void onVariable(variable)) {
// Create a type representation. For type variables call the original
// callback for side effects and return a template placeholder.
@@ -346,7 +395,8 @@
}
// TODO(karlklose): rewrite to use js.Expressions.
- String _getTypeRepresentation(DartType type, String onVariable(variable)) {
+ String _getTypeRepresentation(DartType type,
+ VariableSubstitution onVariable) {
return representationGenerator.getTypeRepresentation(type, onVariable);
}
@@ -477,18 +527,19 @@
}
}
-class TypeCheckMapping implements TypeChecks {
- final Map<ClassElement, Set<ClassElement>> map =
- new Map<ClassElement, Set<ClassElement>>();
- Iterable<ClassElement> operator[](ClassElement element) {
- Set<ClassElement> result = map[element];
- return result != null ? result : const <ClassElement>[];
+class TypeCheckMapping implements TypeChecks {
+ final Map<ClassElement, Set<TypeCheck>> map =
+ new Map<ClassElement, Set<TypeCheck>>();
+
+ Iterable<TypeCheck> operator[](ClassElement element) {
+ Set<TypeCheck> result = map[element];
+ return result != null ? result : const <TypeCheck>[];
}
- void add(ClassElement cls, ClassElement check) {
- map.putIfAbsent(cls, () => new Set<ClassElement>());
- map[cls].add(check);
+ void add(ClassElement cls, ClassElement check, Substitution substitution) {
+ map.putIfAbsent(cls, () => new Set<TypeCheck>());
+ map[cls].add(new TypeCheck(check, substitution));
}
Iterator<ClassElement> get iterator => map.keys.iterator;
@@ -515,6 +566,14 @@
type.accept(this, false);
}
+ /// Collect all types in the list as if they were arguments of an
+ /// InterfaceType.
+ collectAll(Link<DartType> types) {
+ for (Link<DartType> link = types; !link.isEmpty; link = link.tail) {
+ link.head.accept(this, true);
+ }
+ }
+
visitType(DartType type, _) {
// Do nothing.
}
@@ -534,3 +593,52 @@
type.visitChildren(this, true);
}
}
+
+/**
+ * Representation of the substitution of type arguments
+ * when going from the type of a class to one of its supertypes.
+ *
+ * For [:class B<T> extends A<List<T>, int>:], the substitution is
+ * the representation of [: (T) => [<List, T>, int] :]. For more details
+ * of the representation consult the documentation of
+ * [getSupertypeSubstitution].
+ */
+class Substitution {
+ final bool isFunction;
+ final Link<DartType> arguments;
+ final Link<TypeVariableType> parameters;
+
+ Substitution.list(this.arguments)
+ : isFunction = false,
+ parameters = const Link<TypeVariableType>();
+
+ Substitution.function(this.arguments, this.parameters)
+ : isFunction = true;
+
+ String getCode(RuntimeTypes rti, bool ensureIsFunction) {
+ String variableName(TypeVariableType variable) {
+ return variable.name.slowToString();
+ }
+
+ String code = rti.getSubstitutionRepresentation(arguments, variableName);
+ if (isFunction) {
+ String formals = parameters.toList().map(variableName).join(', ');
+ return 'function ($formals) { return $code; }';
+ } else if (ensureIsFunction) {
+ return 'function() { return $code; }';
+ } else {
+ return code;
+ }
+ }
+}
+
+/**
+ * A pair of a class that we need a check against and the type argument
+ * substition for this check.
+ */
+class TypeCheck {
+ final ClassElement cls;
+ final Substitution substitution;
+
+ TypeCheck(this.cls, this.substitution);
+}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
index a34694a..fab0cf5 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
@@ -207,23 +207,25 @@
throw new UnsupportedError("InternetAddress.ANY_IP_V6");
}
patch static Future<List<InternetAddress>> lookup(
- String host, {InternetAddressType type: InternetAddressType.IP_V4}) {
+ String host, {InternetAddressType type: InternetAddressType.ANY}) {
throw new UnsupportedError("InternetAddress.lookup");
}
}
patch class RawServerSocket {
- patch static Future<RawServerSocket> bind([String address = "127.0.0.1",
- int port = 0,
- int backlog = 0]) {
+ patch static Future<RawServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false}) {
throw new UnsupportedError("RawServerSocket.bind");
}
}
patch class ServerSocket {
- patch static Future<ServerSocket> bind([String address = "127.0.0.1",
- int port = 0,
- int backlog = 0]) {
+ patch static Future<ServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false}) {
throw new UnsupportedError("ServerSocket.bind");
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index fbde5f9..8dcfdab 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -209,6 +209,7 @@
options.add('--analyze-only');
options.add('--analyze-signatures-only');
options.add('--analyze-all');
+ options.add('--categories=Client,Server');
bool compilationFailed = false;
void internalDiagnosticHandler(Uri uri, int begin, int end,
@@ -549,6 +550,8 @@
_members = <String, MemberMirror>{};
_library.forEachLocalMember((Element e) {
if (!e.isClass() && !e.isTypedef()) {
+ // TODO(ahe): I think it is incorrect to filter out classes
+ // and typedefs. See http://dartbug.com/10371.
for (var member in _convertElementMemberToMemberMirrors(this, e)) {
assert(!_members.containsKey(member.simpleName));
_members[member.simpleName] = member;
@@ -1682,3 +1685,54 @@
throw new UnsupportedError('InstanceMirror does not have a reflectee');
}
}
+
+_convertElementToMembers(Dart2JsLibraryMirror library, Element e) {
+ // TODO(ahe): This method creates new mirror objects which is not correct.
+ if (e.isClass()) {
+ ClassElement classElement = e;
+ classElement.ensureResolved(library.mirrors.compiler);
+ return [new Dart2JsClassMirror.fromLibrary(library, classElement)];
+ } else if (e.isTypedef()) {
+ return [new Dart2JsTypedefMirror.fromLibrary(
+ library, e.computeType(library.mirrors.compiler))];
+ } else {
+ return _convertElementMemberToMemberMirrors(library, e);
+ }
+}
+
+/**
+ * Experimental API for accessing compilation units defined in a
+ * library.
+ */
+// TODO(ahe): Superclasses? Is this really a mirror?
+class Dart2JsCompilationUnitMirror extends Dart2JsMirror {
+ final Dart2JsLibraryMirror _library;
+ final CompilationUnitElement _element;
+
+ Dart2JsCompilationUnitMirror(this._element, this._library);
+
+ Dart2JsMirrorSystem get mirrors => _library.mirrors;
+
+ List<DeclarationMirror> get members {
+ // TODO(ahe): Should return an immutable List.
+ return _element.localMembers.toList().map(
+ (m) => _convertElementToMembers(_library, m))
+ .fold([], (a, b) => a..addAll(b)).toList();
+ }
+
+ Uri get uri => _element.script.uri;
+}
+
+/**
+ * Transitional class that allows access to features that have not yet
+ * made it to the mirror API.
+ *
+ * All API in this class is experimental.
+ */
+class BackDoor {
+ /// Return the compilation units comprising [library].
+ static List<Mirror> compilationUnitsOf(Dart2JsLibraryMirror library) {
+ return library._element.compilationUnits.toList().map(
+ (cu) => new Dart2JsCompilationUnitMirror(cu, library)).toList();
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 9c521a2..27d990d 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -15,6 +15,7 @@
import 'ssa/ssa.dart';
import 'tree/tree.dart';
import 'util/util.dart';
+import 'js/js.dart' as js;
/// This class is a temporary work-around until we get a more powerful DartType.
@@ -535,9 +536,9 @@
/// [DartType]s or [SpecialType]s instantiated by the native element.
final List typesInstantiated = [];
- static final NativeBehavior NONE = new NativeBehavior();
-
- //NativeBehavior();
+ // If this behavior is for a JS expression, [codeAst] contains the
+ // parsed tree.
+ js.Expression codeAst;
static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
// The first argument of a JS-call is a string encoding various attributes
@@ -552,33 +553,38 @@
compiler.cancel("JS expression has no type", node: jsCall);
}
- var firstArg = argNodes.head;
- LiteralString specLiteral = firstArg.asLiteralString();
- if (specLiteral != null) {
- String specString = specLiteral.dartString.slowToString();
- // Various things that are not in fact types.
- if (specString == 'void') return NativeBehavior.NONE;
- if (specString == '' || specString == 'var') {
- var behavior = new NativeBehavior();
- behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
- behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
- return behavior;
- }
- var behavior = new NativeBehavior();
- for (final typeString in specString.split('|')) {
- var type = _parseType(typeString, compiler,
- (name) => resolver.resolveTypeFromString(name),
- jsCall);
- behavior.typesInstantiated.add(type);
- behavior.typesReturned.add(type);
- }
- return behavior;
+ var code = argNodes.tail.head;
+ if (code is !StringNode || code.isInterpolation) {
+ compiler.cancel('JS code must be a string literal', node: code);
}
- // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
- // is not very satisfactory because it does not work for void, dynamic.
+ LiteralString specLiteral = argNodes.head.asLiteralString();
+ if (specLiteral == null) {
+ // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
+ // is not very satisfactory because it does not work for void, dynamic.
+ compiler.cancel("Unexpected JS first argument", node: argNodes.head);
+ }
- compiler.cancel("Unexpected JS first argument", node: firstArg);
+ var behavior = new NativeBehavior();
+ behavior.codeAst = js.js.parseForeignJS(code.dartString.slowToString());
+
+ String specString = specLiteral.dartString.slowToString();
+ // Various things that are not in fact types.
+ if (specString == 'void') return behavior;
+ if (specString == '' || specString == 'var') {
+ behavior.typesReturned.add(compiler.objectClass.computeType(compiler));
+ behavior.typesReturned.add(compiler.nullClass.computeType(compiler));
+ return behavior;
+ }
+ for (final typeString in specString.split('|')) {
+ var type = _parseType(typeString, compiler,
+ (name) => resolver.resolveTypeFromString(name),
+ jsCall);
+ behavior.typesInstantiated.add(type);
+ behavior.typesReturned.add(type);
+ }
+
+ return behavior;
}
static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
@@ -911,8 +917,7 @@
element: element);
}
- DartString jsCode = new DartString.literal(nativeMethodCall);
- builder.push(new HForeign(jsCode, HType.UNKNOWN, inputs));
+ builder.push(new HForeign(js.js(nativeMethodCall), HType.UNKNOWN, inputs));
builder.close(new HReturn(builder.pop())).addSuccessor(builder.graph.exit);
} else {
if (parameters.parameterCount != 0) {
@@ -921,6 +926,8 @@
node: nativeBody);
}
LiteralString jsCode = nativeBody.asLiteralString();
- builder.push(new HForeign.statement(jsCode.dartString, <HInstruction>[]));
+ builder.push(new HForeign.statement(
+ new js.LiteralStatement(jsCode.dartString.slowToString()),
+ <HInstruction>[]));
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/byte_array_scanner.dart b/sdk/lib/_internal/compiler/implementation/scanner/byte_array_scanner.dart
index a5d801d..4cf9eeb 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/byte_array_scanner.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/byte_array_scanner.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.
+part of parser;
+
/**
* Scanner that reads from a byte array and creates tokens that points
* to the same array.
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart b/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart
index 4ae62ed..543cd6c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/byte_strings.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.
+part of parser;
+
/**
* An abstract string representation.
*/
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index 70659e0..874300b 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -47,6 +47,8 @@
relativize(cwd, resourceUri, isWindows), source);
return new Future.value(source);
}
+
+ Future<String> call(Uri resourceUri) => readStringFromUri(resourceUri);
}
class FormattingDiagnosticHandler {
@@ -61,7 +63,9 @@
final int INFO =
api.Diagnostic.INFO.ordinal | api.Diagnostic.VERBOSE_INFO.ordinal;
- FormattingDiagnosticHandler(SourceFileProvider this.provider);
+ FormattingDiagnosticHandler([SourceFileProvider provider])
+ : this.provider =
+ (provider == null) ? new SourceFileProvider() : provider;
void info(var message, [api.Diagnostic kind = api.Diagnostic.VERBOSE_INFO]) {
if (!verbose && identical(kind, api.Diagnostic.VERBOSE_INFO)) return;
@@ -116,6 +120,8 @@
throw new AbortLeg(message);
}
}
+
+ void call(Uri uri, int begin, int end, String message, api.Diagnostic kind) {
+ return diagnosticHandler(uri, begin, end, message, kind);
+ }
}
-
-
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 19525ee..b769c27 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -162,7 +162,7 @@
HInstruction createBox() {
// TODO(floitsch): Clean up this hack. Should we create a box-object by
// just creating an empty object literal?
- HInstruction box = new HForeign(const LiteralDartString("{}"),
+ HInstruction box = new HForeign(new js.ObjectInitializer([]),
HType.UNKNOWN,
<HInstruction>[]);
builder.add(box);
@@ -2518,9 +2518,8 @@
HInstruction instruction = new HStatic(element.declaration);
if (element.isGetter()) {
add(instruction);
- push(new HInvokeStatic(
- <HInstruction>[instruction],
- new HType.inferredReturnTypeForElement(element, compiler)));
+ instruction = buildInvokeStatic(<HInstruction>[instruction]);
+ push(instruction);
} else {
instruction.instructionType =
new HType.inferredTypeForElement(element, compiler);
@@ -2581,9 +2580,9 @@
if (element.isSetter()) {
HStatic target = new HStatic(element);
add(target);
- addWithPosition(
- new HInvokeStatic(<HInstruction>[target, value], HType.UNKNOWN),
- location);
+ var instruction = buildInvokeStatic(
+ <HInstruction>[target, value], HType.UNKNOWN);
+ addWithPosition(instruction, location);
} else {
value = potentiallyCheckType(value, element.computeType(compiler));
addWithPosition(new HStaticStore(element, value), location);
@@ -2612,8 +2611,7 @@
}
HInstruction invokeInterceptor(Set<ClassElement> intercepted,
- HInstruction receiver,
- Node node) {
+ HInstruction receiver) {
HInterceptor interceptor = new HInterceptor(intercepted, receiver);
add(interceptor);
return interceptor;
@@ -2623,16 +2621,14 @@
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
void pushInvokeHelper1(Element helper, HInstruction a0, HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
void pushInvokeHelper2(Element helper,
@@ -2642,8 +2638,7 @@
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
void pushInvokeHelper3(Element helper,
@@ -2654,8 +2649,7 @@
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
void pushInvokeHelper4(Element helper,
@@ -2667,8 +2661,7 @@
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
void pushInvokeHelper5(Element helper,
@@ -2681,15 +2674,14 @@
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3, a4];
- HInstruction result = new HInvokeStatic(inputs, type);
- push(result);
+ push(buildInvokeStatic(inputs, type));
}
HForeign createForeign(String code,
HType type,
List<HInstruction> inputs,
{bool isSideEffectFree: false}) {
- return new HForeign(new LiteralDartString(code),
+ return new HForeign(js.js.parseForeignJS(code),
type,
inputs,
isSideEffectFree: isSideEffectFree);
@@ -2789,7 +2781,7 @@
add(helperCall);
List<HInstruction> inputs = <HInstruction>[helperCall, expression,
runtimeType];
- HInstruction call = new HInvokeStatic(inputs, HType.BOOLEAN);
+ HInstruction call = buildInvokeStatic(inputs, HType.BOOLEAN);
add(call);
instruction = new HIs(type, <HInstruction>[expression, call],
HIs.VARIABLE_CHECK);
@@ -2813,7 +2805,7 @@
isFieldName,
representations,
asFieldName];
- HInstruction call = new HInvokeStatic(inputs, HType.BOOLEAN);
+ HInstruction call = buildInvokeStatic(inputs, HType.BOOLEAN);
add(call);
instruction = new HIs(type, <HInstruction>[expression, call],
HIs.COMPOUND_CHECK);
@@ -2992,23 +2984,15 @@
compiler.cancel('At least two arguments expected',
node: node.argumentsNode);
}
- List<HInstruction> inputs = <HInstruction>[];
- Node type = link.head;
- Node code = link.tail.head;
- addGenericSendArgumentsToList(link.tail.tail, inputs);
-
native.NativeBehavior nativeBehavior =
compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+
+ List<HInstruction> inputs = <HInstruction>[];
+ addGenericSendArgumentsToList(link.tail.tail, inputs);
+
HType ssaType = new HType.fromNativeBehavior(nativeBehavior, compiler);
- if (code is StringNode) {
- StringNode codeString = code;
- if (!codeString.isInterpolation) {
- // codeString may not be an interpolation, but may be a juxtaposition.
- push(new HForeign(codeString.dartString, ssaType, inputs));
- return;
- }
- }
- compiler.cancel('JS code must be a string literal', node: code);
+ push(new HForeign(nativeBehavior.codeAst, ssaType, inputs));
+ return;
}
void handleForeignJsCurrentIsolate(Send node) {
@@ -3019,9 +3003,9 @@
if (!compiler.hasIsolateSupport()) {
// If the isolate library is not used, we just generate code
- // to fetch the Leg's current isolate.
+ // to fetch the current isolate.
String name = backend.namer.CURRENT_ISOLATE;
- push(new HForeign(new DartString.literal(name),
+ push(new HForeign(new js.LiteralString(name),
HType.UNKNOWN,
<HInstruction>[]));
} else {
@@ -3058,7 +3042,7 @@
add(target);
List<HInstruction> inputs = <HInstruction>[target];
addGenericSendArgumentsToList(link, inputs);
- push(new HInvokeStatic(inputs, HType.UNKNOWN));
+ push(buildInvokeStatic(inputs, HType.UNKNOWN));
}
}
@@ -3094,7 +3078,7 @@
List<HInstruction> inputs = <HInstruction>[pop()];
String invocationName = backend.namer.invocationName(
new Selector.callClosure(params.requiredParameterCount));
- push(new HForeign(new DartString.literal('#.$invocationName'),
+ push(new HForeign(js.js('#.$invocationName'),
HType.UNKNOWN,
inputs));
}
@@ -3106,7 +3090,7 @@
}
visit(node.arguments.head);
String isolateName = backend.namer.CURRENT_ISOLATE;
- push(new HForeign(new DartString.literal("$isolateName = #"),
+ push(new HForeign(js.js("$isolateName = #"),
HType.UNKNOWN,
<HInstruction>[pop()]));
}
@@ -3117,7 +3101,7 @@
node: node.argumentsNode);
}
String constructorName = backend.namer.isolateName;
- push(new HForeign(new DartString.literal("new $constructorName()"),
+ push(new HForeign(js.js("new $constructorName()"),
HType.UNKNOWN,
<HInstruction>[]));
}
@@ -3127,7 +3111,7 @@
compiler.cancel('Too many arguments', node: node.argumentsNode);
}
String jsClassReference = backend.namer.isolateAccess(compiler.objectClass);
- push(new HForeign(new DartString.literal(jsClassReference),
+ push(new HForeign(new js.LiteralString(jsClassReference),
HType.UNKNOWN,
<HInstruction>[]));
}
@@ -3174,9 +3158,6 @@
// [JSInvocationMirror._invokeOn].
compiler.enqueuer.codegen.registerSelectorUse(selector);
}
- HStatic target = new HStatic(element);
- add(target);
- HInstruction self = localsHandler.readThis();
Constant nameConstant = constantSystem.createString(
new DartString.literal(name.slowToString()), node);
@@ -3209,12 +3190,8 @@
argumentNamesInstruction,
HType.UNKNOWN);
- var inputs = <HInstruction>[target, self];
- if (backend.isInterceptedMethod(element)) {
- inputs.add(self);
- }
- inputs.add(pop());
- push(new HInvokeSuper(currentNonClosureClass, inputs));
+ var inputs = <HInstruction>[pop()];
+ push(buildInvokeSuper(compiler.noSuchMethodSelector, element, inputs));
}
visitSend(Send node) {
@@ -3235,13 +3212,9 @@
}
return generateSuperNoSuchMethodSend(node, selector, arguments);
}
- List<HInstruction> inputs = buildSuperAccessorInputs(element);
+ List<HInstruction> inputs = <HInstruction>[];
if (node.isPropertyAccess) {
- HInstruction invokeSuper =
- new HInvokeSuper(currentNonClosureClass, inputs);
- invokeSuper.instructionType =
- new HType.inferredTypeForElement(element, compiler);
- push(invokeSuper);
+ push(buildInvokeSuper(selector, element, inputs));
} else if (element.isFunction() || element.isGenerativeConstructor()) {
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [addStaticSendArgumentsToList].
@@ -3251,16 +3224,10 @@
if (!succeeded) {
generateWrongArgumentCountError(node, element, node.arguments);
} else {
- HInstruction invokeSuper =
- new HInvokeSuper(currentNonClosureClass, inputs);
- invokeSuper.instructionType =
- new HType.inferredReturnTypeForElement(element, compiler);
- push(invokeSuper);
+ push(buildInvokeSuper(selector, element, inputs));
}
} else {
- HInstruction target = new HInvokeSuper(currentNonClosureClass, inputs);
- target.instructionType =
- new HType.inferredTypeForElement(element, compiler);
+ HInstruction target = buildInvokeSuper(selector, element, inputs);
add(target);
inputs = <HInstruction>[target];
addDynamicSendArgumentsToList(node, inputs);
@@ -3374,7 +3341,7 @@
Element typeInfoSetterElement = backend.getSetRuntimeTypeInfo();
HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement);
add(typeInfoSetter);
- add(new HInvokeStatic(
+ add(buildInvokeStatic(
<HInstruction>[typeInfoSetter, newObject, typeInfo], HType.UNKNOWN));
}
@@ -3464,7 +3431,7 @@
compiler.enqueuer.codegen.registerFactoryWithTypeArguments(elements);
}
HType elementType = computeType(constructor);
- HInstruction newInstance = new HInvokeStatic(inputs, elementType);
+ HInstruction newInstance = buildInvokeStatic(inputs, elementType);
pushWithPosition(newInstance, node);
// The List constructor forwards to a Dart static method that does
@@ -3521,7 +3488,7 @@
return;
}
- HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
+ HInvokeStatic instruction = buildInvokeStatic(inputs, HType.UNKNOWN);
HType returnType =
new HType.inferredReturnTypeForElement(element, compiler);
if (returnType.isUnknown()) {
@@ -3532,6 +3499,7 @@
currentElement, element);
}
if (returnType != null) instruction.instructionType = returnType;
+
pushWithPosition(instruction, node);
} else {
generateGetter(node, element);
@@ -3723,7 +3691,7 @@
bool isIntercepted = interceptedClasses != null;
if (isIntercepted) {
assert(!interceptedClasses.isEmpty);
- inputs.add(invokeInterceptor(interceptedClasses, receiver, node));
+ inputs.add(invokeInterceptor(interceptedClasses, receiver));
}
inputs.addAll(arguments);
if (selector.isGetter()) {
@@ -3737,6 +3705,44 @@
}
}
+ HInstruction buildInvokeStatic(List<HInstruction> inputs,
+ [HType type = null]) {
+ HStatic staticInstruction = inputs[0];
+ Element element = staticInstruction.element;
+ if (type == null) {
+ type = new HType.inferredReturnTypeForElement(element, compiler);
+ }
+ HInstruction instruction = new HInvokeStatic(inputs, type);
+ instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
+ return instruction;
+ }
+
+ HInstruction buildInvokeSuper(Selector selector,
+ Element element,
+ List<HInstruction> arguments) {
+ HInstruction receiver = localsHandler.readThis();
+ // TODO(5346): Try to avoid the need for calling [declaration] before
+ // creating an [HStatic].
+ HInstruction target = new HStatic(element.declaration);
+ add(target);
+ List<HInstruction> inputs = <HInstruction>[target];
+ Set<ClassElement> interceptedClasses =
+ backend.getInterceptedClassesOn(selector.name);
+ if (interceptedClasses != null) {
+ inputs.add(invokeInterceptor(interceptedClasses, receiver));
+ }
+ inputs.add(receiver);
+ inputs.addAll(arguments);
+ HInstruction instruction = new HInvokeSuper(
+ currentNonClosureClass,
+ inputs,
+ isSetter: selector.isSetter() || selector.isIndexSet());
+ instruction.instructionType =
+ new HType.inferredReturnTypeForElement(element, compiler);
+ instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
+ return instruction;
+ }
+
void handleComplexOperatorSend(SendSet node,
HInstruction receiver,
Link<Node> arguments) {
@@ -3752,23 +3758,6 @@
elements.getOperatorSelectorInComplexSendSet(node), node);
}
- List<HInstruction> buildSuperAccessorInputs(Element element) {
- List<HInstruction> inputs = <HInstruction>[];
- if (Elements.isUnresolved(element)) return inputs;
- // TODO(5346): Try to avoid the need for calling [declaration] before
- // creating an [HStatic].
- HInstruction target = new HStatic(element.declaration);
- add(target);
- inputs.add(target);
- HInstruction context = localsHandler.readThis();
- inputs.add(context);
- if (backend.isInterceptedMethod(element)) {
- inputs.add(context);
- }
- return inputs;
- }
-
-
visitSendSet(SendSet node) {
Element element = elements[node];
if (!Elements.isUnresolved(element) && element.impliesType()) {
@@ -3780,13 +3769,13 @@
Operator op = node.assignmentOperator;
if (node.isSuperCall) {
HInstruction result;
- List<HInstruction> setterInputs = buildSuperAccessorInputs(element);
+ List<HInstruction> setterInputs = <HInstruction>[];
if (identical(node.assignmentOperator.source.stringValue, '=')) {
addDynamicSendArgumentsToList(node, setterInputs);
result = setterInputs.last;
} else {
Element getter = elements[node.selector];
- List<HInstruction> getterInputs = buildSuperAccessorInputs(getter);
+ List<HInstruction> getterInputs = <HInstruction>[];
Link<Node> arguments = node.arguments;
if (node.isIndex) {
// If node is of the from [:super.foo[0] += 2:], the send has
@@ -3800,15 +3789,17 @@
setterInputs.add(index);
}
HInstruction getterInstruction;
+ Selector getterSelector =
+ elements.getGetterSelectorInComplexSendSet(node);
if (Elements.isUnresolved(getter)) {
generateSuperNoSuchMethodSend(
node,
- elements.getGetterSelectorInComplexSendSet(node),
+ getterSelector,
getterInputs);
getterInstruction = pop();
} else {
- getterInstruction = new HInvokeSuper(
- currentNonClosureClass, getterInputs);
+ getterInstruction = buildInvokeSuper(
+ getterSelector, getter, getterInputs);
add(getterInstruction);
}
handleComplexOperatorSend(node, getterInstruction, arguments);
@@ -3820,13 +3811,13 @@
result = setterInputs.last;
}
}
+ Selector setterSelector = elements.getSelector(node);
if (Elements.isUnresolved(element)) {
generateSuperNoSuchMethodSend(
- node, elements.getSelector(node), setterInputs);
+ node, setterSelector, setterInputs);
pop();
} else {
- add(new HInvokeSuper(
- currentNonClosureClass, setterInputs, isSetter: true));
+ add(buildInvokeSuper(setterSelector, element, setterInputs));
}
stack.add(result);
} else if (node.isIndex) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 0f48064..924ed88 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -1693,43 +1693,35 @@
}
void registerForeignType(HType type) {
- // TODO(kasperl): This looks shaky. It makes sense if the type is
- // exact, but otherwise we should be registering more types as
- // instantiated. We should find a way of using something along the
- // lines of the NativeEnqueuerBase.processNativeBehavior method.
if (type.isUnknown()) return;
TypeMask mask = type.computeMask(compiler);
- world.registerInstantiatedClass(mask.base.element, work.resolutionTree);
+ for (ClassElement cls in mask.containedClasses(compiler)) {
+ world.registerInstantiatedClass(cls, work.resolutionTree);
+ }
}
visitForeign(HForeign node) {
- String code = node.code.slowToString();
List<HInstruction> inputs = node.inputs;
if (node.isJsStatement()) {
if (!inputs.isEmpty) {
- compiler.internalError("foreign statement with inputs: $code",
+ compiler.internalError("foreign statement with inputs",
instruction: node);
}
- pushStatement(new js.LiteralStatement(code), node);
+ pushStatement(node.codeAst, node);
} else {
- List<js.Expression> interpolatedExpressions;
if (!inputs.isEmpty) {
- interpolatedExpressions = <js.Expression>[];
+ List<js.Expression> interpolatedExpressions = <js.Expression>[];
for (int i = 0; i < inputs.length; i++) {
use(inputs[i]);
interpolatedExpressions.add(pop());
}
- }
- // We can parse simple JS with the mini parser. At the moment we can't
- // handle JSON literals and function literals, both of which contain "{".
- if (!code.contains("{") && !code.startsWith("throw ")) {
- js.Expression codeAst = js.js(code, interpolatedExpressions);
- push(codeAst, node);
+ var visitor = new js.UninterpolateJSExpression(interpolatedExpressions);
+ push(visitor.visit(node.codeAst), node);
} else {
- push(new js.LiteralExpression.withData(code, interpolatedExpressions),
- node);
+ push(node.codeAst, node);
}
}
+
registerForeignType(node.instructionType);
// TODO(sra): Tell world.nativeEnqueuer about the types created here.
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
index 209a5c0..ce3c0e3 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen_helpers.dart
@@ -58,6 +58,15 @@
// between do not prevent making it generate at use site.
input.moveBefore(user);
pureInputs.add(input);
+ // Previous computations done on [input] are now invalid
+ // because we moved [input] to another place. So all
+ // non code motion invariant instructions need
+ // to be removed from the [generateAtUseSite] set.
+ input.inputs.forEach((instruction) {
+ if (!instruction.isCodeMotionInvariant()) {
+ generateAtUseSite.remove(instruction);
+ }
+ });
// Visit the pure input now so that the expected inputs
// are after the expected inputs of [user].
input.accept(this);
@@ -160,7 +169,6 @@
}
block.last.accept(this);
- bool dontVisitPure = false;
for (HInstruction instruction = block.last.previous;
instruction != null;
instruction = instruction.previous) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index 9d78bfd..985a7a3 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -267,8 +267,8 @@
// Even if there is no builtin equivalent instruction, we know
// the instruction does not have any side effect, and that it
// can be GVN'ed.
- instruction.clearAllSideEffects();
- instruction.clearAllDependencies();
+ instruction.sideEffects.clearAllSideEffects();
+ instruction.sideEffects.clearAllDependencies();
instruction.setUseGvn();
}
return null;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 3491b3f..aa28dfd 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -754,26 +754,9 @@
HBasicBlock block;
HInstruction previous = null;
HInstruction next = null;
- int flags = 0;
- // Changes flags.
- static const int FLAG_CHANGES_INDEX = 0;
- static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1;
- static const int FLAG_CHANGES_STATIC_PROPERTY
- = FLAG_CHANGES_INSTANCE_PROPERTY + 1;
- static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_STATIC_PROPERTY + 1;
-
- // Depends flags (one for each changes flag).
- static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT;
- static const int FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE =
- FLAG_DEPENDS_ON_INDEX_STORE + 1;
- static const int FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE =
- FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE + 1;
- static const int FLAG_DEPENDS_ON_COUNT =
- FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE + 1;
-
- // Other flags.
- static const int FLAG_USE_GVN = FLAG_DEPENDS_ON_COUNT;
+ SideEffects sideEffects = new SideEffects.empty();
+ bool _useGvn = false;
// Type codes.
static const int UNDEFINED_TYPECODE = -1;
@@ -812,54 +795,8 @@
int get hashCode => id;
- bool getFlag(int position) => (flags & (1 << position)) != 0;
- void setFlag(int position) { flags |= (1 << position); }
- void clearFlag(int position) { flags &= ~(1 << position); }
-
- static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT;
-
- int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
- int getDependsOnFlags() {
- return (flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT;
- }
-
- bool hasSideEffects() => getChangesFlags() != 0;
- bool dependsOnSomething() => getDependsOnFlags() != 0;
-
- void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
- void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
-
- void setDependsOnSomething() {
- int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
- flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT);
- }
- void clearAllDependencies() {
- int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
- flags &= ~(((1 << count) - 1) << FLAG_CHANGES_COUNT);
- }
-
- bool dependsOnStaticPropertyStore() {
- return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
- }
- void setDependsOnStaticPropertyStore() {
- setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
- }
- void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); }
-
- bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE);
- void setDependsOnIndexStore() { setFlag(FLAG_DEPENDS_ON_INDEX_STORE); }
- void setChangesIndex() { setFlag(FLAG_CHANGES_INDEX); }
-
- bool dependsOnInstancePropertyStore() {
- return getFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
- }
- void setDependsOnInstancePropertyStore() {
- setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
- }
- void setChangesInstanceProperty() { setFlag(FLAG_CHANGES_INSTANCE_PROPERTY); }
-
- bool useGvn() => getFlag(FLAG_USE_GVN);
- void setUseGvn() { setFlag(FLAG_USE_GVN); }
+ bool useGvn() => _useGvn;
+ void setUseGvn() { _useGvn = true; }
void updateInput(int i, HInstruction insn) {
inputs[i] = insn;
@@ -870,7 +807,11 @@
* effect, nor any dependency. They can be moved anywhere in the
* graph.
*/
- bool isPure() => !hasSideEffects() && !dependsOnSomething() && !canThrow();
+ bool isPure() {
+ return !sideEffects.hasSideEffects()
+ && !sideEffects.dependsOnSomething()
+ && !canThrow();
+ }
// Can this node throw an exception?
bool canThrow() => false;
@@ -932,11 +873,11 @@
bool gvnEquals(HInstruction other) {
assert(useGvn() && other.useGvn());
- // Check that the type and the flags match.
+ // Check that the type and the sideEffects match.
bool hasSameType = typeEquals(other);
assert(hasSameType == (typeCode() == other.typeCode()));
if (!hasSameType) return false;
- if (flags != other.flags) return false;
+ if (sideEffects != other.sideEffects) return false;
// Check that the inputs match.
final int inputsLength = inputs.length;
final List<HInstruction> otherInputs = other.inputs;
@@ -1162,7 +1103,6 @@
class HBoolify extends HInstruction {
HBoolify(HInstruction value) : super(<HInstruction>[value]) {
- assert(!hasSideEffects());
setUseGvn();
instructionType = HType.BOOLEAN;
}
@@ -1182,7 +1122,6 @@
*/
abstract class HCheck extends HInstruction {
HCheck(inputs) : super(inputs) {
- assert(!hasSideEffects());
setUseGvn();
}
HInstruction get checkedInput => inputs[0];
@@ -1198,7 +1137,6 @@
// bailout function.
List<int> padding;
HBailoutTarget(this.state) : super(<HInstruction>[]) {
- assert(!hasSideEffects());
setUseGvn();
}
@@ -1299,8 +1237,8 @@
* to the invocation.
*/
HInvoke(List<HInstruction> inputs) : super(inputs) {
- setAllSideEffects();
- setDependsOnSomething();
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
}
static const int ARGUMENTS_OFFSET = 1;
bool canThrow() => true;
@@ -1387,13 +1325,13 @@
class HInvokeDynamicGetter extends HInvokeDynamicField {
HInvokeDynamicGetter(selector, element, inputs, isSideEffectFree)
: super(selector, element, inputs, isSideEffectFree) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
if (isSideEffectFree) {
setUseGvn();
- setDependsOnInstancePropertyStore();
+ sideEffects.setDependsOnInstancePropertyStore();
} else {
- setDependsOnSomething();
- setAllSideEffects();
+ sideEffects.setDependsOnSomething();
+ sideEffects.setAllSideEffects();
}
}
toString() => 'invoke dynamic getter: $selector';
@@ -1403,12 +1341,12 @@
class HInvokeDynamicSetter extends HInvokeDynamicField {
HInvokeDynamicSetter(selector, element, inputs, isSideEffectFree)
: super(selector, element, inputs, isSideEffectFree) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
if (isSideEffectFree) {
- setChangesInstanceProperty();
+ sideEffects.setChangesInstanceProperty();
} else {
- setAllSideEffects();
- setDependsOnSomething();
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
}
}
toString() => 'invoke dynamic setter: $selector';
@@ -1433,7 +1371,7 @@
final ClassElement caller;
final bool isSetter;
- HInvokeSuper(this.caller, inputs, {this.isSetter: false})
+ HInvokeSuper(this.caller, inputs, {this.isSetter})
: super(inputs, HType.UNKNOWN);
toString() => 'invoke super: ${element.name}';
accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
@@ -1462,10 +1400,10 @@
? isAssignable
: element.isAssignable(),
super(element, <HInstruction>[receiver]) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
setUseGvn();
if (this.isAssignable) {
- setDependsOnInstancePropertyStore();
+ sideEffects.setDependsOnInstancePropertyStore();
}
}
@@ -1495,8 +1433,8 @@
HInstruction receiver,
HInstruction value)
: super(element, <HInstruction>[receiver, value]) {
- clearAllSideEffects();
- setChangesInstanceProperty();
+ sideEffects.clearAllSideEffects();
+ sideEffects.setChangesInstanceProperty();
}
bool canThrow() => receiver.canBeNull();
@@ -1531,25 +1469,25 @@
}
class HForeign extends HInstruction {
- final DartString code;
+ final js.Node codeAst;
final bool isStatement;
final bool isSideEffectFree;
- HForeign(this.code,
+ HForeign(this.codeAst,
HType type,
List<HInstruction> inputs,
{this.isStatement: false,
this.isSideEffectFree: false})
: super(inputs) {
if (!isSideEffectFree) {
- setAllSideEffects();
- setDependsOnSomething();
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
}
instructionType = type;
}
- HForeign.statement(code, List<HInstruction> inputs)
- : this(code, HType.UNKNOWN, inputs, isStatement: true);
+ HForeign.statement(codeAst, List<HInstruction> inputs)
+ : this(codeAst, HType.UNKNOWN, inputs, isStatement: true);
accept(HVisitor visitor) => visitor.visitForeign(this);
@@ -1560,7 +1498,7 @@
class HForeignNew extends HForeign {
ClassElement element;
HForeignNew(this.element, HType type, List<HInstruction> inputs)
- : super(const LiteralDartString("new"), type, inputs);
+ : super(null, type, inputs);
accept(HVisitor visitor) => visitor.visitForeignNew(this);
}
@@ -1568,7 +1506,7 @@
final Selector selector;
HInvokeBinary(HInstruction left, HInstruction right, this.selector)
: super(<HInstruction>[left, right]) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
setUseGvn();
}
@@ -1706,7 +1644,7 @@
final Selector selector;
HInvokeUnary(HInstruction input, this.selector)
: super(<HInstruction>[input]) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
setUseGvn();
}
@@ -2046,9 +1984,9 @@
HStatic(this.element) : super(<HInstruction>[]) {
assert(element != null);
assert(invariant(this, element.isDeclaration));
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
if (element.isAssignable()) {
- setDependsOnStaticPropertyStore();
+ sideEffects.setDependsOnStaticPropertyStore();
}
setUseGvn();
}
@@ -2066,7 +2004,7 @@
Set<ClassElement> interceptedClasses;
HInterceptor(this.interceptedClasses, HInstruction receiver)
: super(<HInstruction>[receiver]) {
- clearAllSideEffects();
+ sideEffects.clearAllSideEffects();
setUseGvn();
}
String toString() => 'interceptor on $interceptedClasses';
@@ -2113,8 +2051,8 @@
HLazyStatic(this.element) : super(<HInstruction>[]) {
// TODO(4931): The first access has side-effects, but we afterwards we
// should be able to GVN.
- setAllSideEffects();
- setDependsOnSomething();
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
}
toString() => 'lazy static ${element.name}';
@@ -2130,8 +2068,8 @@
Element element;
HStaticStore(this.element, HInstruction value)
: super(<HInstruction>[value]) {
- clearAllSideEffects();
- setChangesStaticProperty();
+ sideEffects.clearAllSideEffects();
+ sideEffects.setChangesStaticProperty();
}
toString() => 'static store ${element.name}';
accept(HVisitor visitor) => visitor.visitStaticStore(this);
@@ -2158,8 +2096,8 @@
final Selector selector;
HIndex(HInstruction receiver, HInstruction index, this.selector)
: super(<HInstruction>[receiver, index]) {
- clearAllSideEffects();
- setDependsOnIndexStore();
+ sideEffects.clearAllSideEffects();
+ sideEffects.setDependsOnIndexStore();
setUseGvn();
}
@@ -2185,8 +2123,8 @@
HInstruction value,
this.selector)
: super(<HInstruction>[receiver, index, value]) {
- clearAllSideEffects();
- setChangesIndex();
+ sideEffects.clearAllSideEffects();
+ sideEffects.setChangesIndex();
}
String toString() => 'index assign operator';
accept(HVisitor visitor) => visitor.visitIndexAssign(this);
@@ -2305,7 +2243,7 @@
// TODO(sra): Until Issue 9293 is fixed, this false dependency keeps the
// concats bunched with stringified inputs for much better looking code with
// fewer temps.
- setDependsOnSomething();
+ sideEffects.setDependsOnSomething();
instructionType = HType.STRING;
}
@@ -2323,8 +2261,8 @@
class HStringify extends HInstruction {
final Node node;
HStringify(HInstruction input, this.node) : super(<HInstruction>[input]) {
- setAllSideEffects();
- setDependsOnSomething();
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
instructionType = HType.STRING;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index e5d7981..98b2725 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -1003,7 +1003,7 @@
SsaDeadCodeEliminator();
bool isDeadCode(HInstruction instruction) {
- return !instruction.hasSideEffects()
+ return !instruction.sideEffects.hasSideEffects()
&& !instruction.canThrow()
&& instruction.usedBy.isEmpty
&& instruction is !HTypeGuard
@@ -1168,13 +1168,13 @@
int changesFlags) {
assert(block.parentLoopHeader == loopHeader);
HBasicBlock preheader = loopHeader.predecessors[0];
- int dependsFlags = HInstruction.computeDependsOnFlags(changesFlags);
+ int dependsFlags = SideEffects.computeDependsOnFlags(changesFlags);
HInstruction instruction = block.first;
while (instruction != null) {
HInstruction next = instruction.next;
if (instruction.useGvn()
&& (instruction is !HCheck)
- && (instruction.flags & dependsFlags) == 0) {
+ && !instruction.sideEffects.dependsOn(dependsFlags)) {
bool loopInvariantInputs = true;
List<HInstruction> inputs = instruction.inputs;
for (int i = 0, length = inputs.length; i < length; i++) {
@@ -1192,9 +1192,9 @@
}
}
int oldChangesFlags = changesFlags;
- changesFlags |= instruction.getChangesFlags();
+ changesFlags |= instruction.sideEffects.getChangesFlags();
if (oldChangesFlags != changesFlags) {
- dependsFlags = HInstruction.computeDependsOnFlags(changesFlags);
+ dependsFlags = SideEffects.computeDependsOnFlags(changesFlags);
}
instruction = next;
}
@@ -1213,7 +1213,7 @@
}
while (instruction != null) {
HInstruction next = instruction.next;
- int flags = instruction.getChangesFlags();
+ int flags = instruction.sideEffects.getChangesFlags();
assert(flags == 0 || !instruction.useGvn());
values.kill(flags);
if (instruction.useGvn()) {
@@ -1268,7 +1268,7 @@
int changesFlags = 0;
HInstruction instruction = block.first;
while (instruction != null) {
- changesFlags |= instruction.getChangesFlags();
+ changesFlags |= instruction.sideEffects.getChangesFlags();
instruction = instruction.next;
}
assert(blockChangesFlags[id] == null);
@@ -1379,8 +1379,8 @@
HInstruction instruction = block.first;
int flags = 0;
while (instruction != null) {
- int dependsFlags = HInstruction.computeDependsOnFlags(flags);
- flags |= instruction.getChangesFlags();
+ int dependsFlags = SideEffects.computeDependsOnFlags(flags);
+ flags |= instruction.sideEffects.getChangesFlags();
HInstruction current = instruction;
instruction = instruction.next;
@@ -1389,7 +1389,7 @@
// not have flags to express 'Gvn'able', but not movable.
if (current is HCheck) continue;
if (!current.useGvn()) continue;
- if ((current.flags & dependsFlags) != 0) continue;
+ if (current.sideEffects.dependsOn(dependsFlags)) continue;
bool canBeMoved = true;
for (final HInstruction input in current.inputs) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
index 13de8b6..fe79732 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/ssa.dart
@@ -8,7 +8,7 @@
import '../closure.dart';
import '../js/js.dart' as js;
-import '../dart2jslib.dart' hide Selector;
+import '../dart2jslib.dart' hide Selector, TypedSelector;
import '../dart_types.dart';
import '../source_file.dart';
import '../source_map_builder.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
index 76415a6..740d0f9 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/tracer.dart
@@ -81,8 +81,8 @@
instruction = instruction.next) {
int bci = 0;
int uses = instruction.usedBy.length;
- String changes = instruction.hasSideEffects() ? '!' : ' ';
- String depends = instruction.dependsOnSomething() ? '?' : '';
+ String changes = instruction.sideEffects.hasSideEffects() ? '!' : ' ';
+ String depends = instruction.sideEffects.dependsOnSomething() ? '?' : '';
addIndent();
String temporaryId = stringifier.temporaryId(instruction);
String instructionString = stringifier.visit(instruction);
@@ -368,7 +368,7 @@
}
String visitForeign(HForeign foreign) {
- return visitGenericInvoke("Foreign", "${foreign.code}", foreign.inputs);
+ return visitGenericInvoke("Foreign", "${foreign.codeAst}", foreign.inputs);
}
String visitForeignNew(HForeignNew node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index da6ad83..20a0b64 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -18,43 +18,37 @@
return isNullable ? HType.NULL : HType.CONFLICTING;
}
- Element element = mask.base.element;
- JavaScriptBackend backend = compiler.backend;
- if (element == compiler.intClass || element == backend.jsIntClass) {
+ if (mask.containsOnlyInt(compiler)) {
return isNullable ? HType.INTEGER_OR_NULL : HType.INTEGER;
- } else if (element == compiler.numClass
- || element == backend.jsNumberClass) {
- return isNullable ? HType.NUMBER_OR_NULL : HType.NUMBER;
- } else if (element == compiler.doubleClass
- || element == backend.jsDoubleClass) {
+ } else if (mask.containsOnlyDouble(compiler)) {
return isNullable ? HType.DOUBLE_OR_NULL : HType.DOUBLE;
- } else if (element == compiler.stringClass
- || element == backend.jsStringClass) {
+ } else if (mask.containsOnlyNum(compiler)) {
+ return isNullable ? HType.NUMBER_OR_NULL : HType.NUMBER;
+ } else if (mask.containsOnlyString(compiler)) {
return isNullable ? HType.STRING_OR_NULL : HType.STRING;
- } else if (element == compiler.boolClass
- || element == backend.jsBoolClass) {
+ } else if (mask.containsOnlyBool(compiler)) {
return isNullable ? HType.BOOLEAN_OR_NULL : HType.BOOLEAN;
- } else if (element == compiler.nullClass
- || element == backend.jsNullClass) {
+ } else if (mask.containsOnlyNull(compiler)) {
return HType.NULL;
}
// TODO(kasperl): A lot of the code in the system currently
// expects the top type to be 'unknown'. I'll rework this.
- if (element == compiler.objectClass || element == compiler.dynamicClass) {
+ if (mask.containsAll(compiler)) {
return isNullable ? HType.UNKNOWN : HType.NON_NULL;
}
+ JavaScriptBackend backend = compiler.backend;
if (!isNullable) {
- if (element == backend.jsIndexableClass) {
+ if (mask.containsOnly(backend.jsIndexableClass)) {
return HType.INDEXABLE_PRIMITIVE;
- } else if (element == backend.jsArrayClass) {
+ } else if (mask.containsOnly(backend.jsArrayClass)) {
return HType.READABLE_ARRAY;
- } else if (element == backend.jsMutableArrayClass) {
+ } else if (mask.containsOnly(backend.jsMutableArrayClass)) {
return HType.MUTABLE_ARRAY;
- } else if (element == backend.jsFixedArrayClass) {
+ } else if (mask.containsOnly(backend.jsFixedArrayClass)) {
return HType.FIXED_ARRAY;
- } else if (element == backend.jsExtendableArrayClass) {
+ } else if (mask.containsOnly(backend.jsExtendableArrayClass)) {
return HType.EXTENDABLE_ARRAY;
}
}
@@ -144,6 +138,8 @@
return HType.NULL;
} else if (type.element == compiler.nullClass) {
return HType.NULL;
+ } else if (type.isDynamic) {
+ return HType.UNKNOWN;
} else if (compiler.world.hasAnySubtype(type.element)) {
return new HType.nonNullSubtype(type, compiler);
} else if (compiler.world.hasAnySubclass(type.element)) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index eced1c4..5e1eb2a 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -129,6 +129,14 @@
HType receiverType = instruction.getDartReceiver(compiler).instructionType;
Selector refined = receiverType.refine(instruction.selector, compiler);
HType type = new HType.inferredTypeForSelector(refined, compiler);
+ // TODO(ngeoffray): Because we don't know yet the side effects of
+ // a JS call, we sometimes know more in the compiler about the
+ // side effects of an element (for example operator% on the int
+ // class). We should remove this check once we analyze JS calls.
+ if (!instruction.useGvn()) {
+ instruction.sideEffects =
+ compiler.world.getSideEffectsOfSelector(refined);
+ }
if (type.isUseful()) return type;
return instruction.specializer.computeTypeFromInputTypes(
instruction, compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index eae106e..092a99c 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -692,7 +692,6 @@
// narrows it. Use that new range for this instruction as well.
Range newIndexRange = indexRange.intersection(
info.newNormalizedRange(info.intZero, maxIndex));
- return newIndexRange;
if (indexRange == newIndexRange) return indexRange;
// Explicitly attach the range information to the index instruction,
// which may be used by other instructions. Returning the new range will
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart
index b68e688..07681b6 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_set.dart
@@ -50,11 +50,11 @@
void kill(int flags) {
if (flags == 0) return;
- int depends = HInstruction.computeDependsOnFlags(flags);
+ int depends = SideEffects.computeDependsOnFlags(flags);
// Kill in the hash table.
for (int index = 0, length = table.length; index < length; index++) {
HInstruction instruction = table[index];
- if (instruction != null && (instruction.flags & depends) != 0) {
+ if (instruction != null && instruction.sideEffects.dependsOn(depends)) {
table[index] = null;
size--;
}
@@ -65,7 +65,7 @@
while (current != null) {
ValueSetNode next = current.next;
HInstruction cached = current.value;
- if ((cached.flags & depends) != 0) {
+ if (cached.sideEffects.dependsOn(depends)) {
if (previous == null) {
collisions = next;
} else {
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 b346692..68e22f1 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -833,6 +833,8 @@
if (element != null) {
if (element == compiler.numClass) {
return new TypeMask.nonNullSubclass(compiler.numClass.rawType);
+ } else if (element == compiler.dynamicClass) {
+ return new TypeMask.nonNullSubclass(compiler.objectClass.rawType);
} else {
return new TypeMask.nonNullExact(element.rawType);
}
@@ -939,7 +941,7 @@
}
if (selector != null && receiverType != null) {
- TypeMask receiverMask = new TypeMask.exact(receiverType.rawType);
+ TypeMask receiverMask = new TypeMask.nonNullExact(receiverType.rawType);
TypeMask resultMask = concreteTypeToTypeMask(result);
augmentInferredSelectorType(selector, receiverMask, resultMask);
}
@@ -2035,6 +2037,8 @@
return returnType.isEmpty()
? returnType
: inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType);
+ } else if (name.stringValue == '&&' || name.stringValue == '||'){
+ return inferrer.singletonConcreteType(inferrer.baseTypes.boolBaseType);
} else {
return analyzeDynamicSend(elements.getSelector(node),
receiverType, name, argumentsTypes);
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index d4fdd13..39fecf2 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -12,13 +12,13 @@
import '../native_handler.dart' as native;
import '../tree/tree.dart';
import '../util/util.dart' show Link;
-import 'types.dart' show TypesInferrer, TypeMask;
+import 'types.dart' show TypesInferrer, FlatTypeMask, TypeMask;
// BUG(8802): There's a bug in the analyzer that makes the re-export
// of Selector from dart2jslib.dart fail. For now, we work around that
// by importing universe.dart explicitly and disabling the re-export.
-import '../dart2jslib.dart' hide Selector;
-import '../universe/universe.dart' show Selector, TypedSelector;
+import '../dart2jslib.dart' hide Selector, TypedSelector;
+import '../universe/universe.dart' show Selector, SideEffects, TypedSelector;
/**
* A work queue that ensures there are no duplicates, and adds and
@@ -100,7 +100,7 @@
* A sentinel type mask class used by the inferrer for the give up
* type, and the dynamic type.
*/
-class SentinelTypeMask extends TypeMask {
+class SentinelTypeMask extends FlatTypeMask {
final String name;
SentinelTypeMask(this.name) : super(null, 0, false);
@@ -261,7 +261,7 @@
* Sentinel used by the inferrer to notify that it does not know
* the type of a specific element.
*/
- final TypeMask dynamicType = new SentinelTypeMask('dynamic');
+ TypeMask dynamicType = new SentinelTypeMask('dynamic');
bool isDynamicType(TypeMask type) => identical(type, dynamicType);
TypeMask nullType;
@@ -712,6 +712,8 @@
mappedType = nullType;
} else if (type.isVoid) {
mappedType = nullType;
+ } else if (type.isDynamic) {
+ return dynamicType;
} else if (compiler.world.hasAnySubclass(type.element)) {
mappedType = new TypeMask.nonNullSubclass(rawTypeOf(type.element));
} else if (compiler.world.hasAnySubtype(type.element)) {
@@ -817,6 +819,31 @@
return existing != arguments;
}
+ void updateSideEffects(SideEffects sideEffects,
+ Selector selector,
+ Element callee) {
+ if (callee.isField()) {
+ if (callee.isInstanceMember()) {
+ if (selector.isSetter()) {
+ sideEffects.setChangesInstanceProperty();
+ } else if (selector.isGetter()) {
+ sideEffects.setDependsOnInstancePropertyStore();
+ }
+ } else {
+ if (selector.isSetter()) {
+ sideEffects.setChangesStaticProperty();
+ } else if (selector.isGetter()) {
+ sideEffects.setDependsOnStaticPropertyStore();
+ }
+ }
+ } else if (callee.isGetter() && !selector.isGetter()) {
+ sideEffects.setAllSideEffects();
+ sideEffects.setDependsOnSomething();
+ } else {
+ sideEffects.add(compiler.world.getSideEffectsOfElement(callee));
+ }
+ }
+
/**
* Registers that [caller] calls [callee] with the given
* [arguments]. [constraint] is a setter constraint (see
@@ -828,6 +855,7 @@
Element callee,
ArgumentsTypes arguments,
Selector constraint,
+ SideEffects sideEffects,
bool inLoop) {
// Bailout for closure calls. We're not tracking types of
// arguments for closures.
@@ -847,6 +875,7 @@
}
}
+ updateSideEffects(sideEffects, selector, callee);
assert(isNotClosure(caller));
callee = callee.implementation;
if (!analyzeCount.containsKey(caller)) {
@@ -1011,6 +1040,7 @@
Element caller,
ArgumentsTypes arguments,
Selector constraint,
+ SideEffects sideEffects,
bool inLoop) {
TypeMask result;
iterateOverElements(selector.asUntyped, (Element element) {
@@ -1018,7 +1048,7 @@
if (isTargetFor(receiverType, selector, element)) {
registerCalledElement(
node, selector, caller, element, arguments,
- constraint, inLoop);
+ constraint, sideEffects, inLoop);
if (!selector.isSetter()) {
TypeMask type = handleIntrisifiedSelector(selector, arguments);
@@ -1378,6 +1408,7 @@
bool visitingInitializers = false;
bool isConstructorRedirect = false;
int loopLevel = 0;
+ SideEffects sideEffects = new SideEffects.empty();
bool get inLoop => loopLevel > 0;
bool get isThisExposed => locals.isThisExposed;
@@ -1528,6 +1559,7 @@
});
// TODO(ngeoffray): Re-analyze method if [changed]?
}
+ compiler.world.registerSideEffects(analyzedElement, sideEffects);
return returnType;
}
@@ -1936,6 +1968,8 @@
}
TypeMask handleForeignSend(Send node) {
+ // TODO(ngeoffray): Analyze JS expressions.
+ sideEffects.setAllSideEffects();
node.visitChildren(this);
Selector selector = elements.getSelector(node);
SourceString name = selector.name;
@@ -2053,7 +2087,8 @@
ArgumentsTypes arguments) {
if (Elements.isUnresolved(element)) return;
inferrer.registerCalledElement(
- node, selector, outermostElement, element, arguments, null, inLoop);
+ node, selector, outermostElement, element, arguments, null,
+ sideEffects, inLoop);
}
void updateSelectorInTree(Node node, Selector selector) {
@@ -2085,7 +2120,7 @@
}
return inferrer.registerCalledSelector(
node, selector, receiver, outermostElement, arguments,
- constraint, inLoop);
+ constraint, sideEffects, inLoop);
}
TypeMask visitDynamicSend(Send node) {
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 8e7843d..df459be 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -4,12 +4,104 @@
part of types;
+abstract class TypeMask {
+ factory TypeMask(DartType base, int kind, bool isNullable)
+ => new FlatTypeMask(base, kind, isNullable);
+
+ factory TypeMask.empty() => new FlatTypeMask.empty();
+
+ factory TypeMask.exact(DartType base) => new FlatTypeMask.exact(base);
+ factory TypeMask.subclass(DartType base) => new FlatTypeMask.subclass(base);
+ factory TypeMask.subtype(DartType base) => new FlatTypeMask.subtype(base);
+
+ factory TypeMask.nonNullEmpty()
+ => new FlatTypeMask.nonNullEmpty();
+ factory TypeMask.nonNullExact(DartType base)
+ => new FlatTypeMask.nonNullExact(base);
+ factory TypeMask.nonNullSubclass(DartType base)
+ => new FlatTypeMask.nonNullSubclass(base);
+ factory TypeMask.nonNullSubtype(DartType base)
+ => new FlatTypeMask.nonNullSubtype(base);
+
+ /**
+ * Returns a nullable variant of [this] type mask.
+ */
+ TypeMask nullable();
+
+ /**
+ * Returns a non-nullable variant of [this] type mask.
+ */
+ TypeMask nonNullable();
+
+ bool get isEmpty;
+ bool get isNullable;
+ bool get isExact;
+
+ bool containsOnlyInt(Compiler compiler);
+ bool containsOnlyDouble(Compiler compiler);
+ bool containsOnlyNum(Compiler compiler);
+ bool containsOnlyNull(Compiler compiler);
+ bool containsOnlyBool(Compiler compiler);
+ bool containsOnlyString(Compiler compiler);
+ bool containsOnly(ClassElement element);
+
+ /**
+ * Returns whether or not this type mask contains the given type.
+ */
+ bool contains(DartType type, Compiler compiler);
+
+ /**
+ * Returns whether or not this type mask contains all types.
+ */
+ bool containsAll(Compiler compiler);
+
+ /**
+ * Returns the [ClassElement] if this type represents a single class,
+ * otherwise returns `null`. This method is conservative.
+ */
+ ClassElement singleClass(Compiler compiler);
+
+ /**
+ * Returns the set of classes this type mask can be.
+ */
+ Set<ClassElement> containedClasses(Compiler compiler);
+
+ /**
+ * Returns a type mask representing the union of [this] and [other].
+ */
+ TypeMask union(TypeMask other, Compiler compiler);
+
+ /**
+ * Returns a type mask representing the intersection of [this] and [other].
+ */
+ TypeMask intersection(TypeMask other, Compiler compiler);
+
+ /**
+ * Returns whether a [selector] call will hit a method at runtime,
+ * and not go through [noSuchMethod].
+ */
+ bool willHit(Selector selector, Compiler compiler);
+
+ /**
+ * Returns whether [element] is a potential target when being
+ * invoked on this type mask. [selector] is used to ensure library
+ * privacy is taken into account.
+ */
+ bool canHit(Element element, Selector selector, Compiler compiler);
+
+ /**
+ * Returns the [element] that is known to always be hit at runtime
+ * on this mask. Returns null if there is none.
+ */
+ Element locateSingleElement(Selector selector, Compiler compiler);
+}
+
/**
* A type mask represents a set of contained classes, but the
* operations on it are not guaranteed to be precise and they may
* yield conservative answers that contain too many classes.
*/
-class TypeMask {
+class FlatTypeMask implements TypeMask {
static const int EMPTY = 0;
static const int EXACT = 1;
@@ -19,29 +111,31 @@
final DartType base;
final int flags;
- TypeMask(DartType base, int kind, bool isNullable)
+ FlatTypeMask(DartType base, int kind, bool isNullable)
: this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
- TypeMask.empty()
+ FlatTypeMask.empty()
: this.internal(null, (EMPTY << 1) | 1);
- TypeMask.exact(DartType base)
+ FlatTypeMask.exact(DartType base)
: this.internal(base, (EXACT << 1) | 1);
- TypeMask.subclass(DartType base)
+ FlatTypeMask.subclass(DartType base)
: this.internal(base, (SUBCLASS << 1) | 1);
- TypeMask.subtype(DartType base)
+ FlatTypeMask.subtype(DartType base)
: this.internal(base, (SUBTYPE << 1) | 1);
- TypeMask.nonNullEmpty()
+ FlatTypeMask.nonNullEmpty()
: this.internal(null, EMPTY << 1);
- TypeMask.nonNullExact(DartType base)
+ FlatTypeMask.nonNullExact(DartType base)
: this.internal(base, EXACT << 1);
- TypeMask.nonNullSubclass(DartType base)
+ FlatTypeMask.nonNullSubclass(DartType base)
: this.internal(base, SUBCLASS << 1);
- TypeMask.nonNullSubtype(DartType base)
+ FlatTypeMask.nonNullSubtype(DartType base)
: this.internal(base, SUBTYPE << 1);
- TypeMask.internal(DartType base, this.flags)
- : this.base = transformBase(base);
+ FlatTypeMask.internal(DartType base, this.flags)
+ : this.base = transformBase(base) {
+ assert(base == null || !(isExact && base.isDynamic));
+ }
// TODO(kasperl): We temporarily transform the base to be the raw
// variant of the type. Long term, we're going to keep the class
@@ -68,25 +162,14 @@
bool get isSubclass => (flags >> 1) == SUBCLASS;
bool get isSubtype => (flags >> 1) == SUBTYPE;
- DartType get exactType => isExact ? base : null;
-
- /**
- * Returns a nullable variant of [this] type mask.
- */
TypeMask nullable() {
- return isNullable ? this : new TypeMask.internal(base, flags | 1);
+ return isNullable ? this : new FlatTypeMask.internal(base, flags | 1);
}
- /**
- * Returns a non-nullable variant of [this] type mask.
- */
TypeMask nonNullable() {
- return isNullable ? new TypeMask.internal(base, flags & ~1) : this;
+ return isNullable ? new FlatTypeMask.internal(base, flags & ~1) : this;
}
- /**
- * Returns whether or not this type mask contains the given type.
- */
bool contains(DartType type, Compiler compiler) {
if (isEmpty) {
return false;
@@ -102,6 +185,40 @@
}
}
+ bool containsOnlyInt(Compiler compiler) {
+ return base.element == compiler.intClass
+ || base.element == compiler.backend.intImplementation;
+ }
+
+ bool containsOnlyDouble(Compiler compiler) {
+ return base.element == compiler.doubleClass
+ || base.element == compiler.backend.doubleImplementation;
+ }
+
+ bool containsOnlyNum(Compiler compiler) {
+ return base.element == compiler.numClass
+ || base.element == compiler.backend.numImplementation;
+ }
+
+ bool containsOnlyNull(Compiler compiler) {
+ return base.element == compiler.nullClass
+ || base.element == compiler.backend.nullImplementation;
+ }
+
+ bool containsOnlyBool(Compiler compiler) {
+ return base.element == compiler.boolClass
+ || base.element == compiler.backend.boolImplementation;
+ }
+
+ bool containsOnlyString(Compiler compiler) {
+ return base.element == compiler.stringClass
+ || base.element == compiler.backend.stringImplementation;
+ }
+
+ bool containsOnly(ClassElement cls) {
+ return base.element == cls;
+ }
+
/**
* Returns the [ClassElement] if this type represents a single class,
* otherwise returns `null`. This method is conservative.
@@ -129,7 +246,7 @@
|| identical(base.element, compiler.dynamicClass);
}
- TypeMask union(TypeMask other, Compiler compiler) {
+ TypeMask union(FlatTypeMask other, Compiler compiler) {
if (isEmpty) {
return isNullable ? other.nullable() : other;
} else if (other.isEmpty) {
@@ -149,7 +266,7 @@
}
}
- TypeMask unionSame(TypeMask other, Compiler compiler) {
+ TypeMask unionSame(FlatTypeMask other, Compiler compiler) {
assert(base == other.base);
// The two masks share the base type, so we must chose the least
// constraining kind (the highest) of the two. If either one of
@@ -162,11 +279,11 @@
} else if (other.flags == combined) {
return other;
} else {
- return new TypeMask.internal(base, combined);
+ return new FlatTypeMask.internal(base, combined);
}
}
- TypeMask unionSubclass(TypeMask other, Compiler compiler) {
+ TypeMask unionSubclass(FlatTypeMask other, Compiler compiler) {
assert(isSubclassOf(other.base, base, compiler));
int combined;
if (isExact && other.isExact) {
@@ -183,22 +300,22 @@
: other.flags | (flags & 1);
}
return (flags != combined)
- ? new TypeMask.internal(base, combined)
+ ? new FlatTypeMask.internal(base, combined)
: this;
}
- TypeMask unionSubtype(TypeMask other, Compiler compiler) {
+ TypeMask unionSubtype(FlatTypeMask other, Compiler compiler) {
assert(isSubtypeOf(other.base, base, compiler));
// Since the other mask is a subtype of this mask, we need the
// resulting union to be a subtype too. If either one of the masks
// are nullable the result should be nullable too.
int combined = (SUBTYPE << 1) | ((flags | other.flags) & 1);
return (flags != combined)
- ? new TypeMask.internal(base, combined)
+ ? new FlatTypeMask.internal(base, combined)
: this;
}
- TypeMask unionDisjoint(TypeMask other, Compiler compiler) {
+ TypeMask unionDisjoint(FlatTypeMask other, Compiler compiler) {
assert(base != other.base);
assert(!isSubtypeOf(base, other.base, compiler));
assert(!isSubtypeOf(other.base, base, compiler));
@@ -253,7 +370,7 @@
isNullable || other.isNullable);
}
- TypeMask intersection(TypeMask other, Compiler compiler) {
+ TypeMask intersection(FlatTypeMask other, Compiler compiler) {
if (isEmpty) {
return other.isNullable ? this : nonNullable();
} else if (other.isEmpty) {
@@ -273,7 +390,7 @@
}
}
- TypeMask intersectionSame(TypeMask other, Compiler compiler) {
+ TypeMask intersectionSame(FlatTypeMask other, Compiler compiler) {
assert(base == other.base);
// The two masks share the base type, so we must chose the most
// constraining kind (the lowest) of the two. Only if both masks
@@ -286,11 +403,11 @@
} else if (other.flags == combined) {
return other;
} else {
- return new TypeMask.internal(base, combined);
+ return new FlatTypeMask.internal(base, combined);
}
}
- TypeMask intersectionSubclass(TypeMask other, Compiler compiler) {
+ TypeMask intersectionSubclass(FlatTypeMask other, Compiler compiler) {
assert(isSubclassOf(other.base, base, compiler));
// If this mask isn't at least a subclass mask, then the
// intersection with the other mask is empty.
@@ -302,11 +419,11 @@
if (other.flags == combined) {
return other;
} else {
- return new TypeMask.internal(other.base, combined);
+ return new FlatTypeMask.internal(other.base, combined);
}
}
- TypeMask intersectionSubtype(TypeMask other, Compiler compiler) {
+ TypeMask intersectionSubtype(FlatTypeMask other, Compiler compiler) {
assert(isSubtypeOf(other.base, base, compiler));
// If this mask isn't a subtype mask, then the intersection with
// the other mask is empty.
@@ -318,11 +435,11 @@
if (other.flags == combined) {
return other;
} else {
- return new TypeMask.internal(other.base, combined);
+ return new FlatTypeMask.internal(other.base, combined);
}
}
- TypeMask intersectionDisjoint(TypeMask other, Compiler compiler) {
+ TypeMask intersectionDisjoint(FlatTypeMask other, Compiler compiler) {
assert(base != other.base);
assert(!isSubtypeOf(base, other.base, compiler));
assert(!isSubtypeOf(other.base, base, compiler));
@@ -358,13 +475,13 @@
int combined = (kind << 1) | (flags & other.flags & 1);
TypeMask result;
for (ClassElement each in candidates) {
- TypeMask mask = new TypeMask.internal(each.rawType, combined);
+ TypeMask mask = new FlatTypeMask.internal(each.rawType, combined);
result = (result == null) ? mask : result.union(mask, compiler);
}
return result;
}
- TypeMask intersectionEmpty(TypeMask other) {
+ TypeMask intersectionEmpty(FlatTypeMask other) {
return new TypeMask(null, EMPTY, isNullable && other.isNullable);
}
@@ -451,9 +568,13 @@
Selector selector,
Compiler compiler) {
Element element = findMatchIn(cls, selector);
- return element != null
- && !element.isAbstract(compiler)
- && selector.appliesUntyped(element, compiler);
+ if (element == null) return false;
+
+ if (element.isAbstract(compiler)) {
+ ClassElement enclosingClass = element.getEnclosingClass();
+ return hasConcreteMatch(enclosingClass.superclass, selector, compiler);
+ }
+ return selector.appliesUntyped(element, compiler);
}
/**
@@ -491,9 +612,23 @@
});
}
+ Element locateSingleElement(Selector selector, Compiler compiler) {
+ if (isEmpty) return null;
+ Iterable<Element> targets = compiler.world.allFunctions.filter(selector);
+ if (targets.length != 1) return null;
+ Element result = targets.first;
+ ClassElement enclosing = result.getEnclosingClass();
+ // We only return the found element if it is guaranteed to be
+ // implemented on the exact receiver type. It could be found in a
+ // subclass or in an inheritance-wise unrelated class in case of
+ // subtype selectors.
+ ClassElement cls = base.element;
+ return (cls.isSubclassOf(enclosing)) ? result : null;
+ }
+
bool operator ==(var other) {
- if (other is !TypeMask) return false;
- TypeMask otherMask = other;
+ if (other is !FlatTypeMask) return false;
+ FlatTypeMask otherMask = other;
return (flags == otherMask.flags) && (base == otherMask.base);
}
@@ -526,7 +661,8 @@
return (subtypes != null) ? subtypes.contains(xElement) : false;
}
- static Set<ClassElement> commonContainedClasses(TypeMask x, TypeMask y,
+ static Set<ClassElement> commonContainedClasses(FlatTypeMask x,
+ FlatTypeMask y,
Compiler compiler) {
Set<ClassElement> xSubset = x.containedClasses(compiler);
if (xSubset == null) return null;
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index cd778f6..dee04af 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -6,7 +6,7 @@
import 'dart:collection' show Queue, IterableBase;
-import '../dart2jslib.dart' hide Selector;
+import '../dart2jslib.dart' hide Selector, TypedSelector;
import '../js_backend/js_backend.dart' show JavaScriptBackend;
import '../tree/tree.dart';
import '../elements/elements.dart';
@@ -89,11 +89,14 @@
* exactness, subclassing, subtyping and nullability. The [element] parameter
* is for debugging purposes only and can be omitted.
*/
- TypeMask best(TypeMask type1, TypeMask type2, [element]) {
+ TypeMask best(var type1, var type2, [element]) {
final result = _best(type1, type2);
- similar() {
- if (type1 == null) return type2 == null;
- if (type2 == null) return false;
+ // Tests type1 and type2 for equality modulo normalization of native types.
+ // Only called when DUMP_SURPRISING_RESULTS is true.
+ bool similar() {
+ if (type1 == null || type2 == null || type1.isEmpty || type2.isEmpty) {
+ return type1 == type2;
+ }
return same(type1.base, type2.base);
}
if (DUMP_SURPRISING_RESULTS && result == type1 && !similar()) {
@@ -103,7 +106,7 @@
}
/// Helper method for [best].
- TypeMask _best(TypeMask type1, TypeMask type2) {
+ TypeMask _best(var type1, var type2) {
if (type1 == null) return type2;
if (type2 == null) return type1;
if (type1.isExact) {
diff --git a/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
new file mode 100644
index 0000000..1e27efa
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/universe/side_effects.dart
@@ -0,0 +1,108 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of universe;
+
+class SideEffects {
+ // Changes flags.
+ static const int FLAG_CHANGES_INDEX = 0;
+ static const int FLAG_CHANGES_INSTANCE_PROPERTY = FLAG_CHANGES_INDEX + 1;
+ static const int FLAG_CHANGES_STATIC_PROPERTY
+ = FLAG_CHANGES_INSTANCE_PROPERTY + 1;
+ static const int FLAG_CHANGES_COUNT = FLAG_CHANGES_STATIC_PROPERTY + 1;
+
+ // Depends flags (one for each changes flag).
+ static const int FLAG_DEPENDS_ON_INDEX_STORE = FLAG_CHANGES_COUNT;
+ static const int FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE =
+ FLAG_DEPENDS_ON_INDEX_STORE + 1;
+ static const int FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE =
+ FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE + 1;
+ static const int FLAG_DEPENDS_ON_COUNT =
+ FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE + 1;
+
+ int flags = 0;
+
+ SideEffects() {
+ setAllSideEffects();
+ setDependsOnSomething();
+ }
+
+ SideEffects.empty();
+
+ bool operator==(other) => flags == other.flags;
+
+ bool getFlag(int position) => (flags & (1 << position)) != 0;
+ void setFlag(int position) { flags |= (1 << position); }
+ void clearFlag(int position) { flags &= ~(1 << position); }
+
+ int getChangesFlags() => flags & ((1 << FLAG_CHANGES_COUNT) - 1);
+ int getDependsOnFlags() {
+ return (flags & ((1 << FLAG_DEPENDS_ON_COUNT) - 1)) >> FLAG_CHANGES_COUNT;
+ }
+
+ bool hasSideEffects() => getChangesFlags() != 0;
+ bool dependsOnSomething() => getDependsOnFlags() != 0;
+
+ void setAllSideEffects() { flags |= ((1 << FLAG_CHANGES_COUNT) - 1); }
+ bool hasAllSideEffects() {
+ return getChangesFlags() == (1 << FLAG_CHANGES_COUNT) - 1;
+ }
+ void clearAllSideEffects() { flags &= ~((1 << FLAG_CHANGES_COUNT) - 1); }
+
+ void setDependsOnSomething() {
+ int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
+ flags |= (((1 << count) - 1) << FLAG_CHANGES_COUNT);
+ }
+ void clearAllDependencies() {
+ int count = FLAG_DEPENDS_ON_COUNT - FLAG_CHANGES_COUNT;
+ flags &= ~(((1 << count) - 1) << FLAG_CHANGES_COUNT);
+ }
+
+ bool dependsOnStaticPropertyStore() {
+ return getFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
+ }
+ void setDependsOnStaticPropertyStore() {
+ setFlag(FLAG_DEPENDS_ON_STATIC_PROPERTY_STORE);
+ }
+ void setChangesStaticProperty() { setFlag(FLAG_CHANGES_STATIC_PROPERTY); }
+ bool changesStaticProperty() => getFlag(FLAG_CHANGES_STATIC_PROPERTY);
+
+ bool dependsOnIndexStore() => getFlag(FLAG_DEPENDS_ON_INDEX_STORE);
+ void setDependsOnIndexStore() { setFlag(FLAG_DEPENDS_ON_INDEX_STORE); }
+ void setChangesIndex() { setFlag(FLAG_CHANGES_INDEX); }
+ bool changesIndex() => getFlag(FLAG_CHANGES_INDEX);
+
+ bool dependsOnInstancePropertyStore() {
+ return getFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
+ }
+ void setDependsOnInstancePropertyStore() {
+ setFlag(FLAG_DEPENDS_ON_INSTANCE_PROPERTY_STORE);
+ }
+ void setChangesInstanceProperty() { setFlag(FLAG_CHANGES_INSTANCE_PROPERTY); }
+ bool changesInstanceProperty() => getFlag(FLAG_CHANGES_INSTANCE_PROPERTY);
+
+ static int computeDependsOnFlags(int flags) => flags << FLAG_CHANGES_COUNT;
+
+ bool dependsOn(int dependsFlags) => (flags & dependsFlags) != 0;
+
+ void add(SideEffects other) {
+ flags |= other.flags;
+ }
+
+ String toString() {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write('Depends on');
+ if (dependsOnIndexStore()) buffer.write(' []');
+ if (dependsOnInstancePropertyStore()) buffer.write(' field store');
+ if (dependsOnStaticPropertyStore()) buffer.write(' static store');
+ if (!dependsOnSomething()) buffer.write(' nothing');
+ buffer.write(', Changes');
+ if (changesIndex()) buffer.write(' []');
+ if (changesInstanceProperty()) buffer.write(' field');
+ if (changesStaticProperty()) buffer.write(' static');
+ if (!hasSideEffects()) buffer.write(' nothing');
+ buffer.write('.');
+ return buffer.toString();
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index b1b3cb9..ecead0f 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -16,6 +16,7 @@
part 'function_set.dart';
part 'full_function_set.dart';
part 'selector_map.dart';
+part 'side_effects.dart';
class Universe {
/**
@@ -422,8 +423,6 @@
selector.library,
selector.argumentCount,
selector.namedArguments) {
- // Invariant: Typed selector can not be based on a malformed type.
- assert(mask.isEmpty || !identical(mask.base.kind, TypeKind.MALFORMED_TYPE));
assert(asUntyped.mask == null);
}
@@ -436,7 +435,6 @@
TypedSelector.subtype(DartType base, Selector selector)
: this(new TypeMask.subtype(base), selector);
- bool get hasExactMask => mask.isExact;
bool appliesUnnamed(Element element, Compiler compiler) {
assert(sameNameHack(element, compiler));
diff --git a/sdk/lib/_internal/compiler/implementation/world.dart b/sdk/lib/_internal/compiler/implementation/world.dart
index 2ecc117..f0bd537 100644
--- a/sdk/lib/_internal/compiler/implementation/world.dart
+++ b/sdk/lib/_internal/compiler/implementation/world.dart
@@ -10,6 +10,7 @@
final Map<ClassElement, Set<ClassElement>> typesImplementedBySubclasses;
final FullFunctionSet allFunctions;
final Set<Element> functionsCalledInLoop = new Set<Element>();
+ final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>();
// We keep track of subtype and subclass relationships in four
// distinct sets to make class hierarchy analysis faster.
@@ -148,20 +149,10 @@
}
Element locateSingleElement(Selector selector) {
- Iterable<Element> targets = allFunctions.filter(selector);
- if (targets.length != 1) return null;
- Element result = targets.first;
- ClassElement enclosing = result.getEnclosingClass();
- // TODO(kasperl): Move this code to the type mask.
- ti.TypeMask mask = selector.mask;
- ClassElement receiverTypeElement = (mask == null || mask.base == null)
- ? compiler.objectClass
- : mask.base.element;
- // We only return the found element if it is guaranteed to be
- // implemented on the exact receiver type. It could be found in a
- // subclass or in an inheritance-wise unrelated class in case of
- // subtype selectors.
- return (receiverTypeElement.isSubclassOf(enclosing)) ? result : null;
+ ti.TypeMask mask = selector.mask == null
+ ? new ti.TypeMask.subclass(compiler.objectClass.rawType)
+ : selector.mask;
+ return mask.locateSingleElement(selector, compiler);
}
bool hasSingleMatch(Selector selector) {
@@ -183,10 +174,39 @@
}
void addFunctionCalledInLoop(Element element) {
- functionsCalledInLoop.add(element);
+ functionsCalledInLoop.add(element.declaration);
}
bool isCalledInLoop(Element element) {
- return functionsCalledInLoop.contains(element);
+ return functionsCalledInLoop.contains(element.declaration);
+ }
+
+ SideEffects getSideEffectsOfElement(Element element) {
+ return sideEffects.putIfAbsent(element.declaration, () {
+ return new SideEffects();
+ });
+ }
+
+ void registerSideEffects(Element element, SideEffects effects) {
+ sideEffects[element.declaration] = effects;
+ }
+
+ SideEffects getSideEffectsOfSelector(Selector selector) {
+ // We're not tracking side effects of closures.
+ if (selector.isClosureCall()) {
+ return new SideEffects();
+ }
+ SideEffects sideEffects = new SideEffects.empty();
+ for (Element e in allFunctions.filter(selector)) {
+ if (e.isField()) {
+ if (selector.isGetter()) {
+ sideEffects.setDependsOnInstancePropertyStore();
+ } else if (selector.isSetter()) {
+ sideEffects.setChangesInstanceProperty();
+ }
+ }
+ sideEffects.add(getSideEffectsOfElement(e));
+ }
+ return sideEffects;
}
}
diff --git a/sdk/lib/_internal/compiler/samples/darttags/darttags.dart b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
new file mode 100644
index 0000000..f600188
--- /dev/null
+++ b/sdk/lib/_internal/compiler/samples/darttags/darttags.dart
@@ -0,0 +1,137 @@
+// 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.
+
+// Usage: Add the following to your .gclient file (found in the parent
+// of the "dart" in a gclient checkout of the Dart repositor).
+//
+// hooks = [
+// {
+// "pattern": ".",
+// "action": [
+// "dart/sdk/bin/dart",
+// "dart/sdk/lib/_internal/compiler/samples/darttags/darttags.dart",
+// "dart/TAGS"
+// ],
+// },
+// ]
+//
+// Modify .emacs to contain:
+//
+// (setq tags-table-list
+// '("DART_LOCATION/dart"))
+//
+// Where DART_LOCATION is the gclient directory where you found .gclient.
+
+import 'dart:io';
+import 'dart:uri';
+
+// TODO(ahe): Should be dart:mirrors.
+import '../../implementation/mirrors/mirrors.dart';
+
+import '../../../libraries.dart'
+ show LIBRARIES, LibraryInfo;
+
+import '../../implementation/mirrors/dart2js_mirror.dart'
+ show analyze, BackDoor;
+
+import '../../implementation/filenames.dart';
+import '../../implementation/source_file.dart';
+import '../../implementation/source_file_provider.dart';
+import '../../implementation/util/uri_extras.dart';
+
+const DART2JS = '../../implementation/dart2js.dart';
+const DART2JS_MIRROR = '../../implementation/mirrors/dart2js_mirror.dart';
+const SDK_ROOT = '../../../../../';
+
+bool isPublicDart2jsLibrary(String name) {
+ return !name.startsWith('_') && LIBRARIES[name].isDart2jsLibrary;
+}
+
+var handler;
+RandomAccessFile output;
+Uri outputUri;
+
+main() {
+ mainWithOptions(new Options());
+}
+
+mainWithOptions(Options options) {
+ handler = new FormattingDiagnosticHandler()
+ ..throwOnError = true;
+
+ outputUri =
+ handler.provider.cwd.resolve(nativeToUriPath(options.arguments.first));
+ output = new File(options.arguments.first).openSync(mode: FileMode.WRITE);
+
+ Uri myLocation =
+ handler.provider.cwd.resolve(nativeToUriPath(options.script));
+
+ // Get the names of public dart2js libraries.
+ Iterable<String> names = LIBRARIES.keys.where(isPublicDart2jsLibrary);
+
+ // Prepend "dart:" to the names.
+ List<Uri> uris = names.map((String name) => Uri.parse('dart:$name')).toList();
+
+ // Append dart2js itself.
+ uris.add(myLocation.resolve(DART2JS));
+ uris.add(myLocation.resolve(DART2JS_MIRROR));
+
+ analyze(uris, myLocation.resolve(SDK_ROOT), null, handler.provider, handler)
+ .then(processMirrors);
+}
+
+processMirrors(MirrorSystem mirrors) {
+ mirrors.libraries.forEach((_, LibraryMirror library) {
+ BackDoor.compilationUnitsOf(library).forEach(emitTagsForCompilationUnit);
+ });
+
+ output.closeSync();
+}
+
+/**
+ * From http://en.wikipedia.org/wiki/Ctags#Etags_2
+ *
+ * A section starts with a two line header, one line containing a
+ * single <\x0c> character, followed by a line which consists of:
+ *
+ * {src_file},{size_of_tag_definition_data_in_bytes}
+ *
+ * The header is followed by tag definitions, one definition per line,
+ * with the format:
+ *
+ * {tag_definition_text}<\x7f>{tagname}<\x01>{line_number},{byte_offset}
+ */
+emitTagsForCompilationUnit(compilationUnit) {
+ // Certain variables in this method do not follow Dart naming
+ // conventions. This is because the format as written on Wikipedia
+ // looks very similar to Dart string interpolation that the author
+ // felt it would make sense to keep the names.
+ Uri uri = compilationUnit.uri;
+ var buffer = new StringBuffer();
+ SourceFile file = handler.provider.sourceFiles['$uri'];
+
+ compilationUnit.members.forEach((DeclarationMirror mirror) {
+ var tagname = mirror.simpleName;
+ var byte_offset = mirror.getBeginToken().charOffset;
+ var line_number = file.getLine(byte_offset) + 1;
+
+ var lineStart = file.lineStarts[line_number - 1];
+ // TODO(ahe): Most often an empty string. Try to see if we can
+ // get the position of the name token instead.
+ var tag_definition_text = file.text.substring(lineStart, byte_offset);
+
+ // One definition.
+ buffer.write('${tag_definition_text}\x7f${tagname}'
+ '\x01${line_number},${byte_offset}\n');
+ });
+
+ var tag_definition_data = '$buffer';
+ var src_file = relativize(outputUri, uri, false);
+ var size_of_tag_definition_data_in_bytes = tag_definition_data.length;
+
+ // The header.
+ output.writeStringSync(
+ '\x0c\n${src_file},${size_of_tag_definition_data_in_bytes}\n');
+ output.writeStringSync(tag_definition_data);
+}
diff --git a/sdk/lib/_internal/pub/lib/src/oauth2.dart b/sdk/lib/_internal/pub/lib/src/oauth2.dart
index e4b8ee0..56b1494 100644
--- a/sdk/lib/_internal/pub/lib/src/oauth2.dart
+++ b/sdk/lib/_internal/pub/lib/src/oauth2.dart
@@ -169,7 +169,7 @@
// Spin up a one-shot HTTP server to receive the authorization code from the
// Google OAuth2 server via redirect. This server will close itself as soon as
// the code is received.
- return SafeHttpServer.bind('127.0.0.1', 0).then((server) {
+ return SafeHttpServer.bind('localhost', 0).then((server) {
var authUrl = grant.getAuthorizationUrl(
Uri.parse('http://localhost:${server.port}'), scopes: _scopes);
diff --git a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
index b6e1c83..25d57ee 100644
--- a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
+++ b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
@@ -21,9 +21,9 @@
class SafeHttpServer extends StreamView<HttpRequest> implements HttpServer {
final HttpServer _inner;
- static Future<SafeHttpServer> bind([String host = "127.0.0.1",
+ static Future<SafeHttpServer> bind([String host = "localhost",
int port = 0, int backlog = 0]) {
- return HttpServer.bind(host, port, backlog)
+ return HttpServer.bind(host, port, backlog: backlog)
.then((server) => new SafeHttpServer(server));
}
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 4e60ccb..b170e83 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -14,6 +14,4 @@
*: Skip
[ $system == windows ]
-test/install/git/dependency_name_match_pubspec_test: Fail # Issue 10348
test/io_test: Fail # Issue 7505
-test/install/hosted/fail_gracefully_on_url_resolve_test: Pass, Fail # Issue 9503
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index dbc326c..a175c7b 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -96,7 +96,7 @@
schedule(() {
return _closeServer().then((_) {
- return SafeHttpServer.bind("127.0.0.1", 0).then((server) {
+ return SafeHttpServer.bind("localhost", 0).then((server) {
_server = server;
server.listen((request) {
var response = request.response;
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index d25e580..40efe9a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -30288,6 +30288,7 @@
* on how we can make this class work with as many international keyboards as
* possible. Bugs welcome!
*/
+
class KeyEvent extends _WrappedEvent implements KeyboardEvent {
/** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */
KeyboardEvent _parent;
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index ef467ac..57cfda6 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -71,22 +71,14 @@
// Don't start a new read if one is already in progress.
if (_readInProgress) return;
_readInProgress = true;
- _openedFile.length()
- .then((length) {
- if (_position >= length) {
- _readInProgress = false;
+ _openedFile.read(_BLOCK_SIZE)
+ .then((block) {
+ _readInProgress = false;
+ if (block.length == 0) {
if (!_unsubscribed) {
_closeFile().then((_) { _controller.close(); });
_unsubscribed = true;
}
- return null;
- } else {
- return _openedFile.read(_BLOCK_SIZE);
- }
- })
- .then((block) {
- _readInProgress = false;
- if (block == null || _unsubscribed) {
return;
}
_position += block.length;
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 853b858..5f6a75a 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -64,32 +64,63 @@
* Starts listening for HTTP requests on the specified [address] and
* [port].
*
- * The default value for [address] is 127.0.0.1, which will allow
- * only incoming connections from the local host. To allow for
- * incoming connection from the network use either the value 0.0.0.0
- * to bind to all interfaces or the IP address of a specific
- * interface.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
*
- * If [port] has the value [:0:] (the default) an ephemeral port
- * will be chosen by the system. The actual port used can be
- * retrieved using the [:port:] getter.
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
+ * with a [ServerSocket] configured for IP version 6 connections
+ * only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
*
* The optional argument [backlog] can be used to specify the listen
* backlog for the underlying OS listen setup. If [backlog] has the
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
*/
- static Future<HttpServer> bind([String address = "127.0.0.1",
- int port = 0,
- int backlog = 0])
+ static Future<HttpServer> bind(address,
+ int port,
+ {int backlog: 0})
=> _HttpServer.bind(address, port, backlog);
/**
- * Starts listening for HTTPS requests on the specified [address] and
- * [port]. If a [port] of 0 is specified the server will choose an
- * ephemeral port. The optional argument [backlog] can be used to
- * specify the listen backlog for the underlying OS listen
- * setup.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
+ *
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [HttpServer.listenOn]
+ * with a [ServerSocket] configured for IP version 6 connections
+ * only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
*
* The certificate with Distinguished Name [certificateName] is looked
* up in the certificate database, and is used as the server certificate.
@@ -97,7 +128,7 @@
* to authenticate with a client certificate.
*/
- static Future<HttpServer> bindSecure(String address,
+ static Future<HttpServer> bindSecure(address,
int port,
{int backlog: 0,
String certificateName,
@@ -697,7 +728,8 @@
/**
- * HTTP response to be send back to the client.
+ * An [HttpResponse] represents the headers and data to be returned to
+ * a client in response to an HTTP request.
*
* This object has a number of properties for setting up the HTTP
* header of the response. When the header has been set up the methods
@@ -806,7 +838,7 @@
* provided which provides access to the headers and body of the response.
*
* HttpClient client = new HttpClient();
- * client.getUrl(new Uri.fromString("http://www.example.com/"))
+ * client.getUrl(Uri.parse("http://www.example.com/"))
* .then((HttpClientRequest request) {
* // Prepare the request then call close on it to send it.
* return request.close();
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 44337ca..ee855ec 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -128,6 +128,12 @@
HttpSession get session {
if (_session != null) {
+ if (_session._destroyed) {
+ // It's destroyed, clear it.
+ _session = null;
+ // Create new session object by calling recursive.
+ return session;
+ }
// It's already mapped, use it.
return _session;
}
@@ -1634,22 +1640,22 @@
// HTTP server waiting for socket connections.
class _HttpServer extends Stream<HttpRequest> implements HttpServer {
- static Future<HttpServer> bind(String host, int port, int backlog) {
- return ServerSocket.bind(host, port, backlog).then((socket) {
+ static Future<HttpServer> bind(address, int port, int backlog) {
+ return ServerSocket.bind(address, port, backlog: backlog).then((socket) {
return new _HttpServer._(socket, true);
});
}
- static Future<HttpServer> bindSecure(String host,
+ static Future<HttpServer> bindSecure(address,
int port,
int backlog,
String certificate_name,
bool requestClientCertificate) {
return SecureServerSocket.bind(
- host,
+ address,
port,
- backlog,
certificate_name,
+ backlog: backlog,
requestClientCertificate: requestClientCertificate)
.then((socket) {
return new _HttpServer._(socket, true);
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index 851b58d..7d7dfd1 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -20,12 +20,25 @@
* completes the server socket is bound to the given [address] and
* [port] and has started listening on it.
*
- * If [port] has the value [:0:] (the default) an ephemeral port will
- * be chosen by the system. The actual port used can be retrieved
- * using the [port] getter.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
*
- * If [backlog] has the value of [:0:] a reasonable value will be
- * chosen by the system.
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
*
* Incoming client connections are promoted to secure connections, using
* the server certificate given by [certificateName].
@@ -47,17 +60,19 @@
* was received, the result will be null.
*/
static Future<SecureServerSocket> bind(
- String address,
+ address,
int port,
- int backlog,
String certificateName,
- {bool requestClientCertificate: false,
+ {int backlog: 0,
+ bool v6Only: false,
+ bool requestClientCertificate: false,
bool requireClientCertificate: false}) {
return RawSecureServerSocket.bind(
address,
port,
- backlog,
certificateName,
+ backlog: backlog,
+ v6Only: v6Only,
requestClientCertificate: requestClientCertificate,
requireClientCertificate: requireClientCertificate).then(
(serverSocket) => new SecureServerSocket._(serverSocket));
@@ -118,12 +133,25 @@
* completes the server socket is bound to the given [address] and
* [port] and has started listening on it.
*
- * If [port] has the value [:0:] (the default) an ephemeral port will
- * be chosen by the system. The actual port used can be retrieved
- * using the [port] getter.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
*
- * If [backlog] has the value of [:0:] a reasonable value will be
- * chosen by the system.
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
+ *
+ * The optional argument [backlog] can be used to specify the listen
+ * backlog for the underlying OS listen setup. If [backlog] has the
+ * value of [:0:] (the default) a reasonable value will be chosen by
+ * the system.
*
* Incoming client connections are promoted to secure connections,
* using the server certificate given by [certificateName].
@@ -146,11 +174,12 @@
static Future<RawSecureServerSocket> bind(
String address,
int port,
- int backlog,
String certificateName,
- {bool requestClientCertificate: false,
+ {int backlog: 0,
+ bool v6Only: false,
+ bool requestClientCertificate: false,
bool requireClientCertificate: false}) {
- return RawServerSocket.bind(address, port, backlog)
+ return RawServerSocket.bind(address, port, backlog: backlog, v6Only: v6Only)
.then((serverSocket) => new RawSecureServerSocket._(
serverSocket,
certificateName,
@@ -183,7 +212,7 @@
void _onData(RawSocket connection) {
_RawSecureSocket.connect(
- connection.remoteHost,
+ connection.address,
connection.remotePort,
certificateName,
is_server: true,
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 9b4d4c6..4ed4da4 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -295,7 +295,7 @@
socket.readEventsEnabled = false;
socket.writeEventsEnabled = false;
return _RawSecureSocket.connect(
- socket.remoteHost,
+ socket.address,
socket.remotePort,
certificateName,
is_server: true,
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 6ad9592..040cf39 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -96,12 +96,13 @@
* change over time.
*/
external static Future<List<InternetAddress>> lookup(
- String host, {InternetAddressType type: InternetAddressType.IP_V4});
+ String host, {InternetAddressType type: InternetAddressType.ANY});
}
/**
- * The RawServerSocket is a server socket, providing a stream of low-level
- * [RawSocket]s.
+ * A [RawServerSocket] represents a listening socket, and provides a
+ * stream of low-level [RawSocket] objects, one for each connection
+ * made to the listening socket.
*
* See [RawSocket] for more info.
*/
@@ -111,13 +112,23 @@
* completes the server socket is bound to the given [address] and
* [port] and has started listening on it.
*
- * The default value for [address] is 127.0.0.1, which will allow
- * only incoming connections from the local host. To allow for
- * incoming connection from the network use either the value 0.0.0.0
- * to bind to all interfaces or the IP address of a specific
- * interface.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
*
- * If [port] has the value [:0:] (the default) an ephemeral port will
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will
* be chosen by the system. The actual port used can be retrieved
* using the [:port:] getter.
*
@@ -126,9 +137,10 @@
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
*/
- external static Future<RawServerSocket> bind([address = "127.0.0.1",
- int port = 0,
- int backlog = 0]);
+ external static Future<RawServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false});
/**
* Returns the port used by this socket.
@@ -143,8 +155,9 @@
/**
- * The [ServerSocket] is server socket, providing a stream of high-level
- * [Socket]s.
+ * A [ServerSocket] represents a listening socket, and provides a
+ * stream of [Socket] objects, one for each connection made to the
+ * listening socket.
*
* See [Socket] for more info.
*/
@@ -154,24 +167,35 @@
* completes the server socket is bound to the given [address] and
* [port] and has started listening on it.
*
- * The default value for [address] is 127.0.0.1, which will allow
- * only incoming connections from the local host. To allow for
- * incoming connection from the network use either the value 0.0.0.0
- * to bind to all interfaces or the IP address of a specific
- * interface.
+ * The [address] can either be a [String] or an
+ * [InternetAddress]. If [address] is a [String], [bind] will
+ * perform a [InternetAddress.lookup] and use the first value in the
+ * list. To listen on the loopback adapter, which will allow only
+ * incoming connections from the local host, use the value
+ * [InternetAddress.LOOPBACK_IP_V4] or
+ * [InternetAddress.LOOPBACK_IP_V6]. To allow for incoming
+ * connection from the network use either one of the values
+ * [InternetAddress.ANY_IP_V4] or [InternetAddress.ANY_IP_V6] to
+ * bind to all interfaces or the IP address of a specific interface.
*
- * If [port] has the value [:0:] (the default) an ephemeral port will
- * be chosen by the system. The actual port used can be retrieved
- * using the [port] getter.
+ * If an IP version 6 (IPv6) address is used, both IP version 6
+ * (IPv6) and version 4 (IPv4) connections will be accepted. To
+ * restrict this to version 6 (IPv6) only, use [v6Only] to set
+ * version 6 only.
+ *
+ * If [port] has the value [:0:] an ephemeral port will be chosen by
+ * the system. The actual port used can be retrieved using the
+ * [port] getter.
*
* The optional argument [backlog] can be used to specify the listen
* backlog for the underlying OS listen setup. If [backlog] has the
* value of [:0:] (the default) a reasonable value will be chosen by
* the system.
*/
- external static Future<ServerSocket> bind([address = "127.0.0.1",
- int port = 0,
- int backlog = 0]);
+ external static Future<ServerSocket> bind(address,
+ int port,
+ {int backlog: 0,
+ bool v6Only: false});
/**
* Returns the port used by this socket.
@@ -210,6 +234,7 @@
* TCP_NODELAY is disabled by default.
*/
static const SocketOption TCP_NODELAY = const SocketOption._(0);
+
const SocketOption._(this._value);
final _value;
}
diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart
index 640ce3d..967e9a3 100644
--- a/sdk/lib/uri/uri.dart
+++ b/sdk/lib/uri/uri.dart
@@ -12,8 +12,13 @@
/**
* A parsed URI, inspired by Closure's [URI][] class. Implements [RFC-3986][].
- * [uri]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
+ * The domain component can either be a hostname, a IPv4 address or an IPv6
+ * address, contained in '[' and ']', following [RFC-2732][]. If the domain
+ * component contains a ':', the String returned from [toString] will have
+ * '[' and ']' around the domain part.
+ * [URI]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
* [RFC-3986]: http://tools.ietf.org/html/rfc3986#section-4.3)
+ * [RFC-2732]: http://www.ietf.org/rfc/rfc2732.txt
*/
class Uri {
final String scheme;
@@ -24,17 +29,13 @@
final String query;
final String fragment;
- /**
- * Deprecated. Please use [parse] instead.
- */
- Uri.fromString(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
-
static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
Uri._fromMatch(Match m) :
this.fromComponents(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
- domain: _emptyIfNull(m[_COMPONENT_DOMAIN]),
+ domain: _eitherOf(
+ m[_COMPONENT_DOMAIN], m[_COMPONENT_DOMAIN_IPV6]),
port: _parseIntOrZero(m[_COMPONENT_PORT]),
path: _emptyIfNull(m[_COMPONENT_PATH]),
query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
@@ -48,7 +49,7 @@
this.query: "",
this.fragment: ""});
- Uri(String uri) : this.fromString(uri);
+ Uri(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
static String _emptyIfNull(String val) => val != null ? val : '';
@@ -60,6 +61,12 @@
}
}
+ static String _eitherOf(String val1, String val2) {
+ if (val1 != null) return val1;
+ if (val2 != null) return val2;
+ return '';
+ }
+
// NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
static final RegExp _splitRe = new RegExp(
'^'
@@ -70,24 +77,31 @@
':)?'
'(?://'
'(?:([^/?#]*)@)?' // userInfo
- '([\\w\\d\\-\\u0100-\\uffff.%]*)'
+ '(?:'
+ r'([\w\d\-\u0100-\uffff.%]*)'
// domain - restrict to letters,
// digits, dashes, dots, percent
// escapes, and unicode characters.
+ '|'
+ // TODO(ajohnsen): Only allow a max number of parts?
+ r'\[([A-Fa-f0-9:.]*)\])'
+ // IPv6 domain - restrict to hex,
+ // dot and colon.
'(?::([0-9]+))?' // port
')?'
- '([^?#]+)?' // path
- '(?:\\?([^#]*))?' // query
+ r'([^?#[]+)?' // path
+ r'(?:\?([^#]*))?' // query
'(?:#(.*))?' // fragment
- '\$');
+ r'$');
static const _COMPONENT_SCHEME = 1;
static const _COMPONENT_USER_INFO = 2;
static const _COMPONENT_DOMAIN = 3;
- static const _COMPONENT_PORT = 4;
- static const _COMPONENT_PATH = 5;
- static const _COMPONENT_QUERY_DATA = 6;
- static const _COMPONENT_FRAGMENT = 7;
+ static const _COMPONENT_DOMAIN_IPV6 = 4;
+ static const _COMPONENT_PORT = 5;
+ static const _COMPONENT_PATH = 6;
+ static const _COMPONENT_QUERY_DATA = 7;
+ static const _COMPONENT_FRAGMENT = 8;
/**
* Returns `true` if the URI is absolute.
@@ -222,7 +236,8 @@
if (hasAuthority || (scheme == "file")) {
sb.write("//");
_addIfNonEmpty(sb, userInfo, userInfo, "@");
- sb.write(domain == null ? "null" : domain);
+ sb.write(domain == null ? "null" :
+ domain.contains(':') ? '[$domain]' : domain);
if (port != 0) {
sb.write(":");
sb.write(port.toString());
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 237a6a9..e602004 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -23,6 +23,7 @@
Message,
MessageKind,
Selector,
+ TypedSelector,
SourceSpan;
import '../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart' as ssa;
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index d67dd56..619f3bf 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -780,6 +780,26 @@
}
}
+testBooleanOperators() {
+ String source(op) {
+ return """
+ main() {
+ var a = true $op null;
+ var b = null $op true;
+ var c = 1 $op true;
+ var d = true $op "a";
+ a; b; c; d;
+ }""";
+ }
+ for (String op in ['&&', '||']) {
+ AnalysisResult result = analyze(source(op));
+ result.checkNodeHasType('a', [result.bool]);
+ result.checkNodeHasType('b', [result.bool]);
+ result.checkNodeHasType('c', [result.bool]);
+ result.checkNodeHasType('d', [result.bool]);
+ }
+}
+
testOperators() {
final String source = r"""
class A {
@@ -1221,7 +1241,7 @@
for (ClassElement cls in [a, b, c, d]) {
Expect.equals(convert(singleton(cls)),
- new TypeMask.exact(cls.rawType).nonNullable());
+ new TypeMask.nonNullExact(cls.rawType));
}
for (ClassElement cls in [a, b, c, d]) {
@@ -1230,13 +1250,76 @@
}
Expect.equals(convert(singleton(a).union(singleton(b))),
- new TypeMask.subclass(a.rawType).nonNullable());
+ new TypeMask.nonNullSubclass(a.rawType));
Expect.equals(convert(singleton(a).union(singleton(b)).union(nullSingleton)),
new TypeMask.subclass(a.rawType));
Expect.equals(convert(singleton(b).union(singleton(d))),
- new TypeMask.subtype(a.rawType).nonNullable());
+ new TypeMask.nonNullSubtype(a.rawType));
+}
+
+testSelectors() {
+ final String source = r"""
+ // ABC <--- A
+ // `- BC <--- B
+ // `- C
+
+ class ABC {}
+ class A extends ABC {}
+ class BC extends ABC {}
+ class B extends BC {}
+ class C extends BC {}
+
+ class XY {}
+ class X extends XY { foo() => new B(); }
+ class Y extends XY { foo() => new C(); }
+ class Z { foo() => new A(); }
+
+ main() {
+ new X().foo();
+ new Y().foo();
+ new Z().foo();
+ }
+ """;
+ AnalysisResult result = analyze(source);
+
+ inferredType(Selector selector) {
+ return result.compiler.typesTask.concreteTypesInferrer
+ .getTypeOfSelector(selector);
+ }
+
+ ClassElement abc = findElement(result.compiler, 'ABC');
+ ClassElement bc = findElement(result.compiler, 'BC');
+ ClassElement a = findElement(result.compiler, 'A');
+ ClassElement b = findElement(result.compiler, 'B');
+ ClassElement c = findElement(result.compiler, 'C');
+ ClassElement xy = findElement(result.compiler, 'XY');
+ ClassElement x = findElement(result.compiler, 'X');
+ ClassElement y = findElement(result.compiler, 'Y');
+ ClassElement z = findElement(result.compiler, 'Z');
+
+ Selector foo = new Selector.call(buildSourceString("foo"), null, 0);
+
+ Expect.equals(
+ inferredType(foo),
+ new TypeMask.nonNullSubclass(abc.rawType));
+ Expect.equals(
+ inferredType(new TypedSelector.subclass(x.rawType, foo)),
+ new TypeMask.nonNullExact(b.rawType));
+ Expect.equals(
+ inferredType(new TypedSelector.subclass(y.rawType, foo)),
+ new TypeMask.nonNullExact(c.rawType));
+ Expect.equals(
+ inferredType(new TypedSelector.subclass(z.rawType, foo)),
+ new TypeMask.nonNullExact(a.rawType));
+ Expect.equals(
+ inferredType(new TypedSelector.subclass(xy.rawType, foo)),
+ new TypeMask.nonNullSubclass(bc.rawType));
+
+ Selector bar = new Selector.call(buildSourceString("bar"), null, 0);
+
+ Expect.isNull(inferredType(bar));
}
void main() {
@@ -1266,6 +1349,7 @@
testReturn();
// testNoReturn(); // right now we infer the empty type instead of null
testArithmeticOperators();
+ testBooleanOperators();
testOperators();
testCompoundOperators1();
testCompoundOperators2();
@@ -1287,4 +1371,5 @@
testGoodGuys();
testIntDoubleNum();
testConcreteTypeToTypeMask();
+ testSelectors();
}
diff --git a/tests/compiler/dart2js/dead_bailout_target_test.dart b/tests/compiler/dart2js/dead_bailout_target_test.dart
index b6fe836..760da9c 100644
--- a/tests/compiler/dart2js/dead_bailout_target_test.dart
+++ b/tests/compiler/dart2js/dead_bailout_target_test.dart
@@ -60,7 +60,7 @@
// Check that the bailout method has a case 2 for the state, which
// is the second bailout in foo.
- RegExp state = new RegExp('case 2:[ \n]+state0 = 0;');
+ RegExp state = new RegExp('case 2:');
checkNumberOfMatches(state.allMatches(generated).iterator, 1);
// Finally, make sure that the reason foo does not contain
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 42bfc60..f2fa92a 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -6,9 +6,6 @@
import "../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart";
import "../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart";
import "../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart";
-import
- "../../../sdk/lib/_internal/compiler/implementation/universe/universe.dart"
- show TypedSelector;
import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
import "mock_compiler.dart";
import "parser_helper.dart";
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 7257bf3..1315cac 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -9,7 +9,6 @@
native_null_closure_frog_test: Fail
native_no_such_method_exception4_frog_test: Fail # Issue 9631
native_no_such_method_exception5_frog_test: Fail # Issue 9631
-super_call_test: Fail # Issue 10166
[ $compiler == dart2js && $checked ]
native_no_such_method_exception3_frog_test: Fail # TODO(ahe): investigate.
diff --git a/tests/language/abstract_object_method_test.dart b/tests/language/abstract_object_method_test.dart
new file mode 100644
index 0000000..f88094b
--- /dev/null
+++ b/tests/language/abstract_object_method_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+class A {
+ noSuchMethod(_) {
+ Expect.fail('Should not reach here');
+ }
+}
+
+class B extends A {
+ operator ==(other);
+}
+
+class C extends B {
+}
+
+var a = [new C()];
+
+main() {
+ C c = a[0];
+ a.add(c);
+ Expect.isTrue(c == a[1]);
+}
diff --git a/tests/language/empty_main.dart b/tests/language/empty_main.dart
index 7def6ef..0946204 100644
--- a/tests/language/empty_main.dart
+++ b/tests/language/empty_main.dart
@@ -2,4 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+part of ApplicationTest.dart;
+
main() {}
diff --git a/tests/language/generic_instanceof.dart b/tests/language/generic_instanceof.dart
index 3f64976..8b9388d 100644
--- a/tests/language/generic_instanceof.dart
+++ b/tests/language/generic_instanceof.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Test that instanceof works correctly with type variables.
+part of GenericInstanceofTest.dart;
+
class Foo<T> {
Foo() {}
diff --git a/tests/language/hello_script_lib_source.dart b/tests/language/hello_script_lib_source.dart
index 8f44b7b..8c74bc4 100644
--- a/tests/language/hello_script_lib_source.dart
+++ b/tests/language/hello_script_lib_source.dart
@@ -7,4 +7,6 @@
// A top-level variable being accessed both from the library and the importer.
+part of HelloScriptLib;
+
var x;
diff --git a/tests/language/issue10321_test.dart b/tests/language/issue10321_test.dart
new file mode 100644
index 0000000..fb35dcd
--- /dev/null
+++ b/tests/language/issue10321_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 "package:expect/expect.dart";
+
+// Regression test for dart2js that used to miscompile [A.foo].
+
+var global = 54;
+
+class A {
+ int a = 0;
+ int b = 42;
+ final int c = global;
+ foo() {
+ int start = a - 1;
+ a = 54;
+ if (b == 42) {
+ b = 32;
+ } else {
+ b = 42;
+ }
+ Expect.equals(-1, start);
+ }
+
+ bar() {
+ int start = a - c - 1;
+ a = 42;
+ if (b == 42) {
+ b = 32;
+ } else {
+ b = 42;
+ }
+ Expect.equals(-55, start);
+ }
+}
+
+main() {
+ new A().foo();
+ new A().bar();
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 2a940a4..740c10f 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -120,7 +120,6 @@
metadata_test: Fail
const_locals_test: Fail
const_nested_test: Fail
-application_negative_test: Fail # Runtime only test, rewrite as multitest
assign_instance_method_negative_test: Fail # Runtime only test, rewrite as multitest
body_less_constructor_wrong_arg_negative_test: Fail # Runtime only test, rewrite as multitest
call_nonexistent_static_test/03: Fail # Unresolved static calls are no longer errors.
@@ -178,11 +177,9 @@
library4_negative_test: Fail # still a valid test? Issue 3530
library6_negative_test: Fail # still a valid test? Issue 3650
named_parameters_with_object_property_names_test: Fail # Issue 2137
-many_overridden_no_such_method_test: Fail
no_such_method_negative_test: Fail # Runtime only test, rewrite as multitest
override_field_test/03: Fail # still a valid test? Issue 3894
override_field_method6_negative_test: Fail, OK # test issue 5249
-overridden_no_such_method_test: Fail
parameter_initializer6_negative_test: Fail # language change 4288
prefix1_negative_test : Fail # language change 1031
prefix4_negative_test : Fail # language change 1031
@@ -223,23 +220,6 @@
# test issue 5529
interface_test/none: Fail, OK
-# test issue 6338
-application_negative_test: Pass
-application_test: Fail, OK
-generic_instanceof_test: Fail, OK
-hello_script_test: Fail, OK
-lazy_static6_test: Fail, OK
-library1_test: Fail, OK
-library_prefixes_test: Fail, OK
-many_generic_instanceof_test: Fail, OK
-multi_pass2_test: Fail, OK
-multi_pass_test: Fail, OK
-private2_test: Fail, OK
-private3_test: Fail, OK
-private_test: Fail, OK
-top_level_entry_test: Fail, OK
-top_level_multiple_files_test: Fail, OK
-top_level_non_prefixed_library_test: Fail, OK
prefix6_negative_test: Fail
diff --git a/tests/language/lazy_static6_src.dart b/tests/language/lazy_static6_src.dart
index 779d3d8..c17f7da 100644
--- a/tests/language/lazy_static6_src.dart
+++ b/tests/language/lazy_static6_src.dart
@@ -18,6 +18,7 @@
******************************************************************************
******************************************************************************
*/
+part of lazy_static6_test;
final x = (t) => (u) => t + u;
diff --git a/tests/language/library1_lib.dart b/tests/language/library1_lib.dart
index c605f426..66af369 100644
--- a/tests/language/library1_lib.dart
+++ b/tests/language/library1_lib.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.
+part of Library1Lib;
+
class A {
A() {}
String foo() { return "foo-rty two"; }
diff --git a/tests/language/library_prefixes.dart b/tests/language/library_prefixes.dart
index d44e374..bac0079 100644
--- a/tests/language/library_prefixes.dart
+++ b/tests/language/library_prefixes.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.
+part of LibraryPrefixes.lib;
+
class LibraryPrefixes {
static void main(var expectEquals) {
diff --git a/tests/language/library_prefixes_test1.dart b/tests/language/library_prefixes_test1.dart
index 53ab581..0ed6c8d 100644
--- a/tests/language/library_prefixes_test1.dart
+++ b/tests/language/library_prefixes_test1.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.
+part of LibraryPrefixesTest1.lib;
+
class Constants {
static const PI = 3.14;
static const foo = 1;
diff --git a/tests/language/library_prefixes_test2.dart b/tests/language/library_prefixes_test2.dart
index 7e5e600..4415040 100644
--- a/tests/language/library_prefixes_test2.dart
+++ b/tests/language/library_prefixes_test2.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.
+part of LibraryPrefixesTest2.lib;
+
class Constants {
static const PI = 3.14;
static const foo = 2;
diff --git a/tests/language/many_generic_instanceof_test.dart b/tests/language/many_generic_instanceof_test.dart
index 5f92367..6f1d9c2 100644
--- a/tests/language/many_generic_instanceof_test.dart
+++ b/tests/language/many_generic_instanceof_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library ManyGenericInstanceofTest.dart;
+library GenericInstanceofTest.dart;
import "package:expect/expect.dart";
part "generic_instanceof.dart";
diff --git a/tests/language/many_overridden_no_such_method_test.dart b/tests/language/many_overridden_no_such_method_test.dart
index f772998..7c90383 100644
--- a/tests/language/many_overridden_no_such_method_test.dart
+++ b/tests/language/many_overridden_no_such_method_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library ManyOverriddenNoSuchMethodTest.dart;
+library OverriddenNoSuchMethodTest.dart;
import "dart:mirrors" show reflect;
import "package:expect/expect.dart";
diff --git a/tests/language/multi_pass2_test.dart b/tests/language/multi_pass2_test.dart
index 4e67d98..f7042a0 100644
--- a/tests/language/multi_pass2_test.dart
+++ b/tests/language/multi_pass2_test.dart
@@ -4,7 +4,7 @@
// Dart test for loading several dart files and resolving superclasses lazily.
// Same as MultiPassTest, except that the file order is reversed.
-library MultiPass2Test.dart;
+library MultiPassTest.dart;
import "package:expect/expect.dart";
part "multi_pass_a.dart";
part "multi_pass_b.dart";
diff --git a/tests/language/multi_pass_a.dart b/tests/language/multi_pass_a.dart
index 05f4189..5b2863f 100644
--- a/tests/language/multi_pass_a.dart
+++ b/tests/language/multi_pass_a.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for loading several dart files and resolving superclasses lazily.
+part of MultiPassTest.dart;
class A extends Base {
A(v) : super(v) {}
diff --git a/tests/language/multi_pass_b.dart b/tests/language/multi_pass_b.dart
index 802f1c6..ed99b83 100644
--- a/tests/language/multi_pass_b.dart
+++ b/tests/language/multi_pass_b.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for loading several dart files and resolving superclasses lazily.
+part of MultiPassTest.dart;
+
class B extends A {
B(v) : super(v) {}
}
diff --git a/tests/language/overridden_no_such_method.dart b/tests/language/overridden_no_such_method.dart
index d3a87b2..54b44a4 100644
--- a/tests/language/overridden_no_such_method.dart
+++ b/tests/language/overridden_no_such_method.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test program testing overridden messageNotUnderstood.
+part of OverriddenNoSuchMethodTest.dart;
+
class GetName {
foo(a, b) => "foo";
}
diff --git a/tests/language/private1.dart b/tests/language/private1.dart
index b4e9371..5329acf 100644
--- a/tests/language/private1.dart
+++ b/tests/language/private1.dart
@@ -4,6 +4,8 @@
// Dart test for testing access to private fields.
+part of PrivateTest.dart;
+
main() {
testPrivateTopLevel();
testPrivateClasses();
diff --git a/tests/language/private2.dart b/tests/language/private2.dart
index 8a624b7..eb50027 100644
--- a/tests/language/private2.dart
+++ b/tests/language/private2.dart
@@ -4,6 +4,8 @@
// Dart test for testing access to private fields.
+part of PrivateTest.dart;
+
String _private2() { return "private2"; }
const String _private2Field = "private2Field";
diff --git a/tests/language/private2_lib.dart b/tests/language/private2_lib.dart
index 0443f26..938b5b4 100644
--- a/tests/language/private2_lib.dart
+++ b/tests/language/private2_lib.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing access to private fields across class hierarchies.
+part of Private2Lib;
+
class B extends A {
B() : super();
}
diff --git a/tests/language/private2_main.dart b/tests/language/private2_main.dart
index a39ff70..1d4d15f 100644
--- a/tests/language/private2_main.dart
+++ b/tests/language/private2_main.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing access to private fields across class hierarchies.
+part of Private2Test;
+
class A {
var _f;
var g;
diff --git a/tests/language/private3.dart b/tests/language/private3.dart
index 93a3d41..d058fc8 100644
--- a/tests/language/private3.dart
+++ b/tests/language/private3.dart
@@ -4,6 +4,8 @@
// Dart test for testing access to private fields.
+part of PrivateOther;
+
class LibOther3 {
static accessFieldA3(var a) => a.fieldA;
static accessFieldB3(var b) => b._fieldB;
diff --git a/tests/language/private_lib.dart b/tests/language/private_lib.dart
index cb9331e..d5dea43 100644
--- a/tests/language/private_lib.dart
+++ b/tests/language/private_lib.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing access to private fields.
+part of PrivateLib;
+
class PrivateLib {
final _myPrecious;
diff --git a/tests/language/private_main.dart b/tests/language/private_main.dart
index 531cbb0..5e1f8d4 100644
--- a/tests/language/private_main.dart
+++ b/tests/language/private_main.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing access to private fields.
+part of Private3Test.dart;
+
main() {
PrivateMain.main();
}
diff --git a/tests/language/private_other.dart b/tests/language/private_other.dart
index c4e19ec..107d8fc 100644
--- a/tests/language/private_other.dart
+++ b/tests/language/private_other.dart
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
// Dart test for testing access to private fields.
+part of Private3Test.dart;
+
class PrivateOther {
final _myPrecious;
diff --git a/tests/language/top_level_entry.dart b/tests/language/top_level_entry.dart
index 1b483b6..bbe7035 100644
--- a/tests/language/top_level_entry.dart
+++ b/tests/language/top_level_entry.dart
@@ -2,5 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+part of top_level_entry_test.dart;
+
main() {
}
diff --git a/tests/language/top_level_file1.dart b/tests/language/top_level_file1.dart
index 160d300..e0f5d98 100644
--- a/tests/language/top_level_file1.dart
+++ b/tests/language/top_level_file1.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.
+part of TopLevelMultipleFilesTest.dart;
+
main() {
Expect.equals(topLevelVar, 42);
Expect.equals(topLevelMethod(), 87);
diff --git a/tests/language/top_level_file2.dart b/tests/language/top_level_file2.dart
index 1b8f549..19ca8ca 100644
--- a/tests/language/top_level_file2.dart
+++ b/tests/language/top_level_file2.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.
+part of TopLevelMultipleFilesTest.dart;
+
const topLevelVar = 42;
topLevelMethod() => 87;
diff --git a/tests/language/top_level_non_prefixed_library_test.dart b/tests/language/top_level_non_prefixed_library_test.dart
index 5a3995c..d0f8dab 100644
--- a/tests/language/top_level_non_prefixed_library_test.dart
+++ b/tests/language/top_level_non_prefixed_library_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library TopLevelNonPrefixLibraryTest.dart;
+library TopLevelMultipleFilesTest.dart;
import "package:expect/expect.dart";
import 'top_level_prefixed_library_test.lib';
diff --git a/tests/lib/crypto/hmac_sha1_test_vectors.dart b/tests/lib/crypto/hmac_sha1_test_vectors.dart
index 9298817..26f37f9 100644
--- a/tests/lib/crypto/hmac_sha1_test_vectors.dart
+++ b/tests/lib/crypto/hmac_sha1_test_vectors.dart
@@ -5,6 +5,8 @@
// Standard test vectors from:
// http://csrc.nist.gov/groups/STM/cavp/documents/mac/hmactestvectors.zip
+part of hmac_sha1_test;
+
const hmac_sha1_inputs = const [
const [ 0xfc, 0xd6, 0xd9, 0x8b, 0xef, 0x45, 0xed, 0x68, 0x50, 0x80, 0x6e, 0x96, 0xf2, 0x55, 0xfa, 0x0c, 0x81, 0x14, 0xb7, 0x28, 0x73, 0xab, 0xe8, 0xf4, 0x3c, 0x10, 0xbe, 0xa7, 0xc1, 0xdf, 0x70, 0x6f, 0x10, 0x45, 0x8e, 0x6d, 0x4e, 0x1c, 0x92, 0x01, 0xf0, 0x57, 0xb8, 0x49, 0x2f, 0xa1, 0x0f, 0xe4, 0xb5, 0x41, 0xd0, 0xfc, 0x9d, 0x41, 0xef, 0x83, 0x9a, 0xcf, 0xf1, 0xbc, 0x76, 0xe3, 0xfd, 0xfe, 0xbf, 0x22, 0x35, 0xb5, 0xbd, 0x03, 0x47, 0xa9, 0xa6, 0x30, 0x3e, 0x83, 0x15, 0x2f, 0x9f, 0x8d, 0xb9, 0x41, 0xb1, 0xb9, 0x4a, 0x8a, 0x1c, 0xe5, 0xc2, 0x73, 0xb5, 0x5d, 0xc9, 0x4d, 0x99, 0xa1, 0x71, 0x37, 0x79, 0x69, 0x23, 0x41, 0x34, 0xe7, 0xda, 0xd1, 0xab, 0x4c, 0x8e, 0x46, 0xd1, 0x8d, 0xf4, 0xdc, 0x01, 0x67, 0x64, 0xcf, 0x95, 0xa1, 0x1a, 0xc4, 0xb4, 0x91, 0xa2, 0x64, 0x6b, 0xe1 ],
const [ 0xd6, 0x8b, 0x82, 0x8a, 0x15, 0x3f, 0x51, 0x98, 0xc0, 0x05, 0xee, 0x36, 0xc0, 0xaf, 0x2f, 0xf9, 0x2e, 0x84, 0x90, 0x75, 0x17, 0xf0, 0x1d, 0x9b, 0x7c, 0x79, 0x93, 0x46, 0x9d, 0xf5, 0xc2, 0x10, 0x78, 0xfa, 0x35, 0x6a, 0x8c, 0x97, 0x15, 0xec, 0xe2, 0x41, 0x4b, 0xe9, 0x4e, 0x10, 0xe5, 0x47, 0xf3, 0x2c, 0xbb, 0x8d, 0x05, 0x82, 0x52, 0x3e, 0xd3, 0xbb, 0x00, 0x66, 0x04, 0x6e, 0x51, 0x72, 0x20, 0x94, 0xaa, 0x44, 0x53, 0x3d, 0x2c, 0x87, 0x6e, 0x82, 0xdb, 0x40, 0x2f, 0xbb, 0x00, 0xa6, 0xc2, 0xf2, 0xcc, 0x34, 0x87, 0x97, 0x3d, 0xfc, 0x16, 0x74, 0x46, 0x3e, 0x81, 0xe4, 0x2a, 0x39, 0xd9, 0x40, 0x29, 0x41, 0xf3, 0x9b, 0x5e, 0x12, 0x6b, 0xaf, 0xe8, 0x64, 0xea, 0x16, 0x48, 0xc0, 0xa5, 0xbe, 0x0a, 0x91, 0x26, 0x97, 0xa8, 0x7e, 0x4f, 0x8e, 0xab, 0xf7, 0x9c, 0xbf, 0x13, 0x0e ],
diff --git a/tests/lib/crypto/hmac_sha256_test_vectors.dart b/tests/lib/crypto/hmac_sha256_test_vectors.dart
index 32962f8..6cb65b1 100644
--- a/tests/lib/crypto/hmac_sha256_test_vectors.dart
+++ b/tests/lib/crypto/hmac_sha256_test_vectors.dart
@@ -5,6 +5,8 @@
// Standard test vectors from:
// http://csrc.nist.gov/groups/STM/cavp/documents/mac/hmactestvectors.zip
+part of hmac_sha256_test;
+
const hmac_sha256_inputs = const [
const [ 0x75, 0x2c, 0xff, 0x52, 0xe4, 0xb9, 0x07, 0x68, 0x55, 0x8e, 0x53, 0x69, 0xe7, 0x5d, 0x97, 0xc6, 0x96, 0x43, 0x50, 0x9a, 0x5e, 0x59, 0x04, 0xe0, 0xa3, 0x86, 0xcb, 0xe4, 0xd0, 0x97, 0x0e, 0xf7, 0x3f, 0x91, 0x8f, 0x67, 0x59, 0x45, 0xa9, 0xae, 0xfe, 0x26, 0xda, 0xea, 0x27, 0x58, 0x7e, 0x8d, 0xc9, 0x09, 0xdd, 0x56, 0xfd, 0x04, 0x68, 0x80, 0x5f, 0x83, 0x40, 0x39, 0xb3, 0x45, 0xf8, 0x55, 0xcf, 0xe1, 0x9c, 0x44, 0xb5, 0x5a, 0xf2, 0x41, 0xff, 0xf3, 0xff, 0xcd, 0x80, 0x45, 0xcd, 0x5c, 0x28, 0x8e, 0x6c, 0x4e, 0x28, 0x4c, 0x37, 0x20, 0x57, 0x0b, 0x58, 0xe4, 0xd4, 0x7b, 0x8f, 0xee, 0xed, 0xc5, 0x2f, 0xd1, 0x40, 0x1f, 0x69, 0x8a, 0x20, 0x9f, 0xcc, 0xfa, 0x3b, 0x4c, 0x0d, 0x9a, 0x79, 0x7b, 0x04, 0x6a, 0x27, 0x59, 0xf8, 0x2a, 0x54, 0xc4, 0x1c, 0xcd, 0x7b, 0x5f, 0x59, 0x2b ],
const [ 0xe0, 0xef, 0xf0, 0x0f, 0x3c, 0x46, 0xe9, 0x6c, 0x8d, 0x5b, 0xd1, 0x81, 0x28, 0x3e, 0x46, 0x05, 0x34, 0x8e, 0x3f, 0xa1, 0x0b, 0x47, 0x94, 0x5d, 0xe3, 0xdc, 0xc1, 0x59, 0xae, 0x86, 0xe7, 0xbd, 0x3f, 0xdb, 0x13, 0xf2, 0xad, 0xa2, 0xc3, 0x13, 0xfc, 0xe6, 0xa6, 0x9e, 0xfa, 0x49, 0xa4, 0x70, 0x68, 0x9b, 0x1e, 0xf0, 0x5a, 0xab, 0x77, 0x8a, 0xe1, 0x5d, 0xd3, 0x5f, 0xe6, 0xfd, 0x1e, 0x3a, 0x59, 0xd3, 0x51, 0xc6, 0x8c, 0xf8, 0xf0, 0xff, 0xd9, 0x68, 0xd7, 0xe7, 0x8b, 0x57, 0x37, 0x7a, 0xfc, 0xc9, 0xdc, 0xe3, 0xfa, 0x5d, 0xb1, 0xf0, 0x6f, 0x69, 0x85, 0xc4, 0x41, 0x4c, 0x0f, 0xcc, 0x78, 0x00, 0x30, 0xf4, 0x9f, 0xef, 0x79, 0x1a, 0x6c, 0x08, 0xed, 0xc2, 0xa3, 0x11, 0x08, 0x0c, 0x37, 0x3f, 0x00, 0xe4, 0xb2, 0x04, 0x4a, 0x79, 0xd8, 0x28, 0x60, 0xf0, 0x87, 0x1b, 0xc2, 0x59 ],
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 053f62a..26e406b 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -57,11 +57,6 @@
# Skip until we stabilize language tests.
*: Skip
-[ $compiler == dartc ]
-# lib issue 6322
-crypto/hmac_sha1_test: Fail
-crypto/hmac_sha256_test: Fail
-
[ $runtime == safari]
# Bug in JSC: the test only passes when being debugged.
crypto/hmac_md5_test: Fail, Pass
diff --git a/tests/lib/uri/uri_ipv6_test.dart b/tests/lib/uri/uri_ipv6_test.dart
new file mode 100644
index 0000000..1b69cf9
--- /dev/null
+++ b/tests/lib/uri/uri_ipv6_test.dart
@@ -0,0 +1,80 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import 'dart:uri';
+
+
+void testValidIpv6Uri() {
+ var path = 'http://[::1]:1234/path?query=5#now';
+ var uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::1', uri.domain);
+ Expect.equals(1234, uri.port);
+ Expect.equals('/path', uri.path);
+ Expect.equals('query=5', uri.query);
+ Expect.equals('now', uri.fragment);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('FEDC:BA98:7654:3210:FEDC:BA98:7654:3210', uri.domain);
+ Expect.equals(80, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[1080:0:0:0:8:800:200C:417A]/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('1080:0:0:0:8:800:200C:417A', uri.domain);
+ Expect.equals(0, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[3ffe:2a00:100:7031::1]';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('3ffe:2a00:100:7031::1', uri.domain);
+ Expect.equals(0, uri.port);
+ Expect.equals('', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[1080::8:800:200C:417A]/foo';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('1080::8:800:200C:417A', uri.domain);
+ Expect.equals(0, uri.port);
+ Expect.equals('/foo', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[::192.9.5.5]/ipng';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::192.9.5.5', uri.domain);
+ Expect.equals(0, uri.port);
+ Expect.equals('/ipng', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[::FFFF:129.144.52.38]:80/index.html';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('::FFFF:129.144.52.38', uri.domain);
+ Expect.equals(80, uri.port);
+ Expect.equals('/index.html', uri.path);
+ Expect.equals(path, uri.toString());
+
+ path = 'http://[2010:836B:4179::836B:4179]';
+ uri = Uri.parse(path);
+ Expect.equals('http', uri.scheme);
+ Expect.equals('2010:836B:4179::836B:4179', uri.domain);
+ Expect.equals(0, uri.port);
+ Expect.equals('', uri.path);
+ Expect.equals(path, uri.toString());
+}
+
+void main() {
+ testValidIpv6Uri();
+}
+
diff --git a/tests/standalone/io/http_10_test.dart b/tests/standalone/io/http_10_test.dart
index 9250a36..d3ade02 100644
--- a/tests/standalone/io/http_10_test.dart
+++ b/tests/standalone/io/http_10_test.dart
@@ -16,7 +16,7 @@
// server sets a content length but still needs to close the
// connection as there is no keep alive.
void testHttp10NoKeepAlive() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(HttpRequest request) {
Expect.isNull(request.headers.value('content-length'));
@@ -71,7 +71,7 @@
// content length so it has to close the connection to mark the end of
// the response.
void testHttp10ServerClose() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(HttpRequest request) {
Expect.isNull(request.headers.value('content-length'));
@@ -124,7 +124,7 @@
// server sets a content length so the persistent connection can be
// used.
void testHttp10KeepAlive() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(HttpRequest request) {
Expect.isNull(request.headers.value('content-length'));
@@ -180,7 +180,7 @@
// server does not set a content length so it cannot honor connection
// keep alive.
void testHttp10KeepAliveServerCloses() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(HttpRequest request) {
Expect.isNull(request.headers.value('content-length'));
diff --git a/tests/standalone/io/http_advanced_test.dart b/tests/standalone/io/http_advanced_test.dart
index 1d4ca89..deab970 100644
--- a/tests/standalone/io/http_advanced_test.dart
+++ b/tests/standalone/io/http_advanced_test.dart
@@ -206,7 +206,7 @@
void dispatch(message, replyTo) {
if (message.isStart) {
try {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
_server = server;
_server.listen(_requestReceivedHandler);
replyTo.send(new IsolatedHttpServerStatus.started(_server.port),
diff --git a/tests/standalone/io/http_auth_test.dart b/tests/standalone/io/http_auth_test.dart
index 8871d40..f0a9733 100644
--- a/tests/standalone/io/http_auth_test.dart
+++ b/tests/standalone/io/http_auth_test.dart
@@ -16,7 +16,7 @@
Future<Server> start() {
var completer = new Completer();
- HttpServer.bind().then((s) {
+ HttpServer.bind("127.0.0.1", 0).then((s) {
server = s;
server.listen((HttpRequest request) {
var response = request.response;
diff --git a/tests/standalone/io/http_basic_test.dart b/tests/standalone/io/http_basic_test.dart
index 9ebb389..6d9caaf 100644
--- a/tests/standalone/io/http_basic_test.dart
+++ b/tests/standalone/io/http_basic_test.dart
@@ -156,7 +156,7 @@
void dispatch(var message, SendPort replyTo) {
if (message.isStart) {
try {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
_server = server;
_server.listen(_requestReceivedHandler);
replyTo.send(new TestServerStatus.started(_server.port), null);
diff --git a/tests/standalone/io/http_body_test.dart b/tests/standalone/io/http_body_test.dart
index b0f5f73..b036da2 100644
--- a/tests/standalone/io/http_body_test.dart
+++ b/tests/standalone/io/http_body_test.dart
@@ -13,7 +13,7 @@
dynamic expectedBody,
String type,
[bool shouldFail = false]) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.listen(
(_) {},
@@ -91,7 +91,7 @@
dynamic expectedBody,
String type,
[bool shouldFail = false]) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.transform(new HttpBodyHandler())
.listen((body) {
if (shouldFail) Expect.fail("Error expected");
diff --git a/tests/standalone/io/http_client_connect_test.dart b/tests/standalone/io/http_client_connect_test.dart
index 9c18e75..67ee2a5 100644
--- a/tests/standalone/io/http_client_connect_test.dart
+++ b/tests/standalone/io/http_client_connect_test.dart
@@ -13,7 +13,7 @@
import 'dart:isolate';
void testGetEmptyRequest() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.pipe(request.response);
});
@@ -30,7 +30,7 @@
}
void testGetDataRequest() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
var data = "lalala".codeUnits;
server.listen((request) {
request.response.add(data);
@@ -63,7 +63,7 @@
}
void testGetServerClose() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
server.close();
});
@@ -82,7 +82,7 @@
void testGetDataServerClose() {
var completer = new Completer();
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response.contentLength = 100;
request.response.write("data");
@@ -110,7 +110,7 @@
}
void testPostEmptyRequest() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.pipe(request.response);
});
diff --git a/tests/standalone/io/http_client_request_test.dart b/tests/standalone/io/http_client_request_test.dart
index b72551f..35d565b 100644
--- a/tests/standalone/io/http_client_request_test.dart
+++ b/tests/standalone/io/http_client_request_test.dart
@@ -8,7 +8,7 @@
import "dart:typed_data";
void testClientRequest(void handler(request)) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.listen((_) {}, onDone: () {
request.response.close();
diff --git a/tests/standalone/io/http_close_test.dart b/tests/standalone/io/http_close_test.dart
index d88f5f5..a4f8175 100644
--- a/tests/standalone/io/http_close_test.dart
+++ b/tests/standalone/io/http_close_test.dart
@@ -14,7 +14,7 @@
void testClientAndServerCloseNoListen(int connections) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
int closed = 0;
server.listen((request) {
request.response.close();
@@ -40,7 +40,7 @@
void testClientCloseServerListen(int connections) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
int closed = 0;
void check() {
closed++;
@@ -70,7 +70,7 @@
void testClientCloseSendingResponse(int connections) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
int closed = 0;
void check() {
closed++;
diff --git a/tests/standalone/io/http_compression_test.dart b/tests/standalone/io/http_compression_test.dart
index 47c2906..b5addc7 100644
--- a/tests/standalone/io/http_compression_test.dart
+++ b/tests/standalone/io/http_compression_test.dart
@@ -13,7 +13,7 @@
void testServerCompress() {
void test(List<int> data) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response.add(data);
request.response.close();
@@ -49,7 +49,7 @@
void testAcceptEncodingHeader() {
void test(String encoding, bool valid) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response.write("data");
request.response.close();
diff --git a/tests/standalone/io/http_connection_close_test.dart b/tests/standalone/io/http_connection_close_test.dart
index 5a22540..c56ef39 100644
--- a/tests/standalone/io/http_connection_close_test.dart
+++ b/tests/standalone/io/http_connection_close_test.dart
@@ -9,7 +9,7 @@
import "dart:uri";
void testHttp10Close(bool closeRequest) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response.close();
});
@@ -29,7 +29,7 @@
}
void testHttp11Close(bool closeRequest) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response.close();
});
@@ -50,7 +50,7 @@
}
void testStreamResponse() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
var timer = new Timer.periodic(const Duration(milliseconds: 0), (_) {
request.response.write(
diff --git a/tests/standalone/io/http_connection_header_test.dart b/tests/standalone/io/http_connection_header_test.dart
index 9d43624..cd37ead 100644
--- a/tests/standalone/io/http_connection_header_test.dart
+++ b/tests/standalone/io/http_connection_header_test.dart
@@ -32,7 +32,7 @@
}
void test(int totalConnections, bool clientPersistentConnection) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
// Check expected request.
Expect.equals(clientPersistentConnection, request.persistentConnection);
diff --git a/tests/standalone/io/http_content_length_test.dart b/tests/standalone/io/http_content_length_test.dart
index 4efd9af..335121d 100644
--- a/tests/standalone/io/http_content_length_test.dart
+++ b/tests/standalone/io/http_content_length_test.dart
@@ -9,7 +9,7 @@
void testNoBody(int totalConnections, bool explicitContentLength) {
var errors = 0;
- HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+ HttpServer.bind("127.0.0.1", 0, backlog: totalConnections).then((server) {
server.listen(
(HttpRequest request) {
Expect.equals("0", request.headers.value('content-length'));
@@ -75,7 +75,7 @@
}
void testBody(int totalConnections, bool useHeader) {
- HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+ HttpServer.bind("127.0.0.1", 0, backlog: totalConnections).then((server) {
int serverCount = 0;
server.listen(
(HttpRequest request) {
@@ -153,7 +153,7 @@
}
void testBodyChunked(int totalConnections, bool useHeader) {
- HttpServer.bind("127.0.0.1", 0, totalConnections).then((server) {
+ HttpServer.bind("127.0.0.1", 0, backlog: totalConnections).then((server) {
server.listen(
(HttpRequest request) {
Expect.isNull(request.headers.value('content-length'));
@@ -229,7 +229,7 @@
}
void testSetContentLength() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(HttpRequest request) {
var response = request.response;
diff --git a/tests/standalone/io/http_detach_socket_test.dart b/tests/standalone/io/http_detach_socket_test.dart
index 7d14b37..2345079 100644
--- a/tests/standalone/io/http_detach_socket_test.dart
+++ b/tests/standalone/io/http_detach_socket_test.dart
@@ -12,7 +12,7 @@
import "dart:isolate";
void testServerDetachSocket() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
var response = request.response;
response.contentLength = 0;
@@ -48,7 +48,7 @@
}
void testBadServerDetachSocket() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
var response = request.response;
response.contentLength = 0;
@@ -68,7 +68,7 @@
}
void testClientDetachSocket() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) {
socket.write("HTTP/1.1 200 OK\r\n"
"\r\n"
diff --git a/tests/standalone/io/http_head_test.dart b/tests/standalone/io/http_head_test.dart
index ea5974b..4874e47 100644
--- a/tests/standalone/io/http_head_test.dart
+++ b/tests/standalone/io/http_head_test.dart
@@ -6,7 +6,7 @@
import "dart:io";
void testHEAD(int totalConnections) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
var response = request.response;
if (request.uri.path == "/test100") {
diff --git a/tests/standalone/io/http_headers_state_test.dart b/tests/standalone/io/http_headers_state_test.dart
index db4cdc1..42e5384 100644
--- a/tests/standalone/io/http_headers_state_test.dart
+++ b/tests/standalone/io/http_headers_state_test.dart
@@ -8,7 +8,7 @@
import "dart:io";
void test(int totalConnections, [String body]) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
HttpResponse response = request.response;
diff --git a/tests/standalone/io/http_proxy_test.dart b/tests/standalone/io/http_proxy_test.dart
index 365ce29..197b11a 100644
--- a/tests/standalone/io/http_proxy_test.dart
+++ b/tests/standalone/io/http_proxy_test.dart
@@ -23,7 +23,7 @@
Future f = secure
? HttpServer.bindSecure(
"localhost", 0, certificateName: 'localhost_cert')
- : HttpServer.bind("localhost");
+ : HttpServer.bind("localhost", 0);
return f.then((s) {
server = s;
x.complete(this);
@@ -97,7 +97,7 @@
Future<ProxyServer> start() {
var x = new Completer();
- HttpServer.bind("localhost").then((s) {
+ HttpServer.bind("localhost", 0).then((s) {
server = s;
x.complete(this);
server.listen((HttpRequest request) {
diff --git a/tests/standalone/io/http_read_test.dart b/tests/standalone/io/http_read_test.dart
index e9f9cfc..e5f543e 100644
--- a/tests/standalone/io/http_read_test.dart
+++ b/tests/standalone/io/http_read_test.dart
@@ -126,7 +126,7 @@
void dispatch(message, SendPort replyTo) {
if (message.isStart) {
try {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
_server = server;
_server.listen(_requestReceivedHandler);
replyTo.send(
diff --git a/tests/standalone/io/http_redirect_test.dart b/tests/standalone/io/http_redirect_test.dart
index adcd6c3..363f8d0 100644
--- a/tests/standalone/io/http_redirect_test.dart
+++ b/tests/standalone/io/http_redirect_test.dart
@@ -10,7 +10,7 @@
Future<HttpServer> setupServer() {
Completer completer = new Completer();
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
var handlers = new Map<String, Function>();
addRequestHandler(String path, void handler(HttpRequest request,
diff --git a/tests/standalone/io/http_request_pipeling_test.dart b/tests/standalone/io/http_request_pipeling_test.dart
index 152fd15..682c592 100644
--- a/tests/standalone/io/http_request_pipeling_test.dart
+++ b/tests/standalone/io/http_request_pipeling_test.dart
@@ -14,7 +14,7 @@
void main() {
final int REQUEST_COUNT = 100;
int count = 0;
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
count++;
request.response.write(request.uri.path);
diff --git a/tests/standalone/io/http_server_early_client_close_test.dart b/tests/standalone/io/http_server_early_client_close_test.dart
index d9c0113..c4ec244 100644
--- a/tests/standalone/io/http_server_early_client_close_test.dart
+++ b/tests/standalone/io/http_server_early_client_close_test.dart
@@ -135,7 +135,7 @@
}
void testEarlyClose3() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
var subscription;
subscription = request.listen(
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
index 2df33cd..d27dcc7 100644
--- a/tests/standalone/io/http_server_response_test.dart
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -13,7 +13,7 @@
import "dart:typed_data";
void testServerRequest(void handler(server, request), {int bytes}) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
handler(server, request);
});
diff --git a/tests/standalone/io/http_server_test.dart b/tests/standalone/io/http_server_test.dart
index bd8362e..afdd819 100644
--- a/tests/standalone/io/http_server_test.dart
+++ b/tests/standalone/io/http_server_test.dart
@@ -39,7 +39,7 @@
}
// Test two connection after each other.
- ServerSocket.bind().then((s) {
+ ServerSocket.bind("127.0.0.1", 0).then((s) {
socket = s;
server = new HttpServer.listenOn(socket);
ReceivePort serverPort = new ReceivePort();
diff --git a/tests/standalone/io/http_session_test.dart b/tests/standalone/io/http_session_test.dart
index 6c9d565..4fe3d9d 100644
--- a/tests/standalone/io/http_session_test.dart
+++ b/tests/standalone/io/http_session_test.dart
@@ -37,7 +37,7 @@
void testSessions(int sessionCount) {
var client = new HttpClient();
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
var sessions = new Set();
server.listen((request) {
sessions.add(request.session.id);
@@ -67,7 +67,7 @@
void testTimeout(int sessionCount) {
var client = new HttpClient();
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.sessionTimeout = 0;
var timeouts = [];
server.listen((request) {
@@ -103,7 +103,7 @@
}
void testSessionsData() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
bool firstHit = false;
bool secondHit = false;
server.listen((request) {
@@ -150,8 +150,51 @@
});
}
+void testSessionsDestroy() {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
+ bool firstHit = false;
+ server.listen((request) {
+ var session = request.session;
+ if (session.isNew) {
+ Expect.isFalse(firstHit);
+ firstHit = true;
+ } else {
+ Expect.isTrue(firstHit);
+ session.destroy();
+ var session2 = request.session;
+ Expect.notEquals(session.id, session2.id);
+ };
+ request.response.close();
+ });
+
+ var client = new HttpClient();
+ client.get("127.0.0.1", server.port, "/")
+ .then((request) => request.close())
+ .then((response) {
+ response.listen((_) {}, onDone: () {
+ var id = getSessionId(response.cookies);
+ Expect.isNotNull(id);
+ client.get("127.0.0.1", server.port, "/")
+ .then((request) {
+ request.cookies.add(new Cookie(SESSION_ID, id));
+ return request.close();
+ })
+ .then((response) {
+ response.listen((_) {}, onDone: () {
+ Expect.isTrue(firstHit);
+ Expect.notEquals(id, getSessionId(response.cookies));
+ server.close();
+ client.close();
+ });
+ });
+ });
+ });
+ });
+}
+
void main() {
testSessions(1);
testTimeout(5);
testSessionsData();
+ testSessionsDestroy();
}
diff --git a/tests/standalone/io/http_shutdown_test.dart b/tests/standalone/io/http_shutdown_test.dart
index 1cf4803..f6b1424 100644
--- a/tests/standalone/io/http_shutdown_test.dart
+++ b/tests/standalone/io/http_shutdown_test.dart
@@ -13,7 +13,7 @@
void test1(int totalConnections) {
// Server which just closes immediately.
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
request.response.close();
});
@@ -39,7 +39,7 @@
void test2(int totalConnections, int outputStreamWrites) {
// Server which responds without waiting for request body.
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
request.response.write("!dlrow ,olleH");
request.response.close();
@@ -83,7 +83,7 @@
void test3(int totalConnections) {
// Server which responds when request body has been received.
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((HttpRequest request) {
request.listen((_) {}, onDone: () {
@@ -117,7 +117,7 @@
void test4() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((var request) {
request.listen((_) {}, onDone: () {
@@ -145,7 +145,7 @@
void test5(int totalConnections) {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen(
(request) {
request.listen(
diff --git a/tests/standalone/io/raw_secure_server_closing_test.dart b/tests/standalone/io/raw_secure_server_closing_test.dart
index 11e641b..c1b7ddc 100644
--- a/tests/standalone/io/raw_secure_server_closing_test.dart
+++ b/tests/standalone/io/raw_secure_server_closing_test.dart
@@ -24,7 +24,7 @@
.then((_) {
port.close();
});
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
server.listen((serverConnection) {
serverConnection.listen((event) {
if (toClose == "server" || event == RawSocketEvent.READ_CLOSED) {
@@ -54,7 +54,7 @@
void testCloseBothEnds() {
ReceivePort port = new ReceivePort();
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
server.listen((serverEnd) {
clientEndFuture.then((clientEnd) {
@@ -76,8 +76,8 @@
RawSecureServerSocket.bind(HOST_NAME,
0,
- 2 * socketCount,
- CERTIFICATE).then((server) {
+ CERTIFICATE,
+ backlog: 2 * socketCount).then((server) {
Expect.isTrue(server.port > 0);
var subscription;
subscription = server.listen((connection) {
@@ -116,7 +116,7 @@
ReceivePort port = new ReceivePort();
List ends = [];
- RawSecureServerSocket.bind(HOST_NAME, 0, 15, CERTIFICATE).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
Expect.isTrue(server.port > 0);
void checkDone() {
if (ends.length < 2 * socketCount) return;
diff --git a/tests/standalone/io/raw_secure_server_socket_test.dart b/tests/standalone/io/raw_secure_server_socket_test.dart
index 2ca5688..a07083b 100644
--- a/tests/standalone/io/raw_secure_server_socket_test.dart
+++ b/tests/standalone/io/raw_secure_server_socket_test.dart
@@ -17,7 +17,7 @@
void testSimpleBind() {
ReceivePort port = new ReceivePort();
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((s) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
Expect.isTrue(s.port > 0);
s.close();
port.close();
@@ -30,7 +30,7 @@
port.receive((_, __) { count++; if (count == 3) port.close(); });
// Bind to a unknown DNS name.
- RawSecureServerSocket.bind("ko.faar.__hest__", 0, 5, CERTIFICATE).then((_) {
+ RawSecureServerSocket.bind("ko.faar.__hest__", 0, CERTIFICATE).then((_) {
Expect.fail("Failure expected");
}).catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -38,7 +38,7 @@
});
// Bind to an unavaliable IP-address.
- RawSecureServerSocket.bind("8.8.8.8", 0, 5, CERTIFICATE).then((_) {
+ RawSecureServerSocket.bind("8.8.8.8", 0, CERTIFICATE).then((_) {
Expect.fail("Failure expected");
}).catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -49,10 +49,9 @@
// Either an error or a successful bind is allowed.
// Windows platforms allow multiple binding to the same socket, with
// unpredictable results.
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((s) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
RawSecureServerSocket.bind(HOST_NAME,
s.port,
- 5,
CERTIFICATE).then((t) {
Expect.equals('windows', Platform.operatingSystem);
Expect.equals(s.port, t.port);
@@ -71,7 +70,7 @@
void testSimpleConnect(String certificate) {
ReceivePort port = new ReceivePort();
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, certificate).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, certificate).then((server) {
var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
server.listen((serverEnd) {
clientEndFuture.then((clientEnd) {
@@ -86,7 +85,7 @@
void testSimpleConnectFail(String certificate) {
ReceivePort port = new ReceivePort();
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, certificate).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, certificate).then((server) {
var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port)
.then((clientEnd) {
Expect.fail("No client connection expected.");
@@ -106,7 +105,7 @@
void testServerListenAfterConnect() {
ReceivePort port = new ReceivePort();
- RawSecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ RawSecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
Expect.isTrue(server.port > 0);
var clientEndFuture = RawSecureSocket.connect(HOST_NAME, server.port);
new Timer(const Duration(milliseconds: 500), () {
@@ -430,9 +429,9 @@
if (listenSecure) {
RawSecureServerSocket.bind(
- HOST_NAME, 0, 5, CERTIFICATE).then(serverReady);
+ HOST_NAME, 0, CERTIFICATE).then(serverReady);
} else {
- RawServerSocket.bind(HOST_NAME, 0, 5).then(serverReady);
+ RawServerSocket.bind(HOST_NAME, 0).then(serverReady);
}
}
diff --git a/tests/standalone/io/raw_server_socket_cancel_test.dart b/tests/standalone/io/raw_server_socket_cancel_test.dart
index 1b9fe0d..b03b5c7 100644
--- a/tests/standalone/io/raw_server_socket_cancel_test.dart
+++ b/tests/standalone/io/raw_server_socket_cancel_test.dart
@@ -21,7 +21,7 @@
ReceivePort port = new ReceivePort();
- RawServerSocket.bind("127.0.0.1", 0, backlog).then((server) {
+ RawServerSocket.bind("127.0.0.1", 0, backlog: backlog).then((server) {
Expect.isTrue(server.port > 0);
void checkDone() {
diff --git a/tests/standalone/io/raw_socket_test.dart b/tests/standalone/io/raw_socket_test.dart
index 23fc6a5..ed5c494 100644
--- a/tests/standalone/io/raw_socket_test.dart
+++ b/tests/standalone/io/raw_socket_test.dart
@@ -15,12 +15,12 @@
void testArguments() {
Expect.throws(() => RawServerSocket.bind("127.0.0.1", 65536));
Expect.throws(() => RawServerSocket.bind("127.0.0.1", -1));
- Expect.throws(() => RawServerSocket.bind("127.0.0.1", 0, -1));
+ Expect.throws(() => RawServerSocket.bind("127.0.0.1", 0, backlog: -1));
}
void testSimpleBind() {
ReceivePort port = new ReceivePort();
- RawServerSocket.bind().then((s) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((s) {
Expect.isTrue(s.port > 0);
port.close();
});
@@ -32,7 +32,7 @@
port.receive((_, __) { count++; if (count == 3) port.close(); });
// Bind to a unknown DNS name.
- RawServerSocket.bind("ko.faar.__hest__")
+ RawServerSocket.bind("ko.faar.__hest__", 0)
.then((_) { Expect.fail("Failure expected"); } )
.catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -40,7 +40,7 @@
});
// Bind to an unavaliable IP-address.
- RawServerSocket.bind("8.8.8.8")
+ RawServerSocket.bind("8.8.8.8", 0)
.then((_) { Expect.fail("Failure expected"); } )
.catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -51,9 +51,9 @@
// Either an error or a successful bind is allowed.
// Windows platforms allow multiple binding to the same socket, with
// unpredictable results.
- RawServerSocket.bind("127.0.0.1")
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0)
.then((s) {
- RawServerSocket.bind("127.0.0.1", s.port)
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, s.port)
.then((t) {
Expect.equals('windows', Platform.operatingSystem);
Expect.equals(s.port, t.port);
@@ -69,7 +69,7 @@
void testSimpleConnect() {
ReceivePort port = new ReceivePort();
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((_) { });
RawSocket.connect("127.0.0.1", server.port).then((_) {
server.close();
@@ -87,7 +87,7 @@
.then((_) {
port.close();
});
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((serverConnection) {
serverConnection.listen((event) {
if (toClose == "server" || event == RawSocketEvent.READ_CLOSED) {
@@ -117,7 +117,7 @@
void testServerListenAfterConnect() {
ReceivePort port = new ReceivePort();
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
Expect.isTrue(server.port > 0);
RawSocket.connect("127.0.0.1", server.port).then((_) {
server.listen((_) {
@@ -153,7 +153,7 @@
}
}
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((client) {
int bytesRead = 0;
int bytesWritten = 0;
@@ -235,7 +235,7 @@
ReceivePort port = new ReceivePort();
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
Expect.isTrue(server.port > 0);
var subscription = server.listen((_) {
Expect.isTrue(resumed);
@@ -276,7 +276,7 @@
ReceivePort port = new ReceivePort();
- RawServerSocket.bind().then((server) {
+ RawServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
Expect.isTrue(server.port > 0);
server.listen((client) {
List<int> data = new List<int>.filled(messageSize, 0);
diff --git a/tests/standalone/io/raw_socket_write_destroy_test.dart b/tests/standalone/io/raw_socket_write_destroy_test.dart
index 13ecaf3..b5eed7c 100644
--- a/tests/standalone/io/raw_socket_write_destroy_test.dart
+++ b/tests/standalone/io/raw_socket_write_destroy_test.dart
@@ -15,7 +15,7 @@
void testWriteDestroyServer() {
int WROTE = 100000;
- RawServerSocket.bind(SERVER_ADDRESS).then((server) {
+ RawServerSocket.bind(SERVER_ADDRESS, 0).then((server) {
server.listen((socket) {
socket.writeEventsEnabled = false;
@@ -54,7 +54,7 @@
void testWriteDestroyClient() {
int WROTE = 100000;
- RawServerSocket.bind(SERVER_ADDRESS).then((server) {
+ RawServerSocket.bind(SERVER_ADDRESS, 0).then((server) {
server.listen((socket) {
var bytes = 0;
socket.listen((e) {
diff --git a/tests/standalone/io/regress_8828_test.dart b/tests/standalone/io/regress_8828_test.dart
index 7842be5..c33a56d 100644
--- a/tests/standalone/io/regress_8828_test.dart
+++ b/tests/standalone/io/regress_8828_test.dart
@@ -11,7 +11,7 @@
import 'dart:io';
void main() {
- HttpServer.bind().then((server) {
+ HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
request.response
..writeln("first line")
diff --git a/tests/standalone/io/secure_client_raw_server_test.dart b/tests/standalone/io/secure_client_raw_server_test.dart
index e72036a..1fce350 100644
--- a/tests/standalone/io/secure_client_raw_server_test.dart
+++ b/tests/standalone/io/secure_client_raw_server_test.dart
@@ -17,7 +17,6 @@
Future<RawSecureServerSocket> startEchoServer() {
return RawSecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE).then((server) {
server.listen((RawSecureSocket client) {
List<List<int>> readChunks = <List<int>>[];
diff --git a/tests/standalone/io/secure_client_server_test.dart b/tests/standalone/io/secure_client_server_test.dart
index 494d54c..11cf433 100644
--- a/tests/standalone/io/secure_client_server_test.dart
+++ b/tests/standalone/io/secure_client_server_test.dart
@@ -17,7 +17,6 @@
Future<SecureServerSocket> startEchoServer() {
return SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE).then((server) {
server.listen((SecureSocket client) {
client.fold(<int>[], (message, data) => message..addAll(data))
diff --git a/tests/standalone/io/secure_multiple_client_server_test.dart b/tests/standalone/io/secure_multiple_client_server_test.dart
index 69dfb92..e0e91e4 100644
--- a/tests/standalone/io/secure_multiple_client_server_test.dart
+++ b/tests/standalone/io/secure_multiple_client_server_test.dart
@@ -17,7 +17,6 @@
Future<SecureServerSocket> startServer() {
return SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE).then((server) {
server.listen((SecureSocket client) {
client.fold(<int>[], (message, data) => message..addAll(data))
diff --git a/tests/standalone/io/secure_server_client_certificate_test.dart b/tests/standalone/io/secure_server_client_certificate_test.dart
index 4edabef..35475e2 100644
--- a/tests/standalone/io/secure_server_client_certificate_test.dart
+++ b/tests/standalone/io/secure_server_client_certificate_test.dart
@@ -14,7 +14,6 @@
ReceivePort port = new ReceivePort();
SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE,
requestClientCertificate: true).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME,
@@ -43,7 +42,6 @@
ReceivePort port = new ReceivePort();
SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE,
requireClientCertificate: true).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME,
@@ -72,7 +70,6 @@
ReceivePort port = new ReceivePort();
SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE,
requestClientCertificate: true).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME,
@@ -95,7 +92,6 @@
bool clientError = false;
SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE,
requireClientCertificate: true).then((server) {
Future clientDone = SecureSocket.connect(HOST_NAME, server.port)
diff --git a/tests/standalone/io/secure_server_closing_test.dart b/tests/standalone/io/secure_server_closing_test.dart
index 2e0bd4b..0d27cb2 100644
--- a/tests/standalone/io/secure_server_closing_test.dart
+++ b/tests/standalone/io/secure_server_closing_test.dart
@@ -24,7 +24,7 @@
.then((_) {
port.close();
});
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
server.listen((serverConnection) {
serverConnection.listen(
(data) {
@@ -60,7 +60,7 @@
void testCloseBothEnds() {
ReceivePort port = new ReceivePort();
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
server.listen((serverEnd) {
clientEndFuture.then((clientEnd) {
@@ -82,8 +82,8 @@
SecureServerSocket.bind(HOST_NAME,
0,
- 2 * socketCount,
- CERTIFICATE).then((server) {
+ CERTIFICATE,
+ backlog: 2 * socketCount).then((server) {
Expect.isTrue(server.port > 0);
var subscription;
subscription = server.listen((connection) {
@@ -124,7 +124,7 @@
ReceivePort port = new ReceivePort();
List ends = [];
- SecureServerSocket.bind(HOST_NAME, 0, 15, CERTIFICATE).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
Expect.isTrue(server.port > 0);
void checkDone() {
if (ends.length < 2 * socketCount) return;
diff --git a/tests/standalone/io/secure_server_socket_test.dart b/tests/standalone/io/secure_server_socket_test.dart
index bf1bc05..478a53a 100644
--- a/tests/standalone/io/secure_server_socket_test.dart
+++ b/tests/standalone/io/secure_server_socket_test.dart
@@ -17,7 +17,7 @@
void testSimpleBind() {
ReceivePort port = new ReceivePort();
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((s) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
Expect.isTrue(s.port > 0);
s.close();
port.close();
@@ -30,7 +30,7 @@
port.receive((_, __) { count++; if (count == 3) port.close(); });
// Bind to a unknown DNS name.
- SecureServerSocket.bind("ko.faar.__hest__", 0, 5, CERTIFICATE).then((_) {
+ SecureServerSocket.bind("ko.faar.__hest__", 0, CERTIFICATE).then((_) {
Expect.fail("Failure expected");
}).catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -38,7 +38,7 @@
});
// Bind to an unavaliable IP-address.
- SecureServerSocket.bind("8.8.8.8", 0, 5, CERTIFICATE).then((_) {
+ SecureServerSocket.bind("8.8.8.8", 0, CERTIFICATE).then((_) {
Expect.fail("Failure expected");
}).catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -49,10 +49,9 @@
// Either an error or a successful bind is allowed.
// Windows platforms allow multiple binding to the same socket, with
// unpredictable results.
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((s) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((s) {
SecureServerSocket.bind(HOST_NAME,
s.port,
- 5,
CERTIFICATE).then((t) {
Expect.equals('windows', Platform.operatingSystem);
Expect.equals(s.port, t.port);
@@ -70,7 +69,7 @@
void testSimpleConnect(String certificate) {
ReceivePort port = new ReceivePort();
- SecureServerSocket.bind(HOST_NAME, 0, 5, certificate).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, certificate).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
server.listen((serverEnd) {
clientEndFuture.then((clientEnd) {
@@ -85,7 +84,7 @@
void testSimpleConnectFail(String certificate) {
ReceivePort port = new ReceivePort();
- SecureServerSocket.bind(HOST_NAME, 0, 5, certificate).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, certificate).then((server) {
var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port)
.then((clientEnd) {
Expect.fail("No client connection expected.");
@@ -105,7 +104,7 @@
void testServerListenAfterConnect() {
ReceivePort port = new ReceivePort();
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
Expect.isTrue(server.port > 0);
var clientEndFuture = SecureSocket.connect(HOST_NAME, server.port);
new Timer(const Duration(milliseconds: 500), () {
@@ -146,7 +145,7 @@
}
}
- SecureServerSocket.bind(HOST_NAME, 0, 5, CERTIFICATE).then((server) {
+ SecureServerSocket.bind(HOST_NAME, 0, CERTIFICATE).then((server) {
server.listen((client) {
int bytesRead = 0;
int bytesWritten = 0;
diff --git a/tests/standalone/io/secure_session_resume_test.dart b/tests/standalone/io/secure_session_resume_test.dart
index 532dcec..17873e8 100644
--- a/tests/standalone/io/secure_session_resume_test.dart
+++ b/tests/standalone/io/secure_session_resume_test.dart
@@ -26,7 +26,6 @@
Future<SecureServerSocket> startServer() {
return SecureServerSocket.bind(HOST_NAME,
0,
- 5,
CERTIFICATE).then((server) {
server.listen((SecureSocket client) {
client.fold(<int>[], (message, data) => message..addAll(data))
diff --git a/tests/standalone/io/socket_close_test.dart b/tests/standalone/io/socket_close_test.dart
index 791c679..d89c798 100644
--- a/tests/standalone/io/socket_close_test.dart
+++ b/tests/standalone/io/socket_close_test.dart
@@ -339,7 +339,7 @@
_closeEvents = 0;
_iterations = 0;
_mode = message;
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
_server = server;
_server.listen(
(socket) {
diff --git a/tests/standalone/io/socket_exception_test.dart b/tests/standalone/io/socket_exception_test.dart
index 4713c74c..79f5b72 100644
--- a/tests/standalone/io/socket_exception_test.dart
+++ b/tests/standalone/io/socket_exception_test.dart
@@ -15,7 +15,7 @@
bool exceptionCaught = false;
bool wrongExceptionCaught = false;
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Expect.isNotNull(server);
server.close();
try {
@@ -29,7 +29,7 @@
Expect.equals(true, !wrongExceptionCaught);
// Test invalid host.
- ServerSocket.bind("__INVALID_HOST__")
+ ServerSocket.bind("__INVALID_HOST__", 0)
.then((server) { })
.catchError((e) => e is SocketIOException);
});
@@ -37,7 +37,7 @@
static void serverSocketCloseListenTest() {
var port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Socket.connect("127.0.0.1", server.port).then((socket) {
server.close();
server.listen(
@@ -49,7 +49,7 @@
static void serverSocketListenCloseTest() {
var port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Socket.connect("127.0.0.1", server.port).then((socket) {
server.listen(
(incoming) => server.close(),
@@ -62,7 +62,7 @@
bool exceptionCaught = false;
bool wrongExceptionCaught = false;
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Expect.isNotNull(server);
int port = server.port;
Socket.connect("127.0.0.1", port).then((client) {
@@ -104,7 +104,7 @@
}
static void clientSocketDestroyNoErrorTest() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) {
socket.pipe(socket);
});
@@ -116,7 +116,7 @@
}
static void clientSocketAddDestroyNoErrorTest() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) {
// Passive block data by not sobscribing to socket.
});
@@ -129,7 +129,7 @@
}
static void clientSocketAddCloseNoErrorTest() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
var completer = new Completer();
server.listen((socket) {
// The socket is 'paused' until the future completes.
@@ -153,7 +153,7 @@
}
static void clientSocketAddCloseErrorTest() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
var completer = new Completer();
server.listen((socket) {
completer.future.then((_) => socket.destroy());
@@ -192,7 +192,7 @@
}
static void clientSocketAddCloseResultErrorTest() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
var completer = new Completer();
server.listen((socket) {
completer.future.then((_) => socket.destroy());
diff --git a/tests/standalone/io/socket_info_test.dart b/tests/standalone/io/socket_info_test.dart
index f626d66..395b6e4 100644
--- a/tests/standalone/io/socket_info_test.dart
+++ b/tests/standalone/io/socket_info_test.dart
@@ -6,7 +6,7 @@
import "dart:io";
void testHostAndPort() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Socket.connect("127.0.0.1", server.port).then((clientSocket) {
server.listen((socket) {
diff --git a/tests/standalone/io/socket_invalid_arguments_test.dart b/tests/standalone/io/socket_invalid_arguments_test.dart
index 61d526d..e3b8714 100644
--- a/tests/standalone/io/socket_invalid_arguments_test.dart
+++ b/tests/standalone/io/socket_invalid_arguments_test.dart
@@ -25,7 +25,7 @@
}
testAdd(buffer) {
- ServerSocket.bind("127.0.0.1", 0, 5).then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) => socket.destroy());
Socket.connect("127.0.0.1", server.port).then((socket) {
int errors = 0;
@@ -49,7 +49,7 @@
var server;
var port = new ReceivePort();
try {
- ServerSocket.bind(address, port, backlog)
+ ServerSocket.bind(address, port, backlog: backlog)
.then((_) { Expect.fail("ServerSocket bound"); });
} catch (e) {
port.close();
diff --git a/tests/standalone/io/socket_ipv6_test.dart b/tests/standalone/io/socket_ipv6_test.dart
index 032bd9c..d483b8e 100644
--- a/tests/standalone/io/socket_ipv6_test.dart
+++ b/tests/standalone/io/socket_ipv6_test.dart
@@ -10,7 +10,7 @@
void testIPv6toIPv6() {
InternetAddress.lookup("::0", type: ANY).then((serverAddr) {
InternetAddress.lookup("::1", type: ANY).then((clientAddr) {
- ServerSocket.bind(serverAddr.first).then((server) {
+ ServerSocket.bind(serverAddr.first, 0).then((server) {
server.listen((socket) {
socket.destroy();
server.close();
@@ -25,7 +25,7 @@
void testIPv4toIPv6() {
InternetAddress.lookup("::0", type: ANY).then((serverAddr) {
- ServerSocket.bind(serverAddr.first).then((server) {
+ ServerSocket.bind(serverAddr.first, 0).then((server) {
server.listen((socket) {
socket.destroy();
server.close();
@@ -39,7 +39,7 @@
void testIPv6toIPv4() {
InternetAddress.lookup("::1", type: ANY).then((clientAddr) {
- ServerSocket.bind("127.0.0.1").then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) {
throw "Unexpected socket";
});
@@ -51,7 +51,7 @@
}
void testIPv4toIPv4() {
- ServerSocket.bind("127.0.0.1").then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
server.listen((socket) {
socket.destroy();
server.close();
@@ -88,6 +88,21 @@
});
}
+void testIPv4toIPv6_IPV6Only() {
+ InternetAddress.lookup("::0", type: ANY)
+ .then((serverAddr) {
+ ServerSocket.bind(serverAddr.first, 0, v6Only: true)
+ .then((server) {
+ server.listen((socket) {
+ throw "Unexpcted socket";
+ });
+ Socket.connect("127.0.0.1", server.port).catchError((error) {
+ server.close();
+ });
+ });
+ });
+}
+
void main() {
testIPv6toIPv6();
testIPv4toIPv6();
@@ -95,4 +110,6 @@
testIPv4toIPv4();
testIPv6Lookup();
testIPv4Lookup();
+
+ testIPv4toIPv6_IPV6Only();
}
diff --git a/tests/standalone/io/socket_port_test.dart b/tests/standalone/io/socket_port_test.dart
index d3c0179..d9c75d7 100644
--- a/tests/standalone/io/socket_port_test.dart
+++ b/tests/standalone/io/socket_port_test.dart
@@ -6,7 +6,7 @@
import "dart:io";
void testPort() {
- ServerSocket.bind().then((server) {
+ ServerSocket.bind("127.0.0.1", 0).then((server) {
Socket.connect("127.0.0.1", server.port).then((clientSocket) {
server.listen((Socket socket) {
Expect.equals(socket.port, server.port);
diff --git a/tests/standalone/io/socket_test.dart b/tests/standalone/io/socket_test.dart
index 1385b67..e9f2077 100644
--- a/tests/standalone/io/socket_test.dart
+++ b/tests/standalone/io/socket_test.dart
@@ -15,12 +15,12 @@
void testArguments() {
Expect.throws(() => ServerSocket.bind("127.0.0.1", 65536));
Expect.throws(() => ServerSocket.bind("127.0.0.1", -1));
- Expect.throws(() => ServerSocket.bind("127.0.0.1", 0, -1));
+ Expect.throws(() => ServerSocket.bind("127.0.0.1", 0, backlog: -1));
}
void testSimpleBind() {
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((s) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((s) {
Expect.isTrue(s.port > 0);
port.close();
});
@@ -32,7 +32,7 @@
port.receive((_, __) { count++; if (count == 3) port.close(); });
// Bind to a unknown DNS name.
- ServerSocket.bind("ko.faar.__hest__")
+ ServerSocket.bind("ko.faar.__hest__", 0)
.then((_) { Expect.fail("Failure expected"); } )
.catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -40,7 +40,7 @@
});
// Bind to an unavaliable IP-address.
- ServerSocket.bind("8.8.8.8")
+ ServerSocket.bind("8.8.8.8", 0)
.then((_) { Expect.fail("Failure expected"); } )
.catchError((error) {
Expect.isTrue(error is SocketIOException);
@@ -51,7 +51,7 @@
// Either an error or a successful bind is allowed.
// Windows platforms allow multiple binding to the same socket, with
// unpredictable results.
- ServerSocket.bind("127.0.0.1")
+ ServerSocket.bind("127.0.0.1", 0)
.then((s) {
ServerSocket.bind("127.0.0.1", s.port)
.then((t) {
@@ -69,7 +69,7 @@
void testConnectNoDestroy() {
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((_) { });
Socket.connect("127.0.0.1", server.port).then((_) {
server.close();
@@ -80,7 +80,7 @@
void testConnectImmediateDestroy() {
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((_) { });
Socket.connect("127.0.0.1", server.port).then((socket) {
socket.destroy();
@@ -94,7 +94,7 @@
// Connect socket then immediate close the consumer without
// listening on the stream.
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((_) { });
Socket.connect("127.0.0.1", server.port).then((socket) {
socket.close();
@@ -111,7 +111,7 @@
// Connect socket write some data immediate close the consumer
// without listening on the stream.
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((_) { });
Socket.connect("127.0.0.1", server.port).then((socket) {
socket.add([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
@@ -129,7 +129,7 @@
// Connect socket and listen on the stream. The server closes
// immediately so only a done event is received.
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen((client) {
client.close();
client.done.then((_) => client.destroy());
@@ -153,7 +153,7 @@
// and then closes so both data and a done event is received.
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen(
(client) {
client.add(sendData);
@@ -184,7 +184,7 @@
void testConnectStreamDataCloseCancel(bool useDestroy) {
List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
ReceivePort port = new ReceivePort();
- ServerSocket.bind().then((server) {
+ ServerSocket.bind(InternetAddress.LOOPBACK_IP_V4, 0).then((server) {
server.listen(
(client) {
client.add(sendData);
diff --git a/tests/standalone/io/socket_upgrade_to_secure_test.dart b/tests/standalone/io/socket_upgrade_to_secure_test.dart
index d4448ca..4cf55c8 100644
--- a/tests/standalone/io/socket_upgrade_to_secure_test.dart
+++ b/tests/standalone/io/socket_upgrade_to_secure_test.dart
@@ -12,7 +12,6 @@
import "dart:io";
import "dart:isolate";
-const HOST_IP = "127.0.0.1";
const HOST_NAME = "localhost";
const CERTIFICATE = "localhost_cert";
@@ -152,9 +151,8 @@
}
Future<SecureSocket> connectClient(int port) {
- var host = hostnameInConnect ? HOST_NAME : HOST_IP;
if (!handshakeBeforeSecure) {
- return Socket.connect(host, port).then((socket) {
+ return Socket.connect(HOST_NAME, port).then((socket) {
var future;
if (hostnameInConnect) {
future = SecureSocket.secure(socket);
@@ -167,7 +165,7 @@
});
});
} else {
- return Socket.connect(host, port).then((socket) {
+ return Socket.connect(HOST_NAME, port).then((socket) {
return runClientHandshake(socket).then((_) {
var future;
if (hostnameInConnect) {
@@ -209,7 +207,7 @@
});
}
- ServerSocket.bind(HOST_NAME, 0, 5).then(serverReady);
+ ServerSocket.bind(HOST_NAME, 0).then(serverReady);
}
main() {
diff --git a/tests/standalone/io/testing_server.dart b/tests/standalone/io/testing_server.dart
index 79f0175..c8bd2b6 100644
--- a/tests/standalone/io/testing_server.dart
+++ b/tests/standalone/io/testing_server.dart
@@ -21,7 +21,7 @@
void dispatch(message, SendPort replyTo) {
if (message == INIT) {
- ServerSocket.bind(HOST, 0, 10).then((server) {
+ ServerSocket.bind(HOST, 0).then((server) {
_server = server;
_server.listen(
onConnection,
diff --git a/tests/standalone/io/web_socket_test.dart b/tests/standalone/io/web_socket_test.dart
index 5579e8f..4e5df10 100644
--- a/tests/standalone/io/web_socket_test.dart
+++ b/tests/standalone/io/web_socket_test.dart
@@ -32,7 +32,7 @@
certificateName: CERT_NAME)
: HttpServer.bind(HOST_NAME,
0,
- backlog);
+ backlog: backlog);
Future<WebSocket> createClient(int port) =>
WebSocket.connect('${secure ? "wss" : "ws"}://$HOST_NAME:$port/');
@@ -365,7 +365,7 @@
onDone: completer.complete);
});
- futures.add(client.openUrl("GET", new Uri.fromString('${baseHttpUrl}'))
+ futures.add(client.openUrl("GET", Uri.parse('${baseHttpUrl}'))
.then((request) => request.close())
.then((response) {
response.listen((_) { });
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 37eae94..f342f31 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -5,8 +5,11 @@
package/invalid_uri_test: Fail, OK # Fails intentionally
[ $runtime == vm ]
-io/test_runner_test: Fail # Fails because checked-in dart executable is not up to date.
-io/skipping_dart2js_compilations_test: Fail # Fails because checked-in dart executable is not up to date.
+# Fails because checked-in dart executable is not up to date.
+io/test_runner_test: Fail
+# Fails because checked-in dart executable is not up to date.
+# Skip this because it is leaving temp directories behind when it fails.
+io/skipping_dart2js_compilations_test: Skip
[ $runtime == vm && ( $system == windows ) ]
io/raw_socket_test: Pass, Fail # Issue 8901
diff --git a/tools/VERSION b/tools/VERSION
index 699b05f..8b16f58 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 5
-BUILD 3
+BUILD 4
PATCH 0
diff --git a/tools/dom/scripts/htmldartgenerator.py b/tools/dom/scripts/htmldartgenerator.py
index 6ecb34e..fb116d1 100644
--- a/tools/dom/scripts/htmldartgenerator.py
+++ b/tools/dom/scripts/htmldartgenerator.py
@@ -147,7 +147,7 @@
dom_name = DartDomNameOfAttribute(attribute)
attr_name = self._renamer.RenameMember(
self._interface.id, attribute, dom_name, 'get:')
- if not attr_name or self._IsPrivate(attr_name):
+ if not attr_name:
return
html_setter_name = self._renamer.RenameMember(
@@ -597,6 +597,3 @@
def _DartType(self, type_name):
return self._type_registry.DartType(type_name)
-
- def _IsPrivate(self, name):
- return name.startswith('_')
diff --git a/tools/dom/scripts/idlrenderer.py b/tools/dom/scripts/idlrenderer.py
index 7c5d634..3c71ff8 100755
--- a/tools/dom/scripts/idlrenderer.py
+++ b/tools/dom/scripts/idlrenderer.py
@@ -179,7 +179,10 @@
wsp(node.ext_attrs)
if (node.optional):
w('optional ')
- w('%s %s' % (node.type.id, node.id))
+ w(node.type.id)
+ if node.type.nullable:
+ w('?')
+ w(' %s' % node.id)
else:
raise TypeError("Expected str or IDLNode but %s found" %
type(node))
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 130c933..bbd9be3 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -738,6 +738,9 @@
if argument.ext_attrs.get('TreatNullAs') == 'NullString':
return True
+ if argument.type.nullable:
+ return True
+
if isinstance(argument, IDLArgument):
if IsOptional(argument) and not self._IsArgumentOptionalInWebCore(node, argument):
return True
diff --git a/tools/dom/src/dartium_KeyEvent.dart b/tools/dom/src/dartium_KeyEvent.dart
index 6f2cd78..b627b9c 100644
--- a/tools/dom/src/dartium_KeyEvent.dart
+++ b/tools/dom/src/dartium_KeyEvent.dart
@@ -10,6 +10,8 @@
* on how we can make this class work with as many international keyboards as
* possible. Bugs welcome!
*/
+part of html;
+
class KeyEvent extends _WrappedEvent implements KeyboardEvent {
/** The parent KeyboardEvent that this KeyEvent is wrapping and "fixing". */
KeyboardEvent _parent;
diff --git a/tools/gyp/all.gypi b/tools/gyp/all.gypi
index 2d056e8..1e6b313 100644
--- a/tools/gyp/all.gypi
+++ b/tools/gyp/all.gypi
@@ -3,14 +3,13 @@
# BSD-style license that can be found in the LICENSE file.
# A set of variables needed to build some of the Chrome based subparts of the
-# Dart project (e.g. V8). This is in no way a complete list of variables being
-# defined by Chrome, but just the minimally needed subset.
+# Dart project. This is in no way a complete list of variables being defined
+# by Chrome, but just the minimally needed subset.
{
'variables': {
'library': 'static_library',
'component': 'static_library',
'target_arch': 'ia32',
- 'v8_location': '<(DEPTH)/third_party/v8',
# Flag that tells us whether to build native support for dart:io.
'dart_io_support': 1,
},
diff --git a/tools/gyp/common.gypi b/tools/gyp/common.gypi
index 3988dfb..e7ac207 100644
--- a/tools/gyp/common.gypi
+++ b/tools/gyp/common.gypi
@@ -3,8 +3,8 @@
# BSD-style license that can be found in the LICENSE file.
# A set of variables needed to build some of the Chrome based subparts of the
-# Dash project (e.g. V8). This is in no way a complete list of variables being
-# defined by Chrome, but just the minimally needed subset.
+# Dash project. This is in no way a complete list of variables being defined
+# by Chrome, but just the minimally needed subset.
# Note: this file is similar to all.gypi, but is used when running gyp
# from subproject directories. This is deprecated, but still supported.
@@ -13,7 +13,6 @@
'library': 'static_library',
'component': 'static_library',
'target_arch': 'ia32',
- 'v8_location': '<(DEPTH)/../third_party/v8',
# Flag that tells us whether to build native support for dart:io.
'dart_io_support': 1,
},
diff --git a/tools/gyp/configurations.gypi b/tools/gyp/configurations.gypi
index f717f76..f6b1ed0 100644
--- a/tools/gyp/configurations.gypi
+++ b/tools/gyp/configurations.gypi
@@ -8,16 +8,11 @@
'-Wall',
'-Wextra', # Also known as -W.
'-Wno-unused-parameter',
- # TODO(v8-team): Fix V8 build.
- #'-Wold-style-cast',
],
# Default value. This may be overridden in a containing project gyp.
'target_arch%': 'ia32',
- # Don't use separate host toolset for compiling V8.
- 'want_separate_host_toolset': 0,
-
'conditions': [
['"<(target_arch)"=="ia32"', { 'dart_target_arch': 'IA32', }],
['"<(target_arch)"=="x64"', { 'dart_target_arch': 'X64', }],
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index a2b9e8a..abced4d 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -17,8 +17,7 @@
'-Wnon-virtual-dtor',
'-Wvla',
'-Wno-conversion-null',
- # TODO(v8-team): Fix V8 build.
- #'-Woverloaded-virtual',
+ '-Woverloaded-virtual',
'-g3',
'-ggdb3',
# TODO(iposva): Figure out if we need to pass anything else.
diff --git a/tools/gyp/configurations_xcode.gypi b/tools/gyp/configurations_xcode.gypi
index 9098beb..791a104 100644
--- a/tools/gyp/configurations_xcode.gypi
+++ b/tools/gyp/configurations_xcode.gypi
@@ -4,8 +4,7 @@
# The purpose of this file and others in this directory is to simulate
# the Chromium build enviroment. This file is included in all GYP
-# files that are used by the Dart project. This includes V8's GYP
-# files.
+# files that are used by the Dart project.
# READ BEFORE EDITING:
# Do not add Dart VM specific configuration to this file. Instead,
diff --git a/tools/gyp/find_mac_gcc_version.py b/tools/gyp/find_mac_gcc_version.py
index 0af8412..1f136dd 100755
--- a/tools/gyp/find_mac_gcc_version.py
+++ b/tools/gyp/find_mac_gcc_version.py
@@ -21,10 +21,13 @@
major = int(matches[0][0])
minor = int(matches[0][1])
- if major >= 4:
- return 'com.apple.compilers.llvmgcc42'
- elif major == 3 and minor >= 1:
+ if major == 3 and minor >= 1:
return '4.2'
+ elif major == 4 and minor < 5:
+ return 'com.apple.compilers.llvmgcc42'
+ elif major == 4 and minor >= 5:
+ # XCode seems to select the specific clang version automatically
+ return 'com.apple.compilers.llvm.clang.1_0'
else:
raise Exception('Unknown XCode Version "%s"' % version_match)
else:
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index 659fef5..0c6b7a7 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -128,6 +128,15 @@
return output;
}
+String _buildSummaryEnd(int failedTests) {
+ if (failedTests == 0) {
+ return '\n===\n=== All tests succeeded\n===\n';
+ } else {
+ var pluralSuffix = failedTests != 1 ? 's' : '';
+ return '\n===\n=== ${failedTests} test$pluralSuffix failed\n===\n';
+ }
+}
+
class EventListener {
void testAdded() { }
@@ -324,12 +333,14 @@
bool _printSummary;
var _formatter;
var _failureSummary = <String>[];
+ var _failedTests= 0;
TestFailurePrinter(this._printSummary,
[this._formatter = const Formatter()]);
void done(TestCase test) {
if (test.lastCommandOutput.unexpectedOutput) {
+ _failedTests++;
var lines = _buildFailureOutput(test, _formatter);
for (var line in lines) {
print(line);
@@ -350,6 +361,8 @@
print(line);
}
print('');
+
+ print(_buildSummaryEnd(_failedTests));
}
}
}
@@ -397,28 +410,9 @@
_allTestsKnown = true;
}
- void allDone() {
- _printStatus();
- }
-
void _printStartProgress(TestCase test) {}
void _printDoneProgress(TestCase test) {}
- void _printStatus() {
- if (_failedTests == 0) {
- print('\n===');
- print('=== All tests succeeded');
- print('===\n');
- } else {
- var pluralSuffix = _failedTests != 1 ? 's' : '';
- print('\n===');
- print('=== ${_failedTests} test$pluralSuffix failed');
- print('===\n');
- }
- }
-
- int get numFailedTests => _failedTests;
-
int _completedTests() => _passedTests + _failedTests;
int _foundTests = 0;
@@ -521,6 +515,6 @@
}
print('');
}
- super.allDone();
+ print(_buildSummaryEnd(_failedTests));
}
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index e888996..ea8877b 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -188,16 +188,6 @@
}
}
- /**
- * The file name of the d8 executable.
- */
- String get d8FileName {
- var suffix = getExecutableSuffix('d8');
- var d8 = '$buildDir/d8$suffix';
- TestUtils.ensureExists(d8, configuration);
- return d8;
- }
-
String get dartShellFileName {
var name = configuration['dart'];
if (name == '') {
@@ -208,6 +198,14 @@
return name;
}
+ String get d8FileName {
+ var suffix = getExecutableSuffix('d8');
+ var d8Dir = '${TestUtils.dartDir()}/third_party/d8';
+ var d8 = '$d8Dir/${Platform.operatingSystem}/d8$suffix';
+ TestUtils.ensureExists(d8, configuration);
+ return d8;
+ }
+
String get jsShellFileName {
var executableSuffix = getExecutableSuffix('jsshell');
var executable = 'jsshell$executableSuffix';
diff --git a/utils/tests/testrunner/http_client_tests/http_client_test.dart b/utils/tests/testrunner/http_client_tests/http_client_test.dart
index b43b4c1..b46745a 100644
--- a/utils/tests/testrunner/http_client_tests/http_client_test.dart
+++ b/utils/tests/testrunner/http_client_tests/http_client_test.dart
@@ -13,7 +13,7 @@
var get = (String what, int code, String text) {
var c = new Completer();
HttpClient client = new HttpClient();
- client.getUrl(new Uri.fromString("http://127.0.0.1:3456/$what"))
+ client.getUrl(Uri.parse("http://127.0.0.1:3456/$what"))
.then((HttpClientRequest request) {
// Prepare the request then call close on it to send it.
return request.close();