Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 class _IsolateEncoder { | |
| 6 final manglingToken; | |
| 7 final Map _encoded = new Map(); | |
| 8 final Map _visiting = new Map(); | |
| 9 final Function _mangle; | |
| 10 static const int _REFERENCE = 0; | |
| 11 static const int _DECLARATION = 1; | |
| 12 static const int _ESCAPED = 2; | |
| 13 static const int _MANGLED = 3; | |
| 14 | |
| 15 _IsolateEncoder(this.manglingToken, mangle(data)) | |
| 16 : this._mangle = mangle; | |
| 17 | |
| 18 encode(var data) { | |
| 19 if (data is num || data is String || data is bool || data == null) { | |
| 20 return data; | |
| 21 } | |
| 22 | |
| 23 if (_encoded.containsKey(data)) return _encoded[data]; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
This uses equality, not identiity. We should use a
floitsch
2012/11/22 20:06:12
Added TODO.
| |
| 24 if (_visiting.containsKey(data)) { | |
| 25 // Self reference. | |
| 26 var selfReference = _visiting[data]; | |
| 27 if (selfReference == data) { | |
| 28 // Nobody used the self-reference yet. | |
| 29 selfReference = _createReference(); | |
| 30 _visiting[data] = selfReference; | |
| 31 } | |
| 32 return selfReference; | |
| 33 } | |
| 34 | |
| 35 var result; | |
| 36 | |
| 37 if (data is List) { | |
| 38 bool hasBeenDuplicated = false; | |
| 39 result = data; | |
| 40 for (int i = 0; i < data.length; i++) { | |
| 41 var mangled = encode(data[i]); | |
| 42 if (mangled != data[i] && !hasBeenDuplicated) { | |
| 43 result = new List(data.length); | |
| 44 for (int j = 0; j < i; j++) { | |
| 45 result[j] = data[j]; | |
| 46 } | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
hasBeenDuplicated = true; ?
floitsch
2012/11/22 20:06:12
Done.
| |
| 47 } | |
| 48 if (hasBeenDuplicated) { | |
| 49 result[i] = mangled; | |
| 50 } | |
| 51 } | |
| 52 result = _escapeIfNecessary(result); | |
| 53 } else if (data is Set) { | |
| 54 bool needsCopy = false; | |
| 55 data.forEach((entry) { | |
| 56 var encoded = encode(entry); | |
| 57 if (encoded != entry) needsCopy = true; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
and break. No need to test more after the first mo
floitsch
2012/11/22 20:06:12
Duplicate encoding is not a problem since they are
| |
| 58 }); | |
| 59 result = data; | |
| 60 if (needsCopy) { | |
| 61 result = new Set(); | |
| 62 data.forEach((entry) { | |
| 63 result.add(encode(entry)); | |
| 64 }); | |
| 65 } | |
| 66 } else if (data is Map) { | |
| 67 bool needsCopy = false; | |
| 68 data.forEach((key, value) { | |
| 69 var encodedKey = encode(key); | |
| 70 var encodedValue = encode(value); | |
| 71 if (encodedKey != key) needsCopy = true; | |
| 72 if (encodedValue != value) needsCopy = true; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
And break after the first encoding is found.
floitsch
2012/11/22 20:06:12
cannot. This is a map.forEach.
Lasse Reichstein Nielsen
2012/11/23 12:12:38
True. You would need to iterate the keys instead.
| |
| 73 }); | |
| 74 result = data; | |
| 75 if (needsCopy) { | |
| 76 result = new Map(); | |
| 77 data.forEach((key, value) { | |
| 78 result[encode(key)] = encode(value); | |
| 79 }); | |
| 80 } | |
| 81 } else { | |
| 82 // We don't handle self-references for user data. | |
| 83 _visiting.remove(data); | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
Consider keeping it and throwing if you see the sa
floitsch
2012/11/22 20:06:12
Added TODO.
| |
| 84 result = _mangle(data); | |
| 85 if (result != data) { | |
| 86 result = _wrapMangled(encode(result)); | |
| 87 } | |
| 88 } | |
| 89 | |
| 90 var selfReference = _visiting[data]; | |
| 91 if (selfReference != null && selfReference != data) { | |
| 92 // A self-reference has been used. | |
| 93 result = encode(_declareReference(selfReference, data)); | |
| 94 } | |
| 95 _encoded[data] = result; | |
| 96 | |
| 97 _visiting.remove(data); | |
| 98 return result; | |
| 99 } | |
| 100 | |
| 101 _createReference() => [manglingToken, _REFERENCE]; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
What is it a reference to? I.e., how can you tell
floitsch
2012/11/22 20:06:12
Done.
| |
| 102 _declareReference(reference, data) { | |
| 103 return [manglingToken, _DECLARATION, reference, data]; | |
| 104 } | |
| 105 | |
| 106 _wrapMangled(data) => [manglingToken, _MANGLED, data]; | |
| 107 _escapeIfNecessary(List list) { | |
| 108 if (!list.isEmpty && list[0] == manglingToken) { | |
| 109 return [manglingToken, _ESCAPED, list]; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
Then the list contents are not encoded. You should
floitsch
2012/11/22 20:06:12
_escapeIfNecessary is only called on a encoded lis
Lasse Reichstein Nielsen
2012/11/23 12:12:38
Ah, true.
| |
| 110 } else { | |
| 111 return list; | |
| 112 } | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 class _IsolateDecoder { | |
| 117 final manglingToken; | |
| 118 final Map _decoded = new Map(); | |
| 119 final Function _unmangle; | |
| 120 static const int _REFERENCE = IsolateEncoder._REFERENCE; | |
| 121 static const int _DECLARATION = IsolateEncoder._DECLARATION; | |
| 122 static const int _ESCAPED = IsolateEncoder._ESCAPED; | |
| 123 static const int _MANGLED = IsolateEncoder._MANGLED; | |
| 124 | |
| 125 _IsolateDecoder(this.manglingToken, unmangle(data)) | |
| 126 : this._unmangle = unmangle; | |
| 127 | |
| 128 decode(var data) { | |
| 129 if (data is num || data is String || data is bool || data == null) { | |
| 130 return data; | |
| 131 } | |
| 132 | |
| 133 if (_decoded.containsKey(data)) return _decoded[data]; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
if 'data' comes from a JSON.parse, it's not equal
floitsch
2012/11/22 20:06:12
data comes from the isolate-communication. These g
| |
| 134 | |
| 135 if (_isDeclaration(data)) { | |
| 136 var reference = _extractReference(data); | |
| 137 var declared = _extractDeclared(data); | |
| 138 return _decodeObject(declared, reference); | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
So the reference is just a list: [magic#, REFERENC
floitsch
2012/11/22 20:06:12
This works because of the guarantees of the send/r
| |
| 139 } else { | |
| 140 return _decodeObject(data, null); | |
| 141 } | |
| 142 } | |
| 143 | |
| 144 _decodeObject(data, reference) { | |
| 145 if (_decoded.containsKey(data)) { | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
I don't think this lookup will ever succeed if the
floitsch
2012/11/22 20:06:12
which it hasn't.
| |
| 146 assert(reference == null); | |
| 147 return _decoded[data]; | |
| 148 } | |
| 149 | |
| 150 // If the data was a reference then we would have found it in the _decoded | |
| 151 // map. | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
I find that unlikely.
floitsch
2012/11/22 20:06:12
see above.
| |
| 152 assert(!_isReference(data)); | |
| 153 | |
| 154 var result; | |
| 155 if (_isMangled(data)) { | |
| 156 assert(reference == null); | |
| 157 List mangled = _extractMangled(data); | |
| 158 var decoded = decode(mangled); | |
| 159 result = _unmangle(decoded); | |
| 160 } else if (data is List) { | |
| 161 if (_isEscaped(data)) data = _extractEscaped(data); | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
Here you decode the escaped data, even if it wasn'
floitsch
2012/11/22 20:06:12
data cannot be mangled and escaped at the same tim
Lasse Reichstein Nielsen
2012/11/23 12:12:38
Ack, isMangled is not the same as isMarked.
| |
| 162 assert(!_isMarked(data)); | |
| 163 result = data; | |
| 164 bool hasBeenDuplicated = false; | |
| 165 List duplicate() { | |
| 166 assert(!hasBeenDuplicated); | |
| 167 result = new List(); | |
| 168 result.length = data.length; | |
| 169 if (reference != null) _decoded[reference] = result; | |
| 170 hasBeenDuplicated = true; | |
| 171 } | |
| 172 | |
| 173 if (reference != null) duplicate(); | |
| 174 for (int i = 0; i < data.length; i++) { | |
| 175 var decoded = decode(data[i]); | |
| 176 if (decoded != data[i] && !hasBeenDuplicated) { | |
| 177 duplicate(); | |
| 178 for (int j = 0; j < i; j++) { | |
| 179 result[j] = data[j]; | |
| 180 } | |
| 181 } | |
| 182 if (hasBeenDuplicated) { | |
| 183 result[i] = decoded; | |
| 184 } | |
| 185 } | |
| 186 } else if (data is Set) { | |
| 187 bool needsCopy = reference != null; | |
| 188 if (!needsCopy) { | |
| 189 data.forEach((entry) { | |
| 190 var decoded = decode(entry); | |
| 191 if (decoded != entry) needsCopy = true; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
and break.
floitsch
2012/11/22 20:06:12
Done.
| |
| 192 }); | |
| 193 } | |
| 194 result = data; | |
| 195 if (needsCopy) { | |
| 196 result = new Set(); | |
| 197 if (reference != null) _decoded[reference] = result; | |
| 198 data.forEach((entry) { | |
| 199 result.add(decode(entry)); | |
| 200 }); | |
| 201 } | |
| 202 } else if (data is Map) { | |
| 203 bool needsCopy = reference != null; | |
| 204 if (!needsCopy) { | |
| 205 data.forEach((key, value) { | |
| 206 var decodedKey = decode(key); | |
| 207 var decodedValue = decode(value); | |
| 208 if (decodedKey != key) needsCopy = true; | |
| 209 if (decodedValue != value) needsCopy = true; | |
| 210 }); | |
| 211 } | |
| 212 result = data; | |
| 213 if (needsCopy) { | |
| 214 result = new Map(); | |
| 215 if (reference != null) _decoded[reference] = result; | |
| 216 data.forEach((key, value) { | |
| 217 result[decode(key)] = decode(value); | |
| 218 }); | |
| 219 } | |
| 220 } else { | |
| 221 result = data; | |
| 222 } | |
| 223 _decoded[data] = result; | |
| 224 return result; | |
| 225 } | |
| 226 | |
| 227 _isMarked(data) | |
| 228 => data is List && !data.isEmpty && data[0] == manglingToken; | |
|
Lasse Reichstein Nielsen
2012/11/22 10:23:15
'!data.isEmpty' -> 'data.length >= 2' or you can't
floitsch
2012/11/22 20:06:12
added assert.
| |
| 229 _isReference(data) => _isMarked(data) && data[1] == _REFERENCE; | |
| 230 _isDeclaration(data) => _isMarked(data) && data[1] == _DECLARATION; | |
| 231 _isMangled(data) => _isMarked(data) && data[1] == _MANGLED; | |
| 232 _isEscaped(data) => _isMarked(data) && data[1] == _ESCAPED; | |
| 233 | |
| 234 _extractReference(declaration) { | |
| 235 assert(_isDeclaration(declaration)); | |
| 236 return declaration[2]; | |
| 237 } | |
| 238 _extractDeclared(declaration) { | |
| 239 assert(_isDeclaration(declaration)); | |
| 240 return declaration[3]; | |
| 241 } | |
| 242 _extractMangled(wrappedMangled) { | |
| 243 assert(_isMangled(wrappedMangled)); | |
| 244 return wrappedMangled[2]; | |
| 245 } | |
| 246 _extractEscaped(data) { | |
| 247 assert(_isEscaped(data)); | |
| 248 return data[2]; | |
| 249 } | |
| 250 } | |
| OLD | NEW |