Chromium Code Reviews| 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 | 5 |
| 6 // Conversions for IDBKey. | 6 // Conversions for IDBKey. |
| 7 // | 7 // |
| 8 // Per http://www.w3.org/TR/IndexedDB/#key-construct | 8 // Per http://www.w3.org/TR/IndexedDB/#key-construct |
| 9 // | 9 // |
| 10 // "A value is said to be a valid key if it is one of the following types: Array | 10 // "A value is said to be a valid key if it is one of the following types: Array |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 51 * described at | 51 * described at |
| 52 * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interf aces.html#structured-clone | 52 * http://www.whatwg.org/specs/web-apps/current-work/multipage/common-dom-interf aces.html#structured-clone |
| 53 * https://www.khronos.org/registry/typedarray/specs/latest/#9 | 53 * https://www.khronos.org/registry/typedarray/specs/latest/#9 |
| 54 * | 54 * |
| 55 * Since the result of this function is expected to be passed only to JavaScript | 55 * Since the result of this function is expected to be passed only to JavaScript |
| 56 * operations that perform the structured clone algorithm which does not mutate | 56 * operations that perform the structured clone algorithm which does not mutate |
| 57 * its output, the result may share structure with the input [value]. | 57 * its output, the result may share structure with the input [value]. |
| 58 */ | 58 */ |
| 59 abstract class _StructuredClone { | 59 abstract class _StructuredClone { |
| 60 | 60 |
| 61 // TODO(sra): Replace slots with identity hash table. | 61 // Keep track of the clones, keyed by the original object. If we're |
| 62 var values = []; | 62 // not copying, these may be the same. |
| 63 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. | 63 var clones = new HashMap.identity(); |
|
sra1
2016/03/22 00:54:21
Be careful here.
The implementation of identityHa
Alan Knight
2016/03/22 18:00:01
OK, I moved the code to use an identity map down i
| |
| 64 | 64 |
| 65 int findSlot(value) { | 65 Object findSlot(value) { |
| 66 int length = values.length; | 66 return clones.putIfAbsent(value, () => null); |
| 67 for (int i = 0; i < length; i++) { | |
| 68 if (identical(values[i], value)) return i; | |
| 69 } | |
| 70 values.add(value); | |
| 71 copies.add(null); | |
| 72 return length; | |
| 73 } | 67 } |
| 74 readSlot(int i) => copies[i]; | 68 readSlot(Object original) => clones[original]; |
| 75 writeSlot(int i, x) { copies[i] = x; } | 69 writeSlot(Object original, clone) { clones[original] = clone; } |
| 76 cleanupSlots() {} // Will be needed if we mark objects with a property. | 70 cleanupSlots() {} // Will be needed if we mark objects with a property. |
| 77 bool cloneNotRequired(object); | 71 bool cloneNotRequired(object); |
| 78 newJsMap(); | 72 newJsMap(); |
| 79 newJsList(length); | 73 newJsList(length); |
| 80 void putIntoMap(map, key, value); | 74 void putIntoMap(map, key, value); |
| 81 | 75 |
| 82 // Returns the input, or a clone of the input. | 76 // Returns the input, or a clone of the input. |
| 83 walk(e) { | 77 walk(e) { |
| 84 if (e == null) return e; | 78 if (e == null) return e; |
| 85 if (e is bool) return e; | 79 if (e is bool) return e; |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 102 | 96 |
| 103 if (e is File) return e; | 97 if (e is File) return e; |
| 104 if (e is Blob) return e; | 98 if (e is Blob) return e; |
| 105 if (e is FileList) return e; | 99 if (e is FileList) return e; |
| 106 | 100 |
| 107 // TODO(sra): Firefox: How to convert _TypedImageData on the other end? | 101 // TODO(sra): Firefox: How to convert _TypedImageData on the other end? |
| 108 if (e is ImageData) return e; | 102 if (e is ImageData) return e; |
| 109 if (cloneNotRequired(e)) return e; | 103 if (cloneNotRequired(e)) return e; |
| 110 | 104 |
| 111 if (e is Map) { | 105 if (e is Map) { |
| 112 var slot = findSlot(e); | 106 var copy = findSlot(e); |
| 113 var copy = readSlot(slot); | |
| 114 if (copy != null) return copy; | 107 if (copy != null) return copy; |
| 115 copy = newJsMap(); | 108 copy = newJsMap(); |
| 116 writeSlot(slot, copy); | 109 writeSlot(e, copy); |
| 117 e.forEach((key, value) { | 110 e.forEach((key, value) { |
| 118 putIntoMap(copy, key, walk(value)); | 111 putIntoMap(copy, key, walk(value)); |
| 119 }); | 112 }); |
| 120 return copy; | 113 return copy; |
| 121 } | 114 } |
| 122 | 115 |
| 123 if (e is List) { | 116 if (e is List) { |
| 124 // Since a JavaScript Array is an instance of Dart List it is tempting | 117 // Since a JavaScript Array is an instance of Dart List it is tempting |
| 125 // in dart2js to avoid making a copy of the list if there is no need | 118 // in dart2js to avoid making a copy of the list if there is no need |
| 126 // to copy anything reachable from the array. However, the list may have | 119 // to copy anything reachable from the array. However, the list may have |
| 127 // non-native properties or methods from interceptors and such, e.g. | 120 // non-native properties or methods from interceptors and such, e.g. |
| 128 // an immutability marker. So we had to stop doing that. | 121 // an immutability marker. So we had to stop doing that. |
| 129 var slot = findSlot(e); | 122 var copy = findSlot(e); |
| 130 var copy = readSlot(slot); | |
| 131 if (copy != null) return copy; | 123 if (copy != null) return copy; |
| 132 copy = copyList(e, slot); | 124 copy = copyList(e); |
| 133 return copy; | 125 return copy; |
| 134 } | 126 } |
| 135 | 127 |
| 136 throw new UnimplementedError('structured clone of other type'); | 128 throw new UnimplementedError('structured clone of other type'); |
| 137 } | 129 } |
| 138 | 130 |
| 139 copyList(List e, int slot) { | 131 copyList(List e) { |
| 140 int i = 0; | 132 int i = 0; |
| 141 int length = e.length; | 133 int length = e.length; |
| 142 var copy = newJsList(length); | 134 var copy = newJsList(length); |
| 143 writeSlot(slot, copy); | 135 writeSlot(e, copy); |
| 144 for ( ; i < length; i++) { | 136 for ( ; i < length; i++) { |
| 145 copy[i] = walk(e[i]); | 137 copy[i] = walk(e[i]); |
| 146 } | 138 } |
| 147 return copy; | 139 return copy; |
| 148 } | 140 } |
| 149 | 141 |
| 150 convertDartToNative_PrepareForStructuredClone(value) { | 142 convertDartToNative_PrepareForStructuredClone(value) { |
| 151 var copy = walk(value); | 143 var copy = walk(value); |
| 152 cleanupSlots(); | 144 cleanupSlots(); |
| 153 return copy; | 145 return copy; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 167 * If necessary, JavaScript Dates are converted into Dart Dates. | 159 * If necessary, JavaScript Dates are converted into Dart Dates. |
| 168 * | 160 * |
| 169 * If [mustCopy] is [:true:], the entire object is copied and the original input | 161 * If [mustCopy] is [:true:], the entire object is copied and the original input |
| 170 * is not mutated. This should be the case where Dart and JavaScript code can | 162 * is not mutated. This should be the case where Dart and JavaScript code can |
| 171 * access the value, for example, via multiple event listeners for | 163 * access the value, for example, via multiple event listeners for |
| 172 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt | 164 * MessageEvents. Mutating the object to make it more 'Dart-like' would corrupt |
| 173 * the value as seen from the JavaScript listeners. | 165 * the value as seen from the JavaScript listeners. |
| 174 */ | 166 */ |
| 175 abstract class _AcceptStructuredClone { | 167 abstract class _AcceptStructuredClone { |
| 176 | 168 |
| 177 // TODO(sra): Replace slots with identity hash table. | 169 // Keep track of the clones, keyed by the original object. If we're |
| 178 var values = []; | 170 // not copying, these may be the same. |
| 179 var copies = []; // initially 'null', 'true' during initial DFS, then a copy. | 171 var clones = new HashMap.identity(); |
| 180 bool mustCopy = false; | 172 bool mustCopy = false; |
| 181 | 173 |
| 182 int findSlot(value) { | 174 Object findSlot(value) { |
| 183 int length = values.length; | 175 return clones.putIfAbsent(value, () => null); |
| 184 for (int i = 0; i < length; i++) { | |
| 185 if (identicalInJs(values[i], value)) return i; | |
| 186 } | |
| 187 values.add(value); | |
| 188 copies.add(null); | |
| 189 return length; | |
| 190 } | 176 } |
| 191 | 177 |
| 192 /// Are the two objects identical, but taking into account that two JsObject | 178 /// Are the two objects identical, but taking into account that two JsObject |
| 193 /// wrappers may not be identical, but their underlying Js Object might be. | 179 /// wrappers may not be identical, but their underlying Js Object might be. |
| 194 bool identicalInJs(a, b); | 180 bool identicalInJs(a, b); |
| 195 readSlot(int i) => copies[i]; | 181 writeSlot(original, x) { clones[original] = x; } |
| 196 writeSlot(int i, x) { copies[i] = x; } | |
| 197 | 182 |
| 198 /// Iterate over the JS properties. | 183 /// Iterate over the JS properties. |
| 199 forEachJsField(object, action); | 184 forEachJsField(object, action); |
| 200 | 185 |
| 201 /// Create a new Dart list of the given length. May create a native List or | 186 /// Create a new Dart list of the given length. May create a native List or |
| 202 /// a JsArray, depending if we're in Dartium or dart2js. | 187 /// a JsArray, depending if we're in Dartium or dart2js. |
| 203 newDartList(length); | 188 newDartList(length); |
| 204 | 189 |
| 205 walk(e) { | 190 walk(e) { |
| 206 if (e == null) return e; | 191 if (e == null) return e; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 217 throw new UnimplementedError('structured clone of RegExp'); | 202 throw new UnimplementedError('structured clone of RegExp'); |
| 218 } | 203 } |
| 219 | 204 |
| 220 if (isJavaScriptPromise(e)) { | 205 if (isJavaScriptPromise(e)) { |
| 221 return convertNativePromiseToDartFuture(e); | 206 return convertNativePromiseToDartFuture(e); |
| 222 } | 207 } |
| 223 | 208 |
| 224 if (isJavaScriptSimpleObject(e)) { | 209 if (isJavaScriptSimpleObject(e)) { |
| 225 // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map | 210 // TODO(sra): If mustCopy is false, swizzle the prototype for one of a Map |
| 226 // implementation that uses the properies as storage. | 211 // implementation that uses the properies as storage. |
| 227 var slot = findSlot(e); | 212 var copy = findSlot(e); |
| 228 var copy = readSlot(slot); | |
| 229 if (copy != null) return copy; | 213 if (copy != null) return copy; |
| 230 copy = {}; | 214 copy = {}; |
| 231 | 215 |
| 232 writeSlot(slot, copy); | 216 writeSlot(e, copy); |
| 233 forEachJsField(e, (key, value) => copy[key] = walk(value)); | 217 forEachJsField(e, (key, value) => copy[key] = walk(value)); |
| 234 return copy; | 218 return copy; |
| 235 } | 219 } |
| 236 | 220 |
| 237 if (isJavaScriptArray(e)) { | 221 if (isJavaScriptArray(e)) { |
| 238 var slot = findSlot(e); | 222 var copy = findSlot(e); |
| 239 var copy = readSlot(slot); | |
| 240 if (copy != null) return copy; | 223 if (copy != null) return copy; |
| 241 | 224 |
| 242 int length = e.length; | 225 int length = e.length; |
| 243 // Since a JavaScript Array is an instance of Dart List, we can modify it | 226 // Since a JavaScript Array is an instance of Dart List, we can modify it |
| 244 // in-place unless we must copy. | 227 // in-place unless we must copy. |
| 245 copy = mustCopy ? newDartList(length) : e; | 228 copy = mustCopy ? newDartList(length) : e; |
| 246 writeSlot(slot, copy); | 229 writeSlot(e, copy); |
| 247 | 230 |
| 248 for (int i = 0; i < length; i++) { | 231 for (int i = 0; i < length; i++) { |
| 249 copy[i] = walk(e[i]); | 232 copy[i] = walk(e[i]); |
| 250 } | 233 } |
| 251 return copy; | 234 return copy; |
| 252 } | 235 } |
| 253 | 236 |
| 254 // Assume anything else is already a valid Dart object, either by having | 237 // Assume anything else is already a valid Dart object, either by having |
| 255 // already been processed, or e.g. a clonable native class. | 238 // already been processed, or e.g. a clonable native class. |
| 256 return e; | 239 return e; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 355 const String _serializedScriptValue = | 338 const String _serializedScriptValue = |
| 356 'num|String|bool|' | 339 'num|String|bool|' |
| 357 'JSExtendableArray|=Object|' | 340 'JSExtendableArray|=Object|' |
| 358 'Blob|File|NativeByteBuffer|NativeTypedData' | 341 'Blob|File|NativeByteBuffer|NativeTypedData' |
| 359 // TODO(sra): Add Date, RegExp. | 342 // TODO(sra): Add Date, RegExp. |
| 360 ; | 343 ; |
| 361 const annotation_Creates_SerializedScriptValue = | 344 const annotation_Creates_SerializedScriptValue = |
| 362 const Creates(_serializedScriptValue); | 345 const Creates(_serializedScriptValue); |
| 363 const annotation_Returns_SerializedScriptValue = | 346 const annotation_Returns_SerializedScriptValue = |
| 364 const Returns(_serializedScriptValue); | 347 const Returns(_serializedScriptValue); |
| OLD | NEW |