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

Side by Side Diff: sdk/lib/html/html_common/conversions.dart

Issue 1817343002: Remove O(n^2) loop in serialized script value conversions (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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);
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698