Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(330)

Side by Side Diff: runtime/bin/socket.cc

Issue 2791423002: [dart:io] Don't close stdin with a socket finalizer (Closed)
Patch Set: Windows 7 fix Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #if !defined(DART_IO_DISABLED) 5 #if !defined(DART_IO_DISABLED)
6 6
7 #include "bin/socket.h" 7 #include "bin/socket.h"
8 8
9 #include "bin/dartutils.h" 9 #include "bin/dartutils.h"
10 #include "bin/eventhandler.h" 10 #include "bin/eventhandler.h"
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 // created the socket. We therefore increment the refcount and reuse 140 // created the socket. We therefore increment the refcount and reuse
141 // the file descriptor. 141 // the file descriptor.
142 os_socket->ref_count++; 142 os_socket->ref_count++;
143 143
144 // The same Socket is used by a second Dart _NativeSocket object. 144 // The same Socket is used by a second Dart _NativeSocket object.
145 // It Retains a reference. 145 // It Retains a reference.
146 os_socket->socketfd->Retain(); 146 os_socket->socketfd->Retain();
147 // We set as a side-effect the file descriptor on the dart 147 // We set as a side-effect the file descriptor on the dart
148 // socket_object. 148 // socket_object.
149 Socket::ReuseSocketIdNativeField(socket_object, os_socket->socketfd, 149 Socket::ReuseSocketIdNativeField(socket_object, os_socket->socketfd,
150 true); 150 Socket::kFinalizerListening);
151 151
152 return Dart_True(); 152 return Dart_True();
153 } 153 }
154 } 154 }
155 } 155 }
156 156
157 // There is no socket listening on that (address, port), so we create new one. 157 // There is no socket listening on that (address, port), so we create new one.
158 intptr_t fd = ServerSocket::CreateBindListen(addr, backlog, v6_only); 158 intptr_t fd = ServerSocket::CreateBindListen(addr, backlog, v6_only);
159 if (fd == -5) { 159 if (fd == -5) {
160 OSError os_error(-1, "Invalid host", OSError::kUnknown); 160 OSError os_error(-1, "Invalid host", OSError::kUnknown);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 Socket* socketfd = new Socket(fd); 192 Socket* socketfd = new Socket(fd);
193 OSSocket* os_socket = 193 OSSocket* os_socket =
194 new OSSocket(addr, allocated_port, v6_only, shared, socketfd); 194 new OSSocket(addr, allocated_port, v6_only, shared, socketfd);
195 os_socket->ref_count = 1; 195 os_socket->ref_count = 1;
196 os_socket->next = first_os_socket; 196 os_socket->next = first_os_socket;
197 197
198 InsertByPort(allocated_port, os_socket); 198 InsertByPort(allocated_port, os_socket);
199 InsertByFd(socketfd, os_socket); 199 InsertByFd(socketfd, os_socket);
200 200
201 // We set as a side-effect the port on the dart socket_object. 201 // We set as a side-effect the port on the dart socket_object.
202 Socket::ReuseSocketIdNativeField(socket_object, socketfd, true); 202 Socket::ReuseSocketIdNativeField(socket_object, socketfd,
203 Socket::kFinalizerListening);
203 204
204 return Dart_True(); 205 return Dart_True();
205 } 206 }
206 207
207 208
208 bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket, 209 bool ListeningSocketRegistry::CloseOneSafe(OSSocket* os_socket,
209 bool update_hash_maps) { 210 bool update_hash_maps) {
210 ASSERT(!mutex_->TryLock()); 211 ASSERT(!mutex_->TryLock());
211 ASSERT(os_socket != NULL); 212 ASSERT(os_socket != NULL);
212 ASSERT(os_socket->ref_count > 0); 213 ASSERT(os_socket->ref_count > 0);
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
298 void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) { 299 void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
299 RawAddr addr; 300 RawAddr addr;
300 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); 301 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
301 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2); 302 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
302 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535); 303 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
303 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port)); 304 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
304 intptr_t socket = Socket::CreateConnect(addr); 305 intptr_t socket = Socket::CreateConnect(addr);
305 OSError error; 306 OSError error;
306 if (socket >= 0) { 307 if (socket >= 0) {
307 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket, 308 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
308 false); 309 Socket::kFinalizerNormal);
309 Dart_SetReturnValue(args, Dart_True()); 310 Dart_SetReturnValue(args, Dart_True());
310 } else { 311 } else {
311 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error)); 312 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
312 } 313 }
313 } 314 }
314 315
315 316
316 void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) { 317 void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) {
317 RawAddr addr; 318 RawAddr addr;
318 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); 319 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
319 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2); 320 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
320 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535); 321 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
321 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port)); 322 SocketAddress::SetAddrPort(&addr, static_cast<intptr_t>(port));
322 RawAddr sourceAddr; 323 RawAddr sourceAddr;
323 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr); 324 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 3), &sourceAddr);
324 intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr); 325 intptr_t socket = Socket::CreateBindConnect(addr, sourceAddr);
325 OSError error; 326 OSError error;
326 if (socket >= 0) { 327 if (socket >= 0) {
327 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket, 328 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
328 false); 329 Socket::kFinalizerNormal);
329 Dart_SetReturnValue(args, Dart_True()); 330 Dart_SetReturnValue(args, Dart_True());
330 } else { 331 } else {
331 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error)); 332 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
332 } 333 }
333 } 334 }
334 335
335 void FUNCTION_NAME(Socket_IsBindError)(Dart_NativeArguments args) { 336 void FUNCTION_NAME(Socket_IsBindError)(Dart_NativeArguments args) {
336 intptr_t error_number = 337 intptr_t error_number =
337 DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1)); 338 DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
338 bool is_bind_error = Socket::IsBindError(error_number); 339 bool is_bind_error = Socket::IsBindError(error_number);
339 Dart_SetReturnValue(args, is_bind_error ? Dart_True() : Dart_False()); 340 Dart_SetReturnValue(args, is_bind_error ? Dart_True() : Dart_False());
340 } 341 }
341 342
342 void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) { 343 void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) {
343 RawAddr addr; 344 RawAddr addr;
344 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); 345 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
345 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2); 346 Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
346 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535); 347 int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
347 SocketAddress::SetAddrPort(&addr, port); 348 SocketAddress::SetAddrPort(&addr, port);
348 bool reuse_addr = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3)); 349 bool reuse_addr = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
349 intptr_t socket = Socket::CreateBindDatagram(addr, reuse_addr); 350 intptr_t socket = Socket::CreateBindDatagram(addr, reuse_addr);
350 if (socket >= 0) { 351 if (socket >= 0) {
351 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket, 352 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
352 false); 353 Socket::kFinalizerNormal);
353 Dart_SetReturnValue(args, Dart_True()); 354 Dart_SetReturnValue(args, Dart_True());
354 } else { 355 } else {
355 OSError error; 356 OSError error;
356 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error)); 357 Dart_SetReturnValue(args, DartUtils::NewDartOSError(&error));
357 } 358 }
358 } 359 }
359 360
360 361
361 void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) { 362 void FUNCTION_NAME(Socket_Available)(Dart_NativeArguments args) {
362 Socket* socket = 363 Socket* socket =
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
621 Dart_SetReturnValue(args, DartUtils::NewDartOSError()); 622 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
622 } 623 }
623 } 624 }
624 625
625 626
626 void FUNCTION_NAME(Socket_GetStdioHandle)(Dart_NativeArguments args) { 627 void FUNCTION_NAME(Socket_GetStdioHandle)(Dart_NativeArguments args) {
627 int64_t num = 628 int64_t num =
628 DartUtils::GetInt64ValueCheckRange(Dart_GetNativeArgument(args, 1), 0, 2); 629 DartUtils::GetInt64ValueCheckRange(Dart_GetNativeArgument(args, 1), 0, 2);
629 intptr_t socket = Socket::GetStdioHandle(num); 630 intptr_t socket = Socket::GetStdioHandle(num);
630 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket, 631 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), socket,
631 false); 632 Socket::kFinalizerStdio);
632 Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0)); 633 Dart_SetReturnValue(args, Dart_NewBoolean(socket >= 0));
633 } 634 }
634 635
635 636
636 void FUNCTION_NAME(Socket_GetSocketId)(Dart_NativeArguments args) { 637 void FUNCTION_NAME(Socket_GetSocketId)(Dart_NativeArguments args) {
637 Socket* socket = 638 Socket* socket =
638 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); 639 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
639 intptr_t id = reinterpret_cast<intptr_t>(socket); 640 intptr_t id = reinterpret_cast<intptr_t>(socket);
640 Dart_SetReturnValue(args, Dart_NewInteger(id)); 641 Dart_SetReturnValue(args, Dart_NewInteger(id));
641 } 642 }
642 643
643 644
644 void FUNCTION_NAME(Socket_SetSocketId)(Dart_NativeArguments args) { 645 void FUNCTION_NAME(Socket_SetSocketId)(Dart_NativeArguments args) {
645 intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1)); 646 intptr_t id = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 1));
646 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), id, false); 647 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 0), id,
648 Socket::kFinalizerNormal);
647 } 649 }
648 650
649 651
650 void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) { 652 void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
651 RawAddr addr; 653 RawAddr addr;
652 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr); 654 SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
653 int64_t port = DartUtils::GetInt64ValueCheckRange( 655 int64_t port = DartUtils::GetInt64ValueCheckRange(
654 Dart_GetNativeArgument(args, 2), 0, 65535); 656 Dart_GetNativeArgument(args, 2), 0, 65535);
655 SocketAddress::SetAddrPort(&addr, port); 657 SocketAddress::SetAddrPort(&addr, port);
656 int64_t backlog = DartUtils::GetInt64ValueCheckRange( 658 int64_t backlog = DartUtils::GetInt64ValueCheckRange(
657 Dart_GetNativeArgument(args, 3), 0, 65535); 659 Dart_GetNativeArgument(args, 3), 0, 65535);
658 bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4)); 660 bool v6_only = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 4));
659 bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5)); 661 bool shared = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 5));
660 662
661 Dart_Handle socket_object = Dart_GetNativeArgument(args, 0); 663 Dart_Handle socket_object = Dart_GetNativeArgument(args, 0);
662 Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen( 664 Dart_Handle result = ListeningSocketRegistry::Instance()->CreateBindListen(
663 socket_object, addr, backlog, v6_only, shared); 665 socket_object, addr, backlog, v6_only, shared);
664 Dart_SetReturnValue(args, result); 666 Dart_SetReturnValue(args, result);
665 } 667 }
666 668
667 669
668 void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) { 670 void FUNCTION_NAME(ServerSocket_Accept)(Dart_NativeArguments args) {
669 Socket* socket = 671 Socket* socket =
670 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0)); 672 Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
671 intptr_t new_socket = ServerSocket::Accept(socket->fd()); 673 intptr_t new_socket = ServerSocket::Accept(socket->fd());
672 if (new_socket >= 0) { 674 if (new_socket >= 0) {
673 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 1), new_socket, 675 Socket::SetSocketIdNativeField(Dart_GetNativeArgument(args, 1), new_socket,
674 false); 676 Socket::kFinalizerNormal);
675 Dart_SetReturnValue(args, Dart_True()); 677 Dart_SetReturnValue(args, Dart_True());
676 } else if (new_socket == ServerSocket::kTemporaryFailure) { 678 } else if (new_socket == ServerSocket::kTemporaryFailure) {
677 Dart_SetReturnValue(args, Dart_False()); 679 Dart_SetReturnValue(args, Dart_False());
678 } else { 680 } else {
679 Dart_SetReturnValue(args, DartUtils::NewDartOSError()); 681 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
680 } 682 }
681 } 683 }
682 684
683 685
684 CObject* Socket::LookupRequest(const CObjectArray& request) { 686 CObject* Socket::LookupRequest(const CObjectArray& request) {
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
937 int interfaceIndex = 939 int interfaceIndex =
938 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3)); 940 DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
939 if (Socket::LeaveMulticast(socket->fd(), addr, interface, interfaceIndex)) { 941 if (Socket::LeaveMulticast(socket->fd(), addr, interface, interfaceIndex)) {
940 Dart_SetReturnValue(args, Dart_Null()); 942 Dart_SetReturnValue(args, Dart_Null());
941 } else { 943 } else {
942 Dart_SetReturnValue(args, DartUtils::NewDartOSError()); 944 Dart_SetReturnValue(args, DartUtils::NewDartOSError());
943 } 945 }
944 } 946 }
945 947
946 948
947 static void SocketFinalizer(void* isolate_data, 949 static void NormalSocketFinalizer(void* isolate_data,
948 Dart_WeakPersistentHandle handle, 950 Dart_WeakPersistentHandle handle,
949 void* data) { 951 void* data) {
950 Socket* socket = reinterpret_cast<Socket*>(data); 952 Socket* socket = reinterpret_cast<Socket*>(data);
951 if (socket->fd() >= 0) { 953 if (socket->fd() >= 0) {
952 const int64_t flags = 1 << kCloseCommand; 954 const int64_t flags = 1 << kCloseCommand;
953 socket->Retain(); 955 socket->Retain();
954 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket), 956 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket),
955 socket->port(), flags); 957 socket->port(), flags);
956 } 958 }
957 socket->Release(); 959 socket->Release();
958 } 960 }
959 961
960 962
961 static void ListeningSocketFinalizer(void* isolate_data, 963 static void ListeningSocketFinalizer(void* isolate_data,
962 Dart_WeakPersistentHandle handle, 964 Dart_WeakPersistentHandle handle,
963 void* data) { 965 void* data) {
964 Socket* socket = reinterpret_cast<Socket*>(data); 966 Socket* socket = reinterpret_cast<Socket*>(data);
965 if (socket->fd() >= 0) { 967 if (socket->fd() >= 0) {
966 const int64_t flags = (1 << kListeningSocket) | (1 << kCloseCommand); 968 const int64_t flags = (1 << kListeningSocket) | (1 << kCloseCommand);
967 socket->Retain(); 969 socket->Retain();
968 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket), 970 EventHandler::SendFromNative(reinterpret_cast<intptr_t>(socket),
969 socket->port(), flags); 971 socket->port(), flags);
970 } 972 }
971 socket->Release(); 973 socket->Release();
972 } 974 }
973 975
974 976
977 static void StdioSocketFinalizer(void* isolate_data,
978 Dart_WeakPersistentHandle handle,
979 void* data) {
980 Socket* socket = reinterpret_cast<Socket*>(data);
981 if (socket->fd() >= 0) {
982 socket->SetClosedFd();
983 }
984 socket->Release();
985 }
986
987
975 void Socket::ReuseSocketIdNativeField(Dart_Handle handle, 988 void Socket::ReuseSocketIdNativeField(Dart_Handle handle,
976 Socket* socket, 989 Socket* socket,
977 bool listening) { 990 SocketFinalizer finalizer) {
978 Dart_Handle err = Dart_SetNativeInstanceField( 991 Dart_Handle err = Dart_SetNativeInstanceField(
979 handle, kSocketIdNativeField, reinterpret_cast<intptr_t>(socket)); 992 handle, kSocketIdNativeField, reinterpret_cast<intptr_t>(socket));
980 if (Dart_IsError(err)) { 993 if (Dart_IsError(err)) {
981 Dart_PropagateError(err); 994 Dart_PropagateError(err);
982 } 995 }
983 if (listening) { 996 Dart_WeakPersistentHandleFinalizer callback;
997 switch (finalizer) {
998 case kFinalizerNormal:
999 callback = NormalSocketFinalizer;
1000 break;
1001 case kFinalizerListening:
1002 callback = ListeningSocketFinalizer;
1003 break;
1004 case kFinalizerStdio:
1005 callback = StdioSocketFinalizer;
1006 break;
1007 default:
1008 callback = NULL;
1009 UNREACHABLE();
1010 break;
1011 }
1012 if (callback != NULL) {
984 Dart_NewWeakPersistentHandle(handle, reinterpret_cast<void*>(socket), 1013 Dart_NewWeakPersistentHandle(handle, reinterpret_cast<void*>(socket),
985 sizeof(Socket), ListeningSocketFinalizer); 1014 sizeof(Socket), callback);
986 } else {
987 Dart_NewWeakPersistentHandle(handle, reinterpret_cast<void*>(socket),
988 sizeof(Socket), SocketFinalizer);
989 } 1015 }
990 } 1016 }
991 1017
992 1018
993 void Socket::SetSocketIdNativeField(Dart_Handle handle, 1019 void Socket::SetSocketIdNativeField(Dart_Handle handle,
994 intptr_t id, 1020 intptr_t id,
995 bool listening) { 1021 SocketFinalizer finalizer) {
996 Socket* socket = new Socket(id); 1022 Socket* socket = new Socket(id);
997 ReuseSocketIdNativeField(handle, socket, listening); 1023 ReuseSocketIdNativeField(handle, socket, finalizer);
998 } 1024 }
999 1025
1000 1026
1001 Socket* Socket::GetSocketIdNativeField(Dart_Handle socket_obj) { 1027 Socket* Socket::GetSocketIdNativeField(Dart_Handle socket_obj) {
1002 intptr_t id; 1028 intptr_t id;
1003 Dart_Handle err = 1029 Dart_Handle err =
1004 Dart_GetNativeInstanceField(socket_obj, kSocketIdNativeField, &id); 1030 Dart_GetNativeInstanceField(socket_obj, kSocketIdNativeField, &id);
1005 if (Dart_IsError(err)) { 1031 if (Dart_IsError(err)) {
1006 Dart_PropagateError(err); 1032 Dart_PropagateError(err);
1007 } 1033 }
1008 Socket* socket = reinterpret_cast<Socket*>(id); 1034 Socket* socket = reinterpret_cast<Socket*>(id);
1009 return socket; 1035 return socket;
1010 } 1036 }
1011 1037
1012 } // namespace bin 1038 } // namespace bin
1013 } // namespace dart 1039 } // namespace dart
1014 1040
1015 #endif // !defined(DART_IO_DISABLED) 1041 #endif // !defined(DART_IO_DISABLED)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698