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