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 |