Version 2.19.0-277.0.dev
Merge ce7c036db217b43014a05dcbdc377e3bcb7743ae into dev
diff --git a/pkg/compiler/test/analyses/api_allowed.json b/pkg/compiler/test/analyses/api_allowed.json
index 406e762..a307b90 100644
--- a/pkg/compiler/test/analyses/api_allowed.json
+++ b/pkg/compiler/test/analyses/api_allowed.json
@@ -28,8 +28,6 @@
"Dynamic update to 'dart.io::_owner'.": 1
},
"org-dartlang-sdk:///lib/io/secure_socket.dart": {
- "Dynamic invocation of '[]'.": 4,
- "Dynamic invocation of 'dart.io::_detachRaw'.": 2,
"Dynamic access of 'closedReadEventSent'.": 1,
"Dynamic update to 'dart.io::_owner'.": 1
},
diff --git a/pkg/dart2wasm/lib/transformers.dart b/pkg/dart2wasm/lib/transformers.dart
index 41bc19b..4c6784d 100644
--- a/pkg/dart2wasm/lib/transformers.dart
+++ b/pkg/dart2wasm/lib/transformers.dart
@@ -134,10 +134,16 @@
//
// {
// final StreamIterator<T> #forIterator = StreamIterator(<stream>);
- // for (; await #forIterator.moveNext() ;) {
- // {var/final} T variable = await #forIterator.current;
+ // bool #jumpSentinel = false;
+ // try {
+ // for (; jumpSentinel = await #forIterator.moveNext() ;) {
+ // {var/final} T variable = #forIterator.current;
// ...
// }
+ // } finally {
+ // if (#jumpSentinel) {
+ // await #forIterator.cancel();
+ // }
// }
// }
@@ -188,6 +194,11 @@
type: iteratorType)
..fileOffset = iterable.fileOffset;
+ // Only used when `isAsync` is true.
+ final jumpSentinel = VariableDeclaration("#jumpSentinel",
+ initializer: ConstantExpression(BoolConstant(false)),
+ type: InterfaceType(coreTypes.boolClass, Nullability.nonNullable));
+
final condition = InstanceInvocation(InstanceAccessKind.Instance,
VariableGet(iterator), Name('moveNext'), Arguments(const []),
interfaceTarget: iteratorMoveNext,
@@ -200,14 +211,39 @@
interfaceTarget: iteratorCurrent, resultType: elementType)
..fileOffset = stmt.bodyOffset);
- final Block body = Block([variable, stmt.body])
- ..fileOffset = stmt.fileOffset;
+ Block body = Block([variable, stmt.body])..fileOffset = stmt.fileOffset;
- return Block([
- iterator,
- ForStatement(const [], isAsync ? AwaitExpression(condition) : condition,
- const [], body)
- ]).accept<TreeNode>(this);
+ Statement forStatement = ForStatement(
+ const [],
+ isAsync
+ ? VariableSet(jumpSentinel, AwaitExpression(condition))
+ : condition,
+ const [],
+ body);
+
+ // Wrap the body with a try / finally to cancel the stream on breaking out
+ // of the loop.
+ if (isAsync) {
+ forStatement = TryFinally(
+ Block([forStatement]),
+ Block([
+ IfStatement(
+ VariableGet(jumpSentinel),
+ ExpressionStatement(AwaitExpression(InstanceInvocation(
+ InstanceAccessKind.Instance,
+ VariableGet(iterator),
+ Name('cancel'),
+ Arguments(const []),
+ interfaceTarget: coreTypes.streamIteratorCancel,
+ functionType: coreTypes.streamIteratorCancel.getterType
+ as FunctionType))),
+ null)
+ ]),
+ );
+ }
+
+ return Block([iterator, if (isAsync) jumpSentinel, forStatement])
+ .accept<TreeNode>(this);
}
@override
diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart
index 3196397..24b17b5 100644
--- a/sdk/lib/_internal/vm/bin/socket_patch.dart
+++ b/sdk/lib/_internal/vm/bin/socket_patch.dart
@@ -2153,7 +2153,7 @@
late _SocketStreamConsumer _consumer;
late IOSink _sink;
StreamSubscription? _subscription;
- var _detachReady;
+ Completer<Object?>? _detachReady;
_Socket(RawSocket raw) : _raw = raw {
_controller
@@ -2273,10 +2273,11 @@
return raw.remoteAddress;
}
- Future _detachRaw() {
- _detachReady = new Completer();
+ Future<List<Object?>> _detachRaw() {
+ var completer = Completer<Object?>();
+ _detachReady = completer;
_sink.close();
- return _detachReady.future.then((_) {
+ return completer.future.then((_) {
assert(_consumer.buffer == null);
var raw = _raw;
_raw = null;
@@ -2374,7 +2375,7 @@
void _consumerDone() {
if (_detachReady != null) {
- _detachReady.complete(null);
+ _detachReady!.complete(null);
} else {
final raw = _raw;
if (raw != null) {
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 30c4f5c..f0b7e3c 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -144,8 +144,7 @@
bool onBadCertificate(X509Certificate certificate)?,
void keyLog(String line)?,
@Since("2.6") List<String>? supportedProtocols}) {
- return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
- .then<RawSecureSocket>((detachedRaw) {
+ return socket._detachRaw().then<RawSecureSocket>((detachedRaw) {
return RawSecureSocket.secure(detachedRaw[0] as RawSocket,
subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>?,
host: host,
@@ -182,8 +181,7 @@
bool requestClientCertificate = false,
bool requireClientCertificate = false,
List<String>? supportedProtocols}) {
- return ((socket as dynamic /*_Socket*/)._detachRaw() as Future)
- .then<RawSecureSocket>((detachedRaw) {
+ return socket._detachRaw().then<RawSecureSocket>((detachedRaw) {
return RawSecureSocket.secureServer(detachedRaw[0] as RawSocket, context,
subscription: detachedRaw[1] as StreamSubscription<RawSocketEvent>?,
bufferedData: bufferedData,
diff --git a/sdk/lib/io/socket.dart b/sdk/lib/io/socket.dart
index 7087c65..b489198 100644
--- a/sdk/lib/io/socket.dart
+++ b/sdk/lib/io/socket.dart
@@ -773,6 +773,8 @@
external static Future<ConnectionTask<Socket>> _startConnect(host, int port,
{sourceAddress, int sourcePort = 0});
+ Future<List<Object?>> _detachRaw();
+
/// Destroys the socket in both directions.
///
/// Calling [destroy] will make the send a close event on the stream
diff --git a/tools/VERSION b/tools/VERSION
index 08d79d8..0600da2 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 19
PATCH 0
-PRERELEASE 276
+PRERELEASE 277
PRERELEASE_PATCH 0