| 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 |