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

Side by Side Diff: tests/isolate/function_send_test.dart

Issue 584843003: Allow sending static/top-level functions through ports and as isolate (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Address comments. Update status files. Created 6 years, 3 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 | Annotate | Revision Log
OLDNEW
(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 Function createFuncToplevel() => (p, m) { p.send(m); };
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 createFuncStatic() => (p, m) { throw "static expr"; };
20 void instanceMethod(p, m) { throw "instanceMethod"; }
21 Function createFuncMember() => (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.instanceMethod);
40 testUnsendable("static context expression", createFuncToplevel());
41 testUnsendable("static context expression", C.createFuncStatic());
42 testUnsendable("initializer context expression", c.initializer);
43 testUnsendable("constructor context expression", c.body);
44 testUnsendable("instance method context expression", c.createFuncMember());
45
46 // The result of `toplevel.call` and `staticFunc.call` may or may not be
47 // identical to `toplevel` and `staticFunc` respectively. If they are not
48 // equal, they may or may not be considered toplevel/static functions anyway,
49 // and therefore sendable. The VM and dart2js curretnly disagrees on whether
50 // `toplevel` and `toplevel.call` are identical, both allow them to be sent.
51 // If this is ever specified to something else, use:
52 // testUnsendable("toplevel.call", toplevel.call);
53 // testUnsendable("static.call", C.staticFunc.call);
54 // instead.
55 // These two tests should be considered canaries for accidental behavior
56 // change rather than requirements.
57 testSendable("toplevel", toplevel.call);
58 testSendable("static", C.staticFunc.call);
59
60 // Callable objects are sendable if general objects are (VM yes, dart2js no).
61 // It's unspecified whether arbitrary objects can be sent. If it is specified,
62 // add a test that `new Callable()` is either sendable or unsendable.
63
64 // The call method of a callable object is a closure holding the object,
65 // not a top-level or static function, so it should be blocked, just as
66 // a normal method.
67 testUnsendable("callable object", new Callable().call);
68 asyncEnd();
69 return;
70 }
71
72 // Create a receive port that expects exactly one message.
73 // Pass the message to `callback` and return the sendPort.
74 SendPort singleMessagePort(callback) {
75 var p;
76 p = new RawReceivePort((v) { p.close(); callback(v); });
77 return p.sendPort;
78 }
79
80 // A singleMessagePort that expects the message to be a specific value.
81 SendPort expectMessagePort(message) {
82 asyncStart();
83 return singleMessagePort((v) {
84 Expect.equals(message, v);
85 asyncEnd();
86 });
87 }
88
89 void testSendable(name, func) {
90 // Function as spawn message.
91 Isolate.spawn(callFunc, [func, expectMessagePort("$name:spawn"), "spawn"]);
92
93 // Send function to same isolate.
94 var reply = expectMessagePort("$name:direct");
95 singleMessagePort(callFunc).send([func, reply, "direct"]);
96
97 // Send function to other isolate, call it there.
98 reply = expectMessagePort("$name:other isolate");
99 callPort().then((p) {
100 p.send([func, reply, "other isolate"]);
101 });
102
103 // Round-trip function trough other isolate.
104 echoPort((roundtripFunc) {
105 Expect.identical(func, roundtripFunc, "$name:send through isolate");
106 }).then((port) { port.send(func); });
107 }
108
109 // Creates a new isolate and a pair of ports that expect a single message
110 // to be sent to the other isolate and back to the callback function.
111 Future<SendPort> echoPort(callback(value)) {
112 Completer completer = new Completer<SendPort>();
113 SendPort replyPort = singleMessagePort(callback);
114 RawReceivePort initPort;
115 initPort = new RawReceivePort((p) {
116 completer.complete(p);
117 initPort.close();
118 });
119 return Isolate.spawn(_echo, [replyPort, initPort.sendPort])
120 .then((isolate) => completer.future);
121 }
122
123 void _echo(msg) {
124 var replyPort = msg[0];
125 RawReceivePort requestPort;
126 requestPort = new RawReceivePort((msg) {
127 replyPort.send(msg);
128 requestPort.close(); // Single echo only.
129 });
130 msg[1].send(requestPort.sendPort);
131 }
132
133 // Creates other isolate that waits for a single message, `msg`, on the returned
134 // port, and executes it as `msg[0](msg[1],msg[2])` in the other isolate.
135 Future<SendPort> callPort() {
136 Completer completer = new Completer<SendPort>();
137 SendPort initPort = singleMessagePort(completer.complete);
138 return Isolate.spawn(_call, initPort)
139 .then((_) => completer.future);
140 }
141
142 void _call(initPort) {
143 initPort.send(singleMessagePort(callFunc));
144 }
145 // Expect.throws(() {
146 // noReply.sendPort.send([func]);
147 // }, null, "send wrapped");
148
149
150 void testUnsendable(name, func) {
151 asyncStart();
152 Isolate.spawn(nop, func).then((v) => throw "allowed spawn direct?",
153 onError: (e,s){ asyncEnd(); });
154 asyncStart();
155 Isolate.spawn(nop, [func]).then((v) => throw "allowed spawn wrapped?",
156 onError: (e,s){ asyncEnd(); });
157
158 asyncStart();
159 var noReply = new RawReceivePort((_) { throw "Unexpected message: $_"; });
160 // Currently succeedes incorrectly in dart2js.
161 Expect.throws(() { /// 01: ok
162 noReply.sendPort.send(func); /// 01: continued
163 }, null, "send direct"); /// 01: continued
164 Expect.throws(() { /// 01: continued
165 noReply.sendPort.send([func]); /// 01: continued
166 }, null, "send wrapped"); /// 01: continued
167 scheduleMicrotask(() {
168 noReply.close();
169 asyncEnd();
170 });
171
172 // Try sending through other isolate.
173 asyncStart();
174 echoPort((_) => throw "unreachable")
175 .then((p) => p.send(func))
176 .then((p) => throw "unreachable 2",
177 onError: (e, s) {asyncEnd();});
178 }
179
180 void nop(_) {}
181
182 void callFunc(message) {
183 message[0](message[1], message[2]);
184 }
OLDNEW
« no previous file with comments | « sdk/lib/_internal/compiler/js_lib/isolate_helper.dart ('k') | tests/isolate/illegal_msg_function_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698