Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 import "dart:isolate"; | |
| 6 import "dart:async"; | |
| 7 import "package:expect/expect.dart"; | |
| 8 import "package:async_helper/async_helper.dart"; | |
| 9 | |
| 10 void toplevel(port, message) { port.send("toplevel:$message"); } | |
| 11 void mkToplevelFunc() => (p, m) { p.send(m); }; | |
|
floitsch
2014/09/19 19:52:45
mkFuncToplevel
or
funcGeneratorToplevel
Lasse Reichstein Nielsen
2014/09/23 07:25:07
I'll go for createFuncToplevel.
| |
| 12 class C { | |
| 13 Function initializer; | |
| 14 Function body; | |
| 15 C() : initializer = ((p, m) { throw "initializer"; }) { | |
| 16 body = (p, m) { throw "body"; }; | |
| 17 } | |
| 18 static void staticFunc(port, message) { port.send("static:$message"); } | |
| 19 static Function mkStaticFunc() => (p, m) { throw "static expr"; }; | |
| 20 void member(p, m) { throw "member"; } | |
| 21 void mkFunc() => (p, m) { throw "instance expr"; }; | |
| 22 void call(n, p) { throw "C"; } | |
| 23 } | |
| 24 | |
| 25 class Callable { | |
| 26 void call(p, m) { p.send(["callable", m]); } | |
| 27 } | |
| 28 | |
| 29 | |
| 30 void main() { | |
| 31 asyncStart(); | |
| 32 | |
| 33 // Sendables are top-level functions and static functions only. | |
| 34 testSendable("toplevel", toplevel); | |
| 35 testSendable("static", C.staticFunc); | |
| 36 | |
| 37 // Unsendables are any closure - instance methods or function expression. | |
| 38 var c = new C(); | |
| 39 testUnsendable("instance method", c.member); | |
| 40 testUnsendable("static context expression", mkToplevelFunc()); | |
| 41 testUnsendable("static context expression", C.mkStaticFunc()); | |
| 42 testUnsendable("initializer context expression", c.initializer); | |
| 43 testUnsendable("constructor context expression", c.body); | |
| 44 testUnsendable("instance method context expression", c.mkFunc()); | |
| 45 | |
| 46 // Actually allowed. Identical in VM, different, but still static, in dart2js. | |
|
floitsch
2014/09/19 19:52:45
If it's allowed, why is it commented?
Lasse Reichstein Nielsen
2014/09/23 07:25:07
I can't say whether it should be allowed or not, a
| |
| 47 // testUnsendable("toplevel.call closure", toplevel.call); | |
| 48 // testUnsendable("static.call closure", C.staticFunc.call); | |
| 49 | |
| 50 // Callable objects are sendable if general objects are (VM yes, dart2js no). | |
| 51 //testSendable("callable object", new Callable()); /// 01: ok | |
|
floitsch
2014/09/19 19:52:45
Why is it commented?
Especially with "/// 01: ok".
Lasse Reichstein Nielsen
2014/09/23 07:25:07
Again I can't decide on whether it should be one o
| |
| 52 testUnsendable("callable object", new Callable()); /// 02: ok | |
|
floitsch
2014/09/19 19:52:45
That looks like the same as above...
Lasse Reichstein Nielsen
2014/09/23 07:25:07
This one is test*Un*sendablem the one above is tes
| |
| 53 testUnsendable("callable object", new Callable().call); | |
| 54 asyncEnd(); | |
| 55 return; | |
| 56 } | |
| 57 | |
| 58 // Create a receive port that expects exactly one message. | |
| 59 // Pass the message to `callback` and return the sendPort. | |
| 60 void singleMessagePort(callback) { | |
| 61 var p; | |
| 62 p = new RawReceivePort((v) { p.close(); callback(v); }); | |
| 63 return p.sendPort; | |
| 64 } | |
| 65 | |
| 66 // A singleMessagePort that expects the message to be a specific value. | |
| 67 void expectMessagePort(message) { | |
| 68 asyncStart(); | |
| 69 return singleMessagePort((v) { | |
| 70 Expect.equals(message, v); | |
| 71 asyncEnd(); | |
| 72 }); | |
| 73 } | |
| 74 | |
| 75 void testSendable(name, func) { | |
| 76 // Function as spawn message. | |
| 77 Isolate.spawn(callFunc, [func, expectMessagePort("$name:spawn"), "spawn"]); | |
| 78 | |
| 79 // Send function to same isolate. | |
| 80 var reply = expectMessagePort("$name:direct"); | |
| 81 singleMessagePort(callFunc).send([func, reply, "direct"]); | |
| 82 | |
| 83 // Send function to other isolate, call it there. | |
| 84 reply = expectMessagePort("$name:other isolate"); | |
| 85 callPort().then((p) { | |
| 86 p.send([func, reply, "other isolate"]); | |
| 87 }); | |
| 88 | |
| 89 // Round-trip function trough other isolate. | |
| 90 echoPort((roundtripFunc) { | |
| 91 Expect.identical(func, roundtripFunc, "$name:send through isolate"); | |
| 92 }).then((port) { port.send(func); }); | |
| 93 } | |
| 94 | |
| 95 // Creates a new isolate and a pair of ports that expect a single message | |
| 96 // to be sent to the other isolate and back to the callback function. | |
| 97 Future<SendPort> echoPort(callback(value)) { | |
| 98 Completer completer = new Completer<SendPort>(); | |
| 99 SendPort replyPort = singleMessagePort(callback); | |
| 100 RawReceivePort initPort; | |
| 101 initPort = new RawReceivePort((p) { | |
| 102 completer.complete(p); | |
| 103 initPort.close(); | |
| 104 }); | |
| 105 return Isolate.spawn(_echo, [replyPort, initPort.sendPort]) | |
| 106 .then((isolate) => completer.future); | |
| 107 } | |
| 108 | |
| 109 void _echo(msg) { | |
| 110 var replyPort = msg[0]; | |
| 111 RawReceivePort requestPort; | |
| 112 requestPort = new RawReceivePort((msg) { | |
| 113 replyPort.send(msg); | |
| 114 requestPort.close(); // Single echo only. | |
| 115 }); | |
| 116 msg[1].send(requestPort.sendPort); | |
| 117 } | |
| 118 | |
| 119 // Creates other isolate that waits for a single message, `msg`, on the returned | |
| 120 // port, and executes it as `msg[0](msg[1],msg[2])` in the other isolate. | |
| 121 Future<SendPort> callPort() { | |
| 122 Completer completer = new Completer<SendPort>(); | |
| 123 SendPort initPort = singleMessagePort(completer.complete); | |
| 124 return Isolate.spawn(_call, initPort) | |
| 125 .then((_) => completer.future); | |
| 126 } | |
| 127 | |
| 128 void _call(initPort) { | |
| 129 initPort.send(singleMessagePort(callFunc)); | |
| 130 } | |
| 131 // Expect.throws(() { | |
| 132 // noReply.sendPort.send([func]); | |
| 133 // }, null, "send wrapped"); | |
| 134 | |
| 135 | |
| 136 void testUnsendable(name, func) { | |
| 137 asyncStart(); | |
| 138 Isolate.spawn(nop, func).then((v) => throw "allowed spawn direct?", | |
| 139 onError: (e,s){ asyncEnd(); }); | |
| 140 asyncStart(); | |
| 141 Isolate.spawn(nop, [func]).then((v) => throw "allowed spawn wrapped?", | |
| 142 onError: (e,s){ asyncEnd(); }); | |
| 143 | |
| 144 asyncStart(); | |
| 145 var noReply = new RawReceivePort((_) { throw "Unexpected message: $_"; }); | |
| 146 // Currently succeedes incorrectly in dart2js. | |
| 147 // Expect.throws(() { | |
| 148 // noReply.sendPort.send(func); | |
| 149 // }, null, "send direct"); | |
| 150 // Expect.throws(() { | |
| 151 // noReply.sendPort.send([func]); | |
| 152 // }, null, "send wrapped"); | |
| 153 scheduleMicrotask(() { | |
| 154 noReply.close(); | |
| 155 asyncEnd(); | |
| 156 }); | |
| 157 | |
| 158 // Try sending through other isolate. | |
| 159 asyncStart(); | |
| 160 echoPort((_) => throw "unreachable") | |
| 161 .then((p) => p.send(func)) | |
| 162 .then((p) => throw "unreachable 2", | |
| 163 onError: (e, s) {asyncEnd();}); | |
| 164 } | |
| 165 | |
| 166 void nop(_) {} | |
| 167 | |
| 168 void callFunc(message) { | |
| 169 message[0](message[1], message[2]); | |
| 170 } | |
| OLD | NEW |