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 // Bootstrap support for Dart scripts on the page as this script. | 5 // Bootstrap support for Dart scripts on the page as this script. |
6 if (navigator.webkitStartDart) { | 6 if (navigator.webkitStartDart) { |
7 if (!navigator.webkitStartDart()) { | 7 if (!navigator.webkitStartDart()) { |
8 document.body.innerHTML = 'This build has expired. Please download a new Da
rtium at http://www.dartlang.org/dartium/index.html'; | 8 document.body.innerHTML = 'This build has expired. Please download a new Da
rtium at http://www.dartlang.org/dartium/index.html'; |
9 } | 9 } |
10 } else { | 10 } else { |
(...skipping 28 matching lines...) Expand all Loading... |
39 // --------------------------------------------------------------------------- | 39 // --------------------------------------------------------------------------- |
40 function SendPortSync() { | 40 function SendPortSync() { |
41 } | 41 } |
42 | 42 |
43 function ReceivePortSync() { | 43 function ReceivePortSync() { |
44 this.id = ReceivePortSync.id++; | 44 this.id = ReceivePortSync.id++; |
45 ReceivePortSync.map[this.id] = this; | 45 ReceivePortSync.map[this.id] = this; |
46 } | 46 } |
47 | 47 |
48 (function() { | 48 (function() { |
49 // Track proxied functions. | 49 function RefTable(name) { |
50 // TODO: Fix leaks, particularly in dart2js case. | 50 // TODO(vsm): Fix leaks, particularly in dart2js case. |
51 var functionRefMap = {}; | 51 this.name = name; |
| 52 this.map = {}; |
| 53 this.id = 0; |
| 54 this.initialized = false; |
| 55 } |
| 56 |
| 57 RefTable.prototype.nextId = function () { return this.id++; } |
52 | 58 |
53 var nextFunctionRefId = 0; | 59 RefTable.prototype.makeRef = function (obj) { |
54 | 60 this.initializeOnce(); |
55 function functionRefDispatch(message) { | 61 // TODO(vsm): Cache refs for each obj. |
56 var id = message[0]; | 62 var ref = this.name + '-' + this.nextId(); |
57 var args = message[1]; | 63 this.map[ref] = obj; |
58 var f = functionRefMap[id]; | |
59 // TODO: Should we capture this automatically? | |
60 return f.apply(null, args); | |
61 } | |
62 | |
63 var functionRefPort = null; | |
64 | |
65 function makeFunctionRef(f) { | |
66 if (functionRefPort == null) { | |
67 var port = new ReceivePortSync(); | |
68 port.receive(functionRefDispatch); | |
69 functionRefPort = port.toSendPort(); | |
70 } | |
71 var ref = 'func-ref-' + (nextFunctionRefId++); | |
72 functionRefMap[ref] = f; | |
73 return ref; | 64 return ref; |
74 } | 65 } |
75 | 66 |
| 67 RefTable.prototype.initializeOnce = function () { |
| 68 if (!this.initialized) { |
| 69 this.initialize(); |
| 70 } |
| 71 this.initialized = true; |
| 72 } |
| 73 |
| 74 // Overridable initialization on first use hook. |
| 75 RefTable.prototype.initialize = function () {} |
| 76 |
| 77 RefTable.prototype.get = function (ref) { |
| 78 return this.map[ref]; |
| 79 } |
| 80 |
| 81 function FunctionRefTable() {} |
| 82 |
| 83 FunctionRefTable.prototype = new RefTable('func-ref'); |
| 84 |
| 85 FunctionRefTable.prototype.initialize = function () { |
| 86 var receivePort = new ReceivePortSync(); |
| 87 map = this.map; |
| 88 receivePort.receive(function (message) { |
| 89 var id = message[0]; |
| 90 var args = message[1]; |
| 91 var f = map[id]; |
| 92 // TODO(vsm): Should we capture this automatically? |
| 93 return f.apply(null, args); |
| 94 }); |
| 95 this.port = receivePort.toSendPort(); |
| 96 } |
| 97 |
| 98 var functionRefTable = new FunctionRefTable(); |
| 99 |
| 100 function JSRefTable() {} |
| 101 |
| 102 JSRefTable.prototype = new RefTable('js-ref'); |
| 103 |
| 104 var jsRefTable = new JSRefTable(); |
| 105 |
| 106 function DartProxy(id) { |
| 107 // TODO(vsm): Set isolate id. |
| 108 this.id = id; |
| 109 } |
| 110 |
76 function serialize(message) { | 111 function serialize(message) { |
77 var visited = []; | 112 var visited = []; |
78 function checkedSerialization(obj, serializer) { | 113 function checkedSerialization(obj, serializer) { |
79 // Implementation detail: for now use linear search. | 114 // Implementation detail: for now use linear search. |
80 // Another option is expando, but it may prohibit | 115 // Another option is expando, but it may prohibit |
81 // VM optimizations (like putting object into slow mode | 116 // VM optimizations (like putting object into slow mode |
82 // on property deletion.) | 117 // on property deletion.) |
83 var id = visited.indexOf(obj); | 118 var id = visited.indexOf(obj); |
84 if (id != -1) return [ 'ref', id ]; | 119 if (id != -1) return [ 'ref', id ]; |
85 var id = visited.length; | 120 var id = visited.length; |
(...skipping 14 matching lines...) Expand all Loading... |
100 for (var i = 0; i < message.length; i++) { | 135 for (var i = 0; i < message.length; i++) { |
101 values[i] = doSerialize(message[i]); | 136 values[i] = doSerialize(message[i]); |
102 } | 137 } |
103 return [ 'list', id, values ]; | 138 return [ 'list', id, values ]; |
104 }); | 139 }); |
105 } else if (message instanceof LocalSendPortSync) { | 140 } else if (message instanceof LocalSendPortSync) { |
106 return [ 'sendport', 'nativejs', message.receivePort.id ]; | 141 return [ 'sendport', 'nativejs', message.receivePort.id ]; |
107 } else if (message instanceof DartSendPortSync) { | 142 } else if (message instanceof DartSendPortSync) { |
108 return [ 'sendport', 'dart', message.isolateId, message.portId ]; | 143 return [ 'sendport', 'dart', message.isolateId, message.portId ]; |
109 } else if (message instanceof Function) { | 144 } else if (message instanceof Function) { |
110 return [ 'funcref', makeFunctionRef(message), | 145 return [ 'funcref', functionRefTable.makeRef(message), |
111 doSerialize(functionRefPort) ]; | 146 doSerialize(functionRefTable.port) ]; |
| 147 } else if (message instanceof DartProxy) { |
| 148 return [ 'objref', 'dart', message.id ]; |
| 149 } else if (message.__proto__ != {}.__proto__) { |
| 150 // TODO(vsm): Is the above portable and what we want? |
| 151 // Proxy non-map Objects. |
| 152 return [ 'objref', 'nativejs', jsRefTable.makeRef(message) ]; |
112 } else { | 153 } else { |
113 return checkedSerialization(message, function(id) { | 154 return checkedSerialization(message, function(id) { |
114 var keys = Object.getOwnPropertyNames(message); | 155 var keys = Object.getOwnPropertyNames(message); |
115 var values = new Array(keys.length); | 156 var values = new Array(keys.length); |
116 for (var i = 0; i < keys.length; i++) { | 157 for (var i = 0; i < keys.length; i++) { |
117 values[i] = doSerialize(message[keys[i]]); | 158 values[i] = doSerialize(message[keys[i]]); |
118 } | 159 } |
119 return [ 'map', id, keys, values ]; | 160 return [ 'map', id, keys, values ]; |
120 }); | 161 }); |
121 } | 162 } |
122 } | 163 } |
123 return doSerialize(message); | 164 return doSerialize(message); |
124 } | 165 } |
125 | 166 |
126 function deserialize(message) { | 167 function deserialize(message) { |
127 return deserializeHelper(message); | 168 return deserializeHelper(message); |
128 } | 169 } |
129 | 170 |
130 function deserializeHelper(x) { | 171 function deserializeHelper(message) { |
131 if (x == null || | 172 if (message == null || |
132 typeof(x) == 'string' || | 173 typeof(message) == 'string' || |
133 typeof(x) == 'number' || | 174 typeof(message) == 'number' || |
134 typeof(x) == 'boolean') { | 175 typeof(message) == 'boolean') { |
135 return x; | 176 return message; |
136 } | 177 } |
137 switch (x[0]) { | 178 switch (message[0]) { |
138 case 'map': return deserializeMap(x); | 179 case 'map': return deserializeMap(message); |
139 case 'sendport': return deserializeSendPort(x); | 180 case 'sendport': return deserializeSendPort(message); |
140 case 'list': return deserializeList(x); | 181 case 'list': return deserializeList(message); |
141 case 'funcref': return deserializeFunction(x); | 182 case 'funcref': return deserializeFunction(message); |
| 183 case 'objref': return deserializeProxy(message); |
142 default: throw 'unimplemented'; | 184 default: throw 'unimplemented'; |
143 } | 185 } |
144 } | 186 } |
145 | 187 |
146 function deserializeMap(x) { | 188 function deserializeMap(message) { |
147 var result = { }; | 189 var result = { }; |
148 var id = x[1]; | 190 var id = message[1]; |
149 var keys = x[2]; | 191 var keys = message[2]; |
150 var values = x[3]; | 192 var values = message[3]; |
151 for (var i = 0, length = keys.length; i < length; i++) { | 193 for (var i = 0, length = keys.length; i < length; i++) { |
152 var key = deserializeHelper(keys[i]); | 194 var key = deserializeHelper(keys[i]); |
153 var value = deserializeHelper(values[i]); | 195 var value = deserializeHelper(values[i]); |
154 result[key] = value; | 196 result[key] = value; |
155 } | 197 } |
156 return result; | 198 return result; |
157 } | 199 } |
158 | 200 |
159 function deserializeSendPort(x) { | 201 function deserializeSendPort(message) { |
160 var tag = x[1]; | 202 var tag = message[1]; |
161 switch (tag) { | 203 switch (tag) { |
162 case 'nativejs': | 204 case 'nativejs': |
163 var id = x[2]; | 205 var id = message[2]; |
164 return new LocalSendPortSync(ReceivePortSync.map[id]); | 206 return new LocalSendPortSync(ReceivePortSync.map[id]); |
165 case 'dart': | 207 case 'dart': |
166 var isolateId = x[2]; | 208 var isolateId = message[2]; |
167 var portId = x[3]; | 209 var portId = message[3]; |
168 return new DartSendPortSync(isolateId, portId); | 210 return new DartSendPortSync(isolateId, portId); |
169 default: | 211 default: |
170 throw 'Illegal SendPortSync type: $tag'; | 212 throw 'Illegal SendPortSync type: $tag'; |
171 } | 213 } |
172 } | 214 } |
173 | 215 |
174 function deserializeList(x) { | 216 function deserializeList(message) { |
175 var values = x[2]; | 217 var values = message[2]; |
176 var length = values.length; | 218 var length = values.length; |
177 var result = new Array(length); | 219 var result = new Array(length); |
178 for (var i = 0; i < length; i++) { | 220 for (var i = 0; i < length; i++) { |
179 result[i] = deserializeHelper(values[i]); | 221 result[i] = deserializeHelper(values[i]); |
180 } | 222 } |
181 return result; | 223 return result; |
182 } | 224 } |
183 | 225 |
184 function deserializeFunction(x) { | 226 function deserializeFunction(message) { |
185 var ref = x[1]; | 227 var ref = message[1]; |
186 var sendPort = deserializeSendPort(x[2]); | 228 var sendPort = deserializeSendPort(message[2]); |
187 // Number of arguments is not used as of now | 229 // Number of arguments is not used as of now |
188 // we cannot find it out for Dart function in pure Dart. | 230 // we cannot find it out for Dart function in pure Dart. |
189 return _makeFunctionFromRef(ref, sendPort); | 231 return _makeFunctionFromRef(ref, sendPort); |
190 } | 232 } |
191 | 233 |
| 234 function deserializeProxy(message) { |
| 235 var tag = message[1]; |
| 236 if (tag == 'nativejs') { |
| 237 var id = message[2]; |
| 238 return jsRefTable.map[id]; |
| 239 } else if (tag == 'dart') { |
| 240 var id = message[2]; |
| 241 return new DartProxy(id); |
| 242 } |
| 243 throw 'Illegal proxy object: ' + message; |
| 244 } |
| 245 |
192 window.registerPort = function(name, port) { | 246 window.registerPort = function(name, port) { |
193 var stringified = JSON.stringify(serialize(port)); | 247 var stringified = JSON.stringify(serialize(port)); |
194 window.localStorage['dart-port:' + name] = stringified; | 248 window.localStorage['dart-port:' + name] = stringified; |
195 }; | 249 }; |
196 | 250 |
197 window.lookupPort = function(name) { | 251 window.lookupPort = function(name) { |
198 var stringified = window.localStorage['dart-port:' + name]; | 252 var stringified = window.localStorage['dart-port:' + name]; |
199 return deserialize(JSON.parse(stringified)); | 253 return deserialize(JSON.parse(stringified)); |
200 }; | 254 }; |
201 | 255 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
267 var listener = function (e) { | 321 var listener = function (e) { |
268 result = JSON.parse(e.data); | 322 result = JSON.parse(e.data); |
269 }; | 323 }; |
270 window.addEventListener(source, listener, false); | 324 window.addEventListener(source, listener, false); |
271 dispatchEvent(target, [source, serialized]); | 325 dispatchEvent(target, [source, serialized]); |
272 window.removeEventListener(source, listener, false); | 326 window.removeEventListener(source, listener, false); |
273 return deserialize(result); | 327 return deserialize(result); |
274 } | 328 } |
275 | 329 |
276 // Leaking implementation. | 330 // Leaking implementation. |
277 // TODO: provide proper, backend-specific implementation. | 331 // TODO(vsm): provide proper, backend-specific implementation. |
278 function _makeFunctionFromRef(ref, sendPort) { | 332 function _makeFunctionFromRef(ref, sendPort) { |
279 return function() { | 333 return function() { |
280 return sendPort.callSync([ref, Array.prototype.slice.call(arguments)]); | 334 return sendPort.callSync([ref, Array.prototype.slice.call(arguments)]); |
281 } | 335 } |
282 } | 336 } |
283 })(); | 337 })(); |
OLD | NEW |