OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 _serialize(var message) { | 5 _serialize(var message) { |
6 return new _JsSerializer().traverse(message); | 6 return new _JsSerializer().traverse(message); |
7 } | 7 } |
8 | 8 |
| 9 class JsProxy { |
| 10 final _id; |
| 11 |
| 12 JsProxy._internal(this._id); |
| 13 } |
| 14 |
9 class _JsSerializer extends _Serializer { | 15 class _JsSerializer extends _Serializer { |
10 | 16 |
11 visitSendPortSync(SendPortSync x) { | 17 visitSendPortSync(SendPortSync x) { |
12 if (x is _JsSendPortSync) return visitJsSendPortSync(x); | 18 if (x is _JsSendPortSync) return visitJsSendPortSync(x); |
13 if (x is _LocalSendPortSync) return visitLocalSendPortSync(x); | 19 if (x is _LocalSendPortSync) return visitLocalSendPortSync(x); |
14 if (x is _RemoteSendPortSync) return visitRemoteSendPortSync(x); | 20 if (x is _RemoteSendPortSync) return visitRemoteSendPortSync(x); |
15 throw "Illegal underlying port $x"; | 21 throw "Illegal underlying port $x"; |
16 } | 22 } |
17 | 23 |
18 visitJsSendPortSync(_JsSendPortSync x) { | 24 visitJsSendPortSync(_JsSendPortSync x) { |
19 return [ 'sendport', 'nativejs', x._id ]; | 25 return [ 'sendport', 'nativejs', x._id ]; |
20 } | 26 } |
21 | 27 |
22 visitLocalSendPortSync(_LocalSendPortSync x) { | 28 visitLocalSendPortSync(_LocalSendPortSync x) { |
23 return [ 'sendport', 'dart', | 29 return [ 'sendport', 'dart', |
24 ReceivePortSync._isolateId, x._receivePort._portId ]; | 30 ReceivePortSync._isolateId, x._receivePort._portId ]; |
25 } | 31 } |
26 | 32 |
27 visitRemoteSendPortSync(_RemoteSendPortSync x) { | 33 visitRemoteSendPortSync(_RemoteSendPortSync x) { |
28 return [ 'sendport', 'dart', | 34 return [ 'sendport', 'dart', |
29 x._receivePort._isolateId, x._receivePort._portId ]; | 35 x._receivePort._isolateId, x._receivePort._portId ]; |
30 } | 36 } |
31 | 37 |
32 visitObject(Object x) { | 38 visitObject(Object x) { |
33 if (x is Function) return visitFunction(x); | 39 if (x is Function) return visitFunction(x); |
| 40 if (x is JsProxy) return visitJsProxy(x); |
| 41 |
34 // TODO: Handle DOM elements and proxy other objects. | 42 // TODO: Handle DOM elements and proxy other objects. |
35 throw "Unserializable object $x"; | 43 var proxyId = _makeDartProxyRef(x); |
| 44 return [ 'objref', 'dart', proxyId ]; |
36 } | 45 } |
37 | 46 |
38 visitFunction(Function func) { | 47 visitFunction(Function func) { |
39 return [ 'funcref', | 48 return [ 'funcref', |
40 _makeFunctionRef(func), visitSendPortSync(_sendPort()), null ]; | 49 _makeFunctionRef(func), visitSendPortSync(_sendPort()), null ]; |
41 } | 50 } |
| 51 |
| 52 visitJsProxy(JsProxy proxy) { |
| 53 return [ 'objref', 'nativejs', proxy._id ]; |
| 54 } |
42 } | 55 } |
43 | 56 |
44 // Leaking implementation. Later will be backend specific and hopefully | 57 // Leaking implementation. Later will be backend specific and hopefully |
45 // not leaking (at least in most of the cases.) | 58 // not leaking (at least in most of the cases.) |
46 // TODO: provide better, backend specific implementation. | 59 // TODO: provide better, backend specific implementation. |
47 class _FunctionRegistry { | 60 class _Registry<T> { |
| 61 final String _name; |
| 62 int _nextId; |
| 63 final Map<String, T> _registry; |
| 64 |
| 65 _Registry(this._name) : _nextId = 0, _registry = <T>{}; |
| 66 |
| 67 String _add(T x) { |
| 68 // TODO(vsm): Cache x and reuse id. |
| 69 final id = '$_name-${_nextId++}'; |
| 70 _registry[id] = x; |
| 71 return id; |
| 72 } |
| 73 |
| 74 T _get(String id) { |
| 75 return _registry[id]; |
| 76 } |
| 77 } |
| 78 |
| 79 class _FunctionRegistry extends _Registry<Function> { |
48 final ReceivePortSync _port; | 80 final ReceivePortSync _port; |
49 int _nextId; | |
50 final Map<String, Function> _registry; | |
51 | 81 |
52 _FunctionRegistry() : | 82 _FunctionRegistry() : |
53 _port = new ReceivePortSync(), | 83 super('func-ref'), |
54 _nextId = 0, | 84 _port = new ReceivePortSync() { |
55 _registry = <Function>{} { | |
56 _port.receive((msg) { | 85 _port.receive((msg) { |
57 final id = msg[0]; | 86 final id = msg[0]; |
58 final args = msg[1]; | 87 final args = msg[1]; |
59 final f = _registry[id]; | 88 final f = _registry[id]; |
60 switch (args.length) { | 89 switch (args.length) { |
61 case 0: return f(); | 90 case 0: return f(); |
62 case 1: return f(args[0]); | 91 case 1: return f(args[0]); |
63 case 2: return f(args[0], args[1]); | 92 case 2: return f(args[0], args[1]); |
64 case 3: return f(args[0], args[1], args[2]); | 93 case 3: return f(args[0], args[1], args[2]); |
65 case 4: return f(args[0], args[1], args[2], args[3]); | 94 case 4: return f(args[0], args[1], args[2], args[3]); |
66 default: throw 'Unsupported number of arguments.'; | 95 default: throw 'Unsupported number of arguments.'; |
67 } | 96 } |
68 }); | 97 }); |
69 } | 98 } |
70 | 99 |
71 String _add(Function f) { | 100 get _sendPort => _port.toSendPort(); |
72 final id = 'func-ref-${_nextId++}'; | |
73 _registry[id] = f; | |
74 return id; | |
75 } | |
76 | |
77 get _sendPort() => _port.toSendPort(); | |
78 } | 101 } |
79 | 102 |
80 _FunctionRegistry __functionRegistry; | 103 _FunctionRegistry __functionRegistry; |
81 get _functionRegistry() { | 104 get _functionRegistry { |
82 if (__functionRegistry === null) __functionRegistry = new _FunctionRegistry(); | 105 if (__functionRegistry === null) __functionRegistry = new _FunctionRegistry(); |
83 return __functionRegistry; | 106 return __functionRegistry; |
84 } | 107 } |
85 | 108 |
86 _makeFunctionRef(f) => _functionRegistry._add(f); | 109 _makeFunctionRef(f) => _functionRegistry._add(f); |
87 _sendPort() => _functionRegistry._sendPort; | 110 _sendPort() => _functionRegistry._sendPort; |
88 /// End of function serialization implementation. | 111 /// End of function serialization implementation. |
89 | 112 |
| 113 /// Object proxy implementation. |
| 114 |
| 115 class _DartProxyRegistry extends _Registry<Object> { |
| 116 _DartProxyRegistry() : super('dart-ref'); |
| 117 } |
| 118 |
| 119 _DartProxyRegistry __dartProxyRegistry; |
| 120 get _dartProxyRegistry { |
| 121 if (__dartProxyRegistry === null) { |
| 122 __dartProxyRegistry = new _DartProxyRegistry(); |
| 123 } |
| 124 return __dartProxyRegistry; |
| 125 } |
| 126 |
| 127 _makeDartProxyRef(f) => _dartProxyRegistry._add(f); |
| 128 _getDartProxyObj(id) => _dartProxyRegistry._get(id); |
| 129 |
| 130 /// End of object proxy implementation. |
| 131 |
90 _deserialize(var message) { | 132 _deserialize(var message) { |
91 return new _JsDeserializer().deserialize(message); | 133 return new _JsDeserializer().deserialize(message); |
92 } | 134 } |
93 | 135 |
94 class _JsDeserializer extends _Deserializer { | 136 class _JsDeserializer extends _Deserializer { |
95 | 137 |
96 static final _UNSPECIFIED = const Object(); | 138 static final _UNSPECIFIED = const Object(); |
97 | 139 |
98 deserializeSendPort(List x) { | 140 deserializeSendPort(List x) { |
99 String tag = x[1]; | 141 String tag = x[1]; |
100 switch (tag) { | 142 switch (tag) { |
101 case 'nativejs': | 143 case 'nativejs': |
102 num id = x[2]; | 144 num id = x[2]; |
103 return new _JsSendPortSync(id); | 145 return new _JsSendPortSync(id); |
104 case 'dart': | 146 case 'dart': |
105 num isolateId = x[2]; | 147 num isolateId = x[2]; |
106 num portId = x[3]; | 148 num portId = x[3]; |
107 return ReceivePortSync._lookup(isolateId, portId); | 149 return ReceivePortSync._lookup(isolateId, portId); |
108 default: | 150 default: |
109 throw 'Illegal SendPortSync type: $tag'; | 151 throw 'Illegal SendPortSync type: $tag'; |
110 } | 152 } |
111 } | 153 } |
112 | 154 |
113 deserializeObject(List x) { | 155 deserializeObject(List x) { |
114 String tag = x[0]; | 156 String tag = x[0]; |
115 switch (tag) { | 157 switch (tag) { |
116 case 'funcref': return deserializeFunction(x); | 158 case 'funcref': return deserializeFunction(x); |
| 159 case 'objref': return deserializeProxy(x); |
117 default: throw 'Illegal object type: $x'; | 160 default: throw 'Illegal object type: $x'; |
118 } | 161 } |
119 } | 162 } |
120 | 163 |
121 deserializeFunction(List x) { | 164 deserializeFunction(List x) { |
122 var id = x[1]; | 165 var id = x[1]; |
123 SendPortSync port = deserializeSendPort(x[2]); | 166 SendPortSync port = deserializeSendPort(x[2]); |
124 // TODO: Support varargs when there is support in the language. | 167 // TODO: Support varargs when there is support in the language. |
125 return ([arg0 = _UNSPECIFIED, arg1 = _UNSPECIFIED, | 168 return ([arg0 = _UNSPECIFIED, arg1 = _UNSPECIFIED, |
126 arg2 = _UNSPECIFIED, arg3 = _UNSPECIFIED]) { | 169 arg2 = _UNSPECIFIED, arg3 = _UNSPECIFIED]) { |
127 var args = [arg0, arg1, arg2, arg3]; | 170 var args = [arg0, arg1, arg2, arg3]; |
128 var last = args.indexOf(_UNSPECIFIED); | 171 var last = args.indexOf(_UNSPECIFIED); |
129 if (last >= 0) args = args.getRange(0, last); | 172 if (last >= 0) args = args.getRange(0, last); |
130 var message = [id, args]; | 173 var message = [id, args]; |
131 return port.callSync(message); | 174 return port.callSync(message); |
132 }; | 175 }; |
133 } | 176 } |
| 177 |
| 178 deserializeProxy(x) { |
| 179 String tag = x[1]; |
| 180 switch (tag) { |
| 181 case 'nativejs': |
| 182 var id = x[2]; |
| 183 return new JsProxy._internal(id); |
| 184 case 'dart': |
| 185 var id = x[2]; |
| 186 // TODO(vsm): Check for isolate id. If the isolate isn't the |
| 187 // current isolate, return a DartProxy. |
| 188 return _getDartProxyObj(id); |
| 189 default: throw 'Illegal proxy: $x'; |
| 190 } |
| 191 } |
134 } | 192 } |
135 | 193 |
136 // The receiver is JS. | 194 // The receiver is JS. |
137 class _JsSendPortSync implements SendPortSync { | 195 class _JsSendPortSync implements SendPortSync { |
138 | 196 |
139 num _id; | 197 num _id; |
140 _JsSendPortSync(this._id); | 198 _JsSendPortSync(this._id); |
141 | 199 |
142 callSync(var message) { | 200 callSync(var message) { |
143 var serialized = _serialize(message); | 201 var serialized = _serialize(message); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 | 275 |
218 ReceivePortSync() { | 276 ReceivePortSync() { |
219 if (_portIdCount == null) { | 277 if (_portIdCount == null) { |
220 _portIdCount = 0; | 278 _portIdCount = 0; |
221 _portMap = new Map<int, ReceivePortSync>(); | 279 _portMap = new Map<int, ReceivePortSync>(); |
222 } | 280 } |
223 _portId = _portIdCount++; | 281 _portId = _portIdCount++; |
224 _portMap[_portId] = this; | 282 _portMap[_portId] = this; |
225 } | 283 } |
226 | 284 |
227 static int get _isolateId() { | 285 static int get _isolateId { |
228 // TODO(vsm): Make this coherent with existing isolate code. | 286 // TODO(vsm): Make this coherent with existing isolate code. |
229 if (_cachedIsolateId == null) { | 287 if (_cachedIsolateId == null) { |
230 _cachedIsolateId = _getNewIsolateId(); | 288 _cachedIsolateId = _getNewIsolateId(); |
231 } | 289 } |
232 return _cachedIsolateId; | 290 return _cachedIsolateId; |
233 } | 291 } |
234 | 292 |
235 static String _getListenerName(isolateId, portId) => | 293 static String _getListenerName(isolateId, portId) => |
236 'dart-port-$isolateId-$portId'; | 294 'dart-port-$isolateId-$portId'; |
237 String get _listenerName() => _getListenerName(_isolateId, _portId); | 295 String get _listenerName => _getListenerName(_isolateId, _portId); |
238 | 296 |
239 void receive(callback(var message)) { | 297 void receive(callback(var message)) { |
240 _callback = callback; | 298 _callback = callback; |
241 if (_listener === null) { | 299 if (_listener === null) { |
242 _listener = (TextEvent e) { | 300 _listener = (TextEvent e) { |
243 var data = JSON.parse(e.data); | 301 var data = JSON.parse(e.data); |
244 var replyTo = data[0]; | 302 var replyTo = data[0]; |
245 var message = _deserialize(data[1]); | 303 var message = _deserialize(data[1]); |
246 var result = _callback(message); | 304 var result = _callback(message); |
247 _dispatchEvent(replyTo, _serialize(result)); | 305 _dispatchEvent(replyTo, _serialize(result)); |
(...skipping 18 matching lines...) Expand all Loading... |
266 return new _RemoteSendPortSync(isolateId, portId); | 324 return new _RemoteSendPortSync(isolateId, portId); |
267 } | 325 } |
268 } | 326 } |
269 } | 327 } |
270 | 328 |
271 void _dispatchEvent(String receiver, var message) { | 329 void _dispatchEvent(String receiver, var message) { |
272 var event = document.$dom_createEvent('TextEvent'); | 330 var event = document.$dom_createEvent('TextEvent'); |
273 event.initTextEvent(receiver, false, false, window, JSON.stringify(message)); | 331 event.initTextEvent(receiver, false, false, window, JSON.stringify(message)); |
274 window.$dom_dispatchEvent(event); | 332 window.$dom_dispatchEvent(event); |
275 } | 333 } |
OLD | NEW |