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 part of dart.isolate; |
| 6 |
| 7 class _IsolateEncoder { |
| 8 final manglingToken; |
| 9 // TODO(floitsch): switch to identity set. |
| 10 final Map _encoded = new Map(); |
| 11 final Map _visiting = new Map(); |
| 12 final Function _mangle; |
| 13 static const int _REFERENCE = 0; |
| 14 static const int _DECLARATION = 1; |
| 15 static const int _ESCAPED = 2; |
| 16 static const int _MANGLED = 3; |
| 17 |
| 18 _IsolateEncoder(this.manglingToken, mangle(data)) |
| 19 : this._mangle = mangle; |
| 20 |
| 21 encode(var data) { |
| 22 if (data is num || data is String || data is bool || data == null) { |
| 23 return data; |
| 24 } |
| 25 |
| 26 if (_encoded.containsKey(data)) return _encoded[data]; |
| 27 if (_visiting.containsKey(data)) { |
| 28 // Self reference. |
| 29 var selfReference = _visiting[data]; |
| 30 if (selfReference == data) { |
| 31 // Nobody used the self-reference yet. |
| 32 selfReference = _createReference(); |
| 33 _visiting[data] = selfReference; |
| 34 } |
| 35 return selfReference; |
| 36 } |
| 37 _visiting[data] = data; |
| 38 |
| 39 var result; |
| 40 |
| 41 if (data is List) { |
| 42 bool hasBeenDuplicated = false; |
| 43 result = data; |
| 44 for (int i = 0; i < data.length; i++) { |
| 45 var mangled = encode(data[i]); |
| 46 if (mangled != data[i] && !hasBeenDuplicated) { |
| 47 result = new List.fixedLength(data.length); |
| 48 for (int j = 0; j < i; j++) { |
| 49 result[j] = data[j]; |
| 50 } |
| 51 hasBeenDuplicated = true; |
| 52 } |
| 53 if (hasBeenDuplicated) { |
| 54 result[i] = mangled; |
| 55 } |
| 56 } |
| 57 result = _escapeIfNecessary(result); |
| 58 } else if (data is Set) { |
| 59 // TODO(floitsch): should we accept sets? |
| 60 bool needsCopy = false; |
| 61 for (var entry in data) { |
| 62 var encoded = encode(entry); |
| 63 if (encoded != entry) { |
| 64 needsCopy = true; |
| 65 break; |
| 66 } |
| 67 } |
| 68 result = data; |
| 69 if (needsCopy) { |
| 70 result = new Set(); |
| 71 data.forEach((entry) { |
| 72 result.add(encode(entry)); |
| 73 }); |
| 74 } |
| 75 } else if (data is Map) { |
| 76 bool needsCopy = false; |
| 77 data.forEach((key, value) { |
| 78 var encodedKey = encode(key); |
| 79 var encodedValue = encode(value); |
| 80 if (encodedKey != key) needsCopy = true; |
| 81 if (encodedValue != value) needsCopy = true; |
| 82 }); |
| 83 result = data; |
| 84 if (needsCopy) { |
| 85 result = new Map(); |
| 86 data.forEach((key, value) { |
| 87 result[encode(key)] = encode(value); |
| 88 }); |
| 89 } |
| 90 } else { |
| 91 // We don't handle self-references for user data. |
| 92 // TODO(floitsch): we could keep the reference and throw when we see it |
| 93 // again. However now the user has at least the possibility to do |
| 94 // cyclic data-structures. |
| 95 _visiting.remove(data); |
| 96 result = _mangle(data); |
| 97 if (result != data) { |
| 98 result = _wrapMangled(encode(result)); |
| 99 } |
| 100 } |
| 101 |
| 102 var selfReference = _visiting[data]; |
| 103 if (selfReference != null && selfReference != data) { |
| 104 // A self-reference has been used. |
| 105 result = _declareReference(selfReference, result); |
| 106 } |
| 107 _encoded[data] = result; |
| 108 |
| 109 _visiting.remove(data); |
| 110 return result; |
| 111 } |
| 112 |
| 113 _createReference() => [manglingToken, _REFERENCE]; |
| 114 _declareReference(reference, data) { |
| 115 return [manglingToken, _DECLARATION, reference, data]; |
| 116 } |
| 117 |
| 118 _wrapMangled(data) => [manglingToken, _MANGLED, data]; |
| 119 _escapeIfNecessary(List list) { |
| 120 if (!list.isEmpty && list[0] == manglingToken) { |
| 121 return [manglingToken, _ESCAPED, list]; |
| 122 } else { |
| 123 return list; |
| 124 } |
| 125 } |
| 126 } |
| 127 |
| 128 class _IsolateDecoder { |
| 129 final manglingToken; |
| 130 final Map _decoded = new Map(); |
| 131 final Function _unmangle; |
| 132 static const int _REFERENCE = _IsolateEncoder._REFERENCE; |
| 133 static const int _DECLARATION = _IsolateEncoder._DECLARATION; |
| 134 static const int _ESCAPED = _IsolateEncoder._ESCAPED; |
| 135 static const int _MANGLED = _IsolateEncoder._MANGLED; |
| 136 |
| 137 _IsolateDecoder(this.manglingToken, unmangle(data)) |
| 138 : this._unmangle = unmangle; |
| 139 |
| 140 decode(var data) { |
| 141 if (data is num || data is String || data is bool || data == null) { |
| 142 return data; |
| 143 } |
| 144 |
| 145 if (_decoded.containsKey(data)) return _decoded[data]; |
| 146 |
| 147 if (_isDeclaration(data)) { |
| 148 var reference = _extractReference(data); |
| 149 var declared = _extractDeclared(data); |
| 150 return _decodeObject(declared, reference); |
| 151 } else { |
| 152 return _decodeObject(data, null); |
| 153 } |
| 154 } |
| 155 |
| 156 _decodeObject(data, reference) { |
| 157 if (_decoded.containsKey(data)) { |
| 158 assert(reference == null); |
| 159 return _decoded[data]; |
| 160 } |
| 161 |
| 162 // If the data was a reference then we would have found it in the _decoded |
| 163 // map. |
| 164 assert(!_isReference(data)); |
| 165 |
| 166 var result; |
| 167 if (_isMangled(data)) { |
| 168 assert(reference == null); |
| 169 List mangled = _extractMangled(data); |
| 170 var decoded = decode(mangled); |
| 171 result = _unmangle(decoded); |
| 172 } else if (data is List) { |
| 173 if (_isEscaped(data)) data = _extractEscaped(data); |
| 174 assert(!_isMarked(data)); |
| 175 result = data; |
| 176 bool hasBeenDuplicated = false; |
| 177 List duplicate() { |
| 178 assert(!hasBeenDuplicated); |
| 179 result = new List(); |
| 180 result.length = data.length; |
| 181 if (reference != null) _decoded[reference] = result; |
| 182 hasBeenDuplicated = true; |
| 183 } |
| 184 |
| 185 if (reference != null) duplicate(); |
| 186 for (int i = 0; i < data.length; i++) { |
| 187 var decoded = decode(data[i]); |
| 188 if (decoded != data[i] && !hasBeenDuplicated) { |
| 189 duplicate(); |
| 190 for (int j = 0; j < i; j++) { |
| 191 result[j] = data[j]; |
| 192 } |
| 193 } |
| 194 if (hasBeenDuplicated) { |
| 195 result[i] = decoded; |
| 196 } |
| 197 } |
| 198 } else if (data is Set) { |
| 199 bool needsCopy = reference != null; |
| 200 if (!needsCopy) { |
| 201 for (var entry in data) { |
| 202 var decoded = decode(entry); |
| 203 if (decoded != entry) { |
| 204 needsCopy = true; |
| 205 break; |
| 206 } |
| 207 } |
| 208 } |
| 209 result = data; |
| 210 if (needsCopy) { |
| 211 result = new Set(); |
| 212 if (reference != null) _decoded[reference] = result; |
| 213 for (var entry in data) { |
| 214 result.add(decode(entry)); |
| 215 } |
| 216 } |
| 217 } else if (data is Map) { |
| 218 bool needsCopy = reference != null; |
| 219 if (!needsCopy) { |
| 220 data.forEach((key, value) { |
| 221 var decodedKey = decode(key); |
| 222 var decodedValue = decode(value); |
| 223 if (decodedKey != key) needsCopy = true; |
| 224 if (decodedValue != value) needsCopy = true; |
| 225 }); |
| 226 } |
| 227 result = data; |
| 228 if (needsCopy) { |
| 229 result = new Map(); |
| 230 if (reference != null) _decoded[reference] = result; |
| 231 data.forEach((key, value) { |
| 232 result[decode(key)] = decode(value); |
| 233 }); |
| 234 } |
| 235 } else { |
| 236 result = data; |
| 237 } |
| 238 _decoded[data] = result; |
| 239 return result; |
| 240 } |
| 241 |
| 242 _isMarked(data) { |
| 243 if (data is List && !data.isEmpty && data[0] == manglingToken) { |
| 244 assert(data.length > 1); |
| 245 return true; |
| 246 } |
| 247 return false; |
| 248 } |
| 249 _isReference(data) => _isMarked(data) && data[1] == _REFERENCE; |
| 250 _isDeclaration(data) => _isMarked(data) && data[1] == _DECLARATION; |
| 251 _isMangled(data) => _isMarked(data) && data[1] == _MANGLED; |
| 252 _isEscaped(data) => _isMarked(data) && data[1] == _ESCAPED; |
| 253 |
| 254 _extractReference(declaration) { |
| 255 assert(_isDeclaration(declaration)); |
| 256 return declaration[2]; |
| 257 } |
| 258 _extractDeclared(declaration) { |
| 259 assert(_isDeclaration(declaration)); |
| 260 return declaration[3]; |
| 261 } |
| 262 _extractMangled(wrappedMangled) { |
| 263 assert(_isMangled(wrappedMangled)); |
| 264 return wrappedMangled[2]; |
| 265 } |
| 266 _extractEscaped(data) { |
| 267 assert(_isEscaped(data)); |
| 268 return data[2]; |
| 269 } |
| 270 } |
OLD | NEW |