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

Side by Side Diff: sdk/lib/js/dart2js/js.dart

Issue 15782009: RFC: introduce dart:js (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 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) 2013, 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 library dart.js;
6
7 import 'dart:async' show runAsync;
8 import 'dart:html' show Element, document;
vsm 2013/06/06 17:06:41 Can you try killing the two imports above and test
9 import 'dart:_foreign_helper' show JS;
10 import 'dart:_js_helper' show convertDartClosureToJS;
11
12 JsObject get context {
13 _enterScopeIfNeeded();
vsm 2013/05/29 04:55:39 Shall we make scopes no-ops here and get rid of th
alexandre.ardhuin 2013/05/31 19:11:13 I just made some tests. On js_tests.dart we loose
vsm 2013/06/06 17:06:41 Did you eliminate dart:async above as well? On 20
14 return new JsObject._fromJs(JS('Object', 'window'));
15 }
16
17 int _scopeDepth = 0;
18
19 int _dartObjectsTotal = 0;
20 final Map<int, List> _dartObjects = new Map<int, List>();
21
22 int _jsObjectsTotal = 0;
23 final List<JsObject> _jsObjects = new List<JsObject>();
24
25 void _enterScopeIfNeeded() {
26 if (_scopeDepth == 0) {
27 final depth = _enterScope();
28 runAsync(() => _exitScope(depth));
29 }
30 }
31
32 scoped(f) {
33 final depth = _enterScope();
34 try {
35 return f();
36 } finally {
37 _exitScope(depth);
38 }
39 }
40
41 int _enterScope() => ++_scopeDepth;
42
43 void _exitScope(int depth) {
44 assert(_scopeDepth == depth);
45 _dartObjects.remove(_scopeDepth);
46 _jsObjects
47 ..where((JsObject e) => e._scope == depth).forEach((JsObject e) {
48 e._scope = null;
49 })
50 ..removeWhere((JsObject e) => e._scope == depth);
51 _scopeDepth--;
52 }
53
54 int $experimentalEnterScope() {
vsm 2013/06/06 17:06:41 These can go.
55 return _enterScope();
56 }
57
58 void $experimentalExitScope(int depth) {
59 _exitScope(depth);
60 }
61
62 final _globalDartObjects = [];
63 final _globalJsObjects = new List<JsObject>();
64
65 dynamic retain(Serializable<JsObject> object) {
66 final JsObject jsObject = object.toJs();
67 jsObject._scope = 0;
68 _globalJsObjects.add(jsObject);
69 _jsObjects.removeWhere((e) => identical(e, jsObject));
70 return object;
71 }
72 void release(Serializable<JsObject> object) {
73 final JsObject jsObject = object.toJs();
74 jsObject._scope = null;
75 _removeLast(_globalJsObjects, jsObject);
76 }
77
78 void _removeLast(List l, object) {
79 for (int i = l.length - 1; i >= 0; i--) {
80 var element = l[i];
81 if (identical(element, object)) {
82 l.removeAt(i);
83 return;
84 }
85 }
86 }
87
88 JsObject jsify(dynamic data) => data == null ? null : new JsObject._json(data);
89
90 class Callback implements Serializable<JsFunction> {
91 final bool _manualDispose;
vsm 2013/06/06 17:06:41 We can try getting rid of _manualDispose and relat
92 final Function _f; // here to allow capture in closure
93 final bool _withThis; // here to allow capture in closure
94 Object _jsFunction;
vsm 2013/06/06 17:06:41 This should probably be typed dynamic. That is wh
95
96 Callback._internal(this._manualDispose, this._f, this._withThis) {
97 _globalDartObjects.add(_f);
98 _jsFunction = JS('Object', r'''
99 (function(){
100 var f = #;
101 return function(){
102 return f(this, Array.prototype.slice.apply(arguments));
103 };
104 }).apply(this)''', convertDartClosureToJS(_call, 2));
105 }
106
107 _call(thisArg, List args) {
108 if (!_globalDartObjects.any((e) => identical(e, _f)) &&
109 !_dartObjects.values.expand((e) => e).any((e) => identical(e, _f))) {
110 throw 'function has already been disposed';
111 }
112
113 final arguments = new List.from(args);
114 if (_withThis) arguments.insert(0, thisArg);
115 final deserializedArgs = arguments.map(_deserialize).toList();
116 if (_manualDispose) {
117 return _serialize(Function.apply(_f, deserializedArgs));
118 } else {
119 try {
120 return _serialize(Function.apply(_f, deserializedArgs));
121 } finally {
122 _dispose();
123 }
124 }
125 }
126
127 _dispose() {
128 _removeLast(_globalDartObjects, _f);
129 }
130
131 JsFunction toJs() => new JsFunction._fromJs(_jsFunction);
132
133 dispose() {
134 assert(_manualDispose);
135 _dispose();
136 }
137
138 factory Callback.once(Function f, {bool withThis: false}) =>
139 new Callback._internal(false, f, withThis);
140
141 factory Callback.many(Function f, {bool withThis: false}) =>
142 new Callback._internal(true, f, withThis);
143 }
144
145 class JsObject implements Serializable<JsObject> {
146 final Object _jsObject;
147 int _scope = _scopeDepth;
148
149 JsObject._fromJs(this._jsObject) {
150 if (_scopeDepth == 0) throw 'Cannot allocate a proxy outside of a scope.';
151 _jsObjectsTotal++;
152 _jsObjects.add(this);
153 }
154
155 factory JsObject(Serializable<JsFunction> constructor, [List arguments]) {
156 _enterScopeIfNeeded();
157 final constr = _serialize(constructor);
158 if (arguments == null) {
159 return new JsObject._fromJs(JS('Object', 'new #()', constr));
160 }
161 final args = arguments.map(_serialize).toList();
162 switch (args.length) {
163 case 0:
164 return new JsObject._fromJs(JS('Object', 'new #()', constr));
165 case 1:
166 return new JsObject._fromJs(JS('Object', 'new #(#)', constr, args[0]));
167 case 2:
168 return new JsObject._fromJs(JS('Object', 'new #(#,#)', constr, args[0],
169 args[1]));
170 case 3:
171 return new JsObject._fromJs(JS('Object', 'new #(#,#,#)', constr,
172 args[0], args[1], args[2]));
173 case 4:
174 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#)', constr,
175 args[0], args[1], args[2], args[3]));
176 case 5:
177 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#)', constr,
178 args[0], args[1], args[2], args[3], args[4]));
179 case 6:
180 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#,#)', constr,
181 args[0], args[1], args[2], args[3], args[4], args[5]));
182 case 7:
183 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#,#,#)', constr,
184 args[0], args[1], args[2], args[3], args[4], args[5], args[6]));
185 case 8:
186 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#,#,#,#)',
187 constr, args[0], args[1], args[2], args[3], args[4], args[5],
188 args[6], args[7]));
189 case 9:
190 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#,#,#,#,#)',
191 constr, args[0], args[1], args[2], args[3], args[4], args[5],
192 args[6], args[7], args[8]));
193 case 10:
194 return new JsObject._fromJs(JS('Object', 'new #(#,#,#,#,#,#,#,#,#,#)',
195 constr, args[0], args[1], args[2], args[3], args[4], args[5],
196 args[6], args[7], args[8], args[9]));
197 }
198 return new JsObject._fromJs(JS('Object', r'''(function(){
199 var Type = function(){};
200 Type.prototype = #.prototype;
201 var instance = new Type();
202 ret = constructor.apply(instance, #);
203 ret = Object(ret) === ret ? ret : instance;
204 })()''', constr, args));
205 }
206
207 factory JsObject._json(data) {
208 _enterScopeIfNeeded();
209 return new JsObject._fromJs(_serializeDataTree(data));
210 }
211
212 static _serializeDataTree(data) {
213 if (data is Map) {
214 final serializedData = JS('Object', '{}');
215 for (var key in data.keys) {
216 JS('Object', '#[#]=#', serializedData, key,
217 _serializeDataTree(data[key]));
218 }
219 return serializedData;
220 } else if (data is Iterable) {
221 return data.map(_serializeDataTree).toList();
222 } else {
223 return _serialize(data);
224 }
225 }
226
227 JsObject toJs() => this;
228
229 operator[](key) => _deserialize(JS('var', '#[#]', _serialize(this), key));
230 operator[]=(key, value) => JS('void', '#[#]=#', _serialize(this), key,
231 _serialize(value));
232
233 operator==(other) => identical(this, other) ||
234 (other is JsObject && JS('bool', '# == #', _serialize(this),
235 _serialize(other)));
236
237 bool hasProperty(String property) => JS('bool', '# in #', property,
238 _serialize(this));
239
240 void deleteProperty(String name) {
241 JS('void', 'delete #[#]', _serialize(this), name);
242 }
243
244 bool instanceof(Serializable<JsFunction> type) =>
245 JS('bool', '# instanceof #', _serialize(this), _serialize(type));
246
247 String toString() {
248 try {
249 return JS('String', '#.toString()', _serialize(this));
250 } catch(e) {
251 return super.toString();
252 }
253 }
254
255 callMethod(String name, [List args]) =>
256 _deserialize(JS('var', '#[#].apply(#, #)', _serialize(this), name,
257 _serialize(this),
258 args == null ? null : args.map(_serialize).toList()));
259 }
260
261 class JsFunction extends JsObject implements Serializable<JsFunction> {
262 JsFunction._fromJs(jsObject) : super._fromJs(jsObject);
263 apply(thisArg, [List args]) =>
264 _deserialize(JS('var', '#.apply(#, #)', _serialize(this),
265 _serialize(thisArg),
266 args == null ? null : args.map(_serialize).toList()));
267 }
268
269 abstract class Serializable<T> {
270 T toJs();
271 }
272
273 dynamic _serialize(dynamic o) {
vsm 2013/06/06 17:06:41 Is this really serializing? Perhaps call _convert
274 if (o == null) {
275 return null;
276 } else if (o is String || o is num || o is bool) {
277 return o;
278 } else if (o is Element && (o.document == null || o.document == document)) {
vsm 2013/06/06 17:06:41 Let's try removing the dependence on dart:html. C
279 return o;
280 } else if (o is JsObject) {
281 if (o._scope == null){
282 throw 'Proxy $o has been invalidated';
283 }
284 return o._jsObject;
285 } else if (o is Serializable) {
286 return _serialize(o.toJs());
287 } else {
288 _enterScopeIfNeeded();
289 _dartObjectsTotal++;
290 _dartObjects.putIfAbsent(_scopeDepth, () => []).add(o);
291 return o;
vsm 2013/06/06 17:06:41 Does this mean we're passing a raw Dart object to
292 }
293 }
294 dynamic _deserialize(dynamic o) {
vsm 2013/06/06 17:06:42 _convertToDart?
295 if (o == null) {
296 return null;
297 } else if (o is num || o is String || o is bool) {
298 return o;
299 } else if (JS('bool', '# instanceof Element && '
300 '(#.ownerDocument == null || #.ownerDocument === document)', o, o, o)) {
301 return JS('Element', '#', o);
302 } else if (JS('bool', '# instanceof Function', o)) {
303 return new JsFunction._fromJs(JS('Function', '#', o));
304 } else if (_globalDartObjects.any((e) => identical(e, o)) ||
305 _dartObjects.values.expand((e) => e).any((e) => identical(e, o))) {
306 return o;
307 } else {
308 return new JsObject._fromJs(JS('Object', '#', o));
309 }
310 }
311
312 int proxyCount({all: false, dartOnly: false, jsOnly: false}) {
313 final js = !dartOnly;
vsm 2013/06/06 17:06:42 Note, if you're getting rid of scopes, you can try
314 final dart = !jsOnly;
315 var sum = 0;
316 if (!all) {
317 if (js)
318 sum += _globalJsObjects.length;
319 if (dart)
320 sum += _globalDartObjects.length;
321 } else {
322 if (js)
323 sum += _jsObjectsTotal;
324 if (dart)
325 sum += _dartObjectsTotal;
326 }
327 return sum;
328 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698