OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 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 | 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 // Patch file for dart:convert library. | 5 // Patch file for dart:convert library. |
6 | 6 |
7 import 'dart:_js_helper' show patch; | 7 import 'dart:_js_helper' show patch; |
8 import 'dart:_foreign_helper' show JS; | 8 import 'dart:_foreign_helper' show JS; |
9 import 'dart:_interceptors' show JSExtendableArray; | 9 import 'dart:_interceptors' show JSExtendableArray; |
10 import 'dart:_internal' show MappedIterable; | 10 import 'dart:_internal' show MappedIterable; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 return _convertJsonToDart(parsed, reviver); | 45 return _convertJsonToDart(parsed, reviver); |
46 } | 46 } |
47 } | 47 } |
48 | 48 |
49 /** | 49 /** |
50 * Walks the raw JavaScript value [json], replacing JavaScript Objects with | 50 * Walks the raw JavaScript value [json], replacing JavaScript Objects with |
51 * Maps. [json] is expected to be freshly allocated so elements can be replaced | 51 * Maps. [json] is expected to be freshly allocated so elements can be replaced |
52 * in-place. | 52 * in-place. |
53 */ | 53 */ |
54 _convertJsonToDart(json, reviver(key, value)) { | 54 _convertJsonToDart(json, reviver(key, value)) { |
55 var revive = reviver == null ? (key, value) => value : reviver; | 55 assert(reviver != null); |
56 | |
57 walk(e) { | 56 walk(e) { |
58 // JavaScript null, string, number, bool are in the correct representation. | 57 // JavaScript null, string, number, bool are in the correct representation. |
59 if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) { | 58 if (JS('bool', '# == null', e) || JS('bool', 'typeof # != "object"', e)) { |
60 return e; | 59 return e; |
61 } | 60 } |
62 | 61 |
63 // This test is needed to avoid identifing '{"__proto__":[]}' as an Array. | 62 // This test is needed to avoid identifing '{"__proto__":[]}' as an Array. |
64 // TODO(sra): Replace this test with cheaper '#.constructor === Array' when | 63 // TODO(sra): Replace this test with cheaper '#.constructor === Array' when |
65 // bug 621 below is fixed. | 64 // bug 621 below is fixed. |
66 if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) { | 65 if (JS('bool', 'Object.getPrototypeOf(#) === Array.prototype', e)) { |
67 // Teach compiler the type is known by passing it through a JS-expression. | |
68 var list = JS('JSExtendableArray', '#', e); | |
69 // In-place update of the elements since JS Array is a Dart List. | 66 // In-place update of the elements since JS Array is a Dart List. |
70 for (int i = 0; i < list.length; i++) { | 67 for (int i = 0; i < JS('int', '#.length', e); i++) { |
71 // Use JS indexing to avoid range checks. We know this is the only | 68 // Use JS indexing to avoid range checks. We know this is the only |
72 // reference to the list, but the compiler will likely never be able to | 69 // reference to the list, but the compiler will likely never be able to |
73 // tell that this instance of the list cannot have its length changed by | 70 // tell that this instance of the list cannot have its length changed by |
74 // the reviver even though it later will be passed to the reviver at the | 71 // the reviver even though it later will be passed to the reviver at the |
75 // outer level. | 72 // outer level. |
76 var item = JS('', '#[#]', list, i); | 73 var item = JS('', '#[#]', e, i); |
77 JS('', '#[#]=#', list, i, revive(i, walk(item))); | 74 JS('', '#[#]=#', e, i, reviver(i, walk(item))); |
78 } | 75 } |
79 return list; | 76 return e; |
80 } | 77 } |
81 | 78 |
82 // Otherwise it is a plain Object, so copy to a Map. | 79 // Otherwise it is a plain object, so copy to a JSON map, so we process |
83 var keys = JS('JSExtendableArray', 'Object.keys(#)', e); | 80 // and revive all entries recursively. |
84 Map map = {}; | 81 _JsonMap map = new _JsonMap(e); |
| 82 var processed = map._processed; |
| 83 List<String> keys = map._computeKeys(); |
85 for (int i = 0; i < keys.length; i++) { | 84 for (int i = 0; i < keys.length; i++) { |
86 String key = keys[i]; | 85 String key = keys[i]; |
87 map[key] = revive(key, walk(JS('', '#[#]', e, key))); | 86 var revived = reviver(key, walk(JS('', '#[#]', e, key))); |
| 87 JS('', '#[#]=#', processed, key, revived); |
88 } | 88 } |
89 // V8 has a bug with properties named "__proto__" | 89 |
90 // https://code.google.com/p/v8/issues/detail?id=621 | 90 // Update the JSON map structure so future access is cheaper. |
91 var proto = JS('', '#.__proto__', e); | 91 map._original = processed; // Don't keep two objects around. |
92 // __proto__ can be undefined on IE9. | |
93 if (JS('bool', | |
94 'typeof # !== "undefined" && # !== Object.prototype', | |
95 proto, proto)) { | |
96 map['__proto__'] = revive('__proto__', walk(proto)); | |
97 } | |
98 return map; | 92 return map; |
99 } | 93 } |
100 | 94 |
101 return revive(null, walk(json)); | 95 return reviver(null, walk(json)); |
102 } | 96 } |
103 | 97 |
104 _convertJsonToDartLazy(object) { | 98 _convertJsonToDartLazy(object) { |
105 // JavaScript null and undefined are represented as null. | 99 // JavaScript null and undefined are represented as null. |
106 if (object == null) return null; | 100 if (object == null) return null; |
107 | 101 |
108 // JavaScript string, number, bool already has the correct representation. | 102 // JavaScript string, number, bool already has the correct representation. |
109 if (JS('bool', 'typeof # != "object"', object)) { | 103 if (JS('bool', 'typeof # != "object"', object)) { |
110 return object; | 104 return object; |
111 } | 105 } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
172 | 166 |
173 Iterable get values { | 167 Iterable get values { |
174 if (_isUpgraded) return _upgradedMap.values; | 168 if (_isUpgraded) return _upgradedMap.values; |
175 return new MappedIterable(_computeKeys(), (each) => this[each]); | 169 return new MappedIterable(_computeKeys(), (each) => this[each]); |
176 } | 170 } |
177 | 171 |
178 operator[]=(key, value) { | 172 operator[]=(key, value) { |
179 if (_isUpgraded) { | 173 if (_isUpgraded) { |
180 _upgradedMap[key] = value; | 174 _upgradedMap[key] = value; |
181 } else if (containsKey(key)) { | 175 } else if (containsKey(key)) { |
182 _setProperty(_processed, key, value); | 176 var processed = _processed; |
183 _setProperty(_original, key, null); // Reclaim memory. | 177 _setProperty(processed, key, value); |
| 178 var original = _original; |
| 179 if (!identical(original, processed)) { |
| 180 _setProperty(original, key, null); // Reclaim memory. |
| 181 } |
184 } else { | 182 } else { |
185 _upgrade()[key] = value; | 183 _upgrade()[key] = value; |
186 } | 184 } |
187 } | 185 } |
188 | 186 |
189 void addAll(Map other) { | 187 void addAll(Map other) { |
190 other.forEach((key, value) { | 188 other.forEach((key, value) { |
191 this[key] = value; | 189 this[key] = value; |
192 }); | 190 }); |
193 } | 191 } |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 static _newJavaScriptObject() | 334 static _newJavaScriptObject() |
337 => JS('=Object', 'Object.create(null)'); | 335 => JS('=Object', 'Object.create(null)'); |
338 } | 336 } |
339 | 337 |
340 @patch | 338 @patch |
341 class _Utf8Encoder { | 339 class _Utf8Encoder { |
342 // Use Uint8List when supported on all platforms. | 340 // Use Uint8List when supported on all platforms. |
343 @patch | 341 @patch |
344 static List<int> _createBuffer(int size) => new List<int>(size); | 342 static List<int> _createBuffer(int size) => new List<int>(size); |
345 } | 343 } |
OLD | NEW |