| Index: sdk/lib/isolate/mangler.dart
 | 
| diff --git a/sdk/lib/isolate/mangler.dart b/sdk/lib/isolate/mangler.dart
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..a0e16721a4d9d0cd220681319342f05cd7555382
 | 
| --- /dev/null
 | 
| +++ b/sdk/lib/isolate/mangler.dart
 | 
| @@ -0,0 +1,270 @@
 | 
| +// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
 | 
| +// for details. All rights reserved. Use of this source code is governed by a
 | 
| +// BSD-style license that can be found in the LICENSE file.
 | 
| +
 | 
| +part of dart.isolate;
 | 
| +
 | 
| +class _IsolateEncoder {
 | 
| +  final manglingToken;
 | 
| +  // TODO(floitsch): switch to identity set.
 | 
| +  final Map _encoded = new Map();
 | 
| +  final Map _visiting = new Map();
 | 
| +  final Function _mangle;
 | 
| +  static const int _REFERENCE = 0;
 | 
| +  static const int _DECLARATION = 1;
 | 
| +  static const int _ESCAPED = 2;
 | 
| +  static const int _MANGLED = 3;
 | 
| +
 | 
| +  _IsolateEncoder(this.manglingToken, mangle(data))
 | 
| +      : this._mangle = mangle;
 | 
| +
 | 
| +  encode(var data) {
 | 
| +    if (data is num || data is String || data is bool || data == null) {
 | 
| +      return data;
 | 
| +    }
 | 
| +
 | 
| +    if (_encoded.containsKey(data)) return _encoded[data];
 | 
| +    if (_visiting.containsKey(data)) {
 | 
| +      // Self reference.
 | 
| +      var selfReference = _visiting[data];
 | 
| +      if (selfReference == data) {
 | 
| +        // Nobody used the self-reference yet.
 | 
| +        selfReference = _createReference();
 | 
| +        _visiting[data] = selfReference;
 | 
| +      }
 | 
| +      return selfReference;
 | 
| +    }
 | 
| +    _visiting[data] = data;
 | 
| +
 | 
| +    var result;
 | 
| +
 | 
| +    if (data is List) {
 | 
| +      bool hasBeenDuplicated = false;
 | 
| +      result = data;
 | 
| +      for (int i = 0; i < data.length; i++) {
 | 
| +        var mangled = encode(data[i]);
 | 
| +        if (mangled != data[i] && !hasBeenDuplicated) {
 | 
| +          result = new List.fixedLength(data.length);
 | 
| +          for (int j = 0; j < i; j++) {
 | 
| +            result[j] = data[j];
 | 
| +          }
 | 
| +          hasBeenDuplicated = true;
 | 
| +        }
 | 
| +        if (hasBeenDuplicated) {
 | 
| +          result[i] = mangled;
 | 
| +        }
 | 
| +      }
 | 
| +      result = _escapeIfNecessary(result);
 | 
| +    } else if (data is Set) {
 | 
| +      // TODO(floitsch): should we accept sets?
 | 
| +      bool needsCopy = false;
 | 
| +      for (var entry in data) {
 | 
| +        var encoded = encode(entry);
 | 
| +        if (encoded != entry) {
 | 
| +          needsCopy = true;
 | 
| +          break;
 | 
| +        }
 | 
| +      }
 | 
| +      result = data;
 | 
| +      if (needsCopy) {
 | 
| +        result = new Set();
 | 
| +        data.forEach((entry) {
 | 
| +          result.add(encode(entry));
 | 
| +        });
 | 
| +      }
 | 
| +    } else if (data is Map) {
 | 
| +      bool needsCopy = false;
 | 
| +      data.forEach((key, value) {
 | 
| +        var encodedKey = encode(key);
 | 
| +        var encodedValue = encode(value);
 | 
| +        if (encodedKey != key) needsCopy = true;
 | 
| +        if (encodedValue != value) needsCopy = true;
 | 
| +      });
 | 
| +      result = data;
 | 
| +      if (needsCopy) {
 | 
| +        result = new Map();
 | 
| +        data.forEach((key, value) {
 | 
| +          result[encode(key)] = encode(value);
 | 
| +        });
 | 
| +      }
 | 
| +    } else {
 | 
| +      // We don't handle self-references for user data.
 | 
| +      // TODO(floitsch): we could keep the reference and throw when we see it
 | 
| +      // again. However now the user has at least the possibility to do
 | 
| +      // cyclic data-structures.
 | 
| +      _visiting.remove(data);
 | 
| +      result = _mangle(data);
 | 
| +      if (result != data) {
 | 
| +        result = _wrapMangled(encode(result));
 | 
| +      }
 | 
| +    }
 | 
| +
 | 
| +    var selfReference = _visiting[data];
 | 
| +    if (selfReference != null && selfReference != data) {
 | 
| +      // A self-reference has been used.
 | 
| +      result = _declareReference(selfReference, result);
 | 
| +    }
 | 
| +    _encoded[data] = result;
 | 
| +
 | 
| +    _visiting.remove(data);
 | 
| +    return result;
 | 
| +  }
 | 
| +
 | 
| +  _createReference() => [manglingToken, _REFERENCE];
 | 
| +  _declareReference(reference, data) {
 | 
| +    return [manglingToken, _DECLARATION, reference, data];
 | 
| +  }
 | 
| +
 | 
| +  _wrapMangled(data) => [manglingToken, _MANGLED, data];
 | 
| +  _escapeIfNecessary(List list) {
 | 
| +    if (!list.isEmpty && list[0] == manglingToken) {
 | 
| +      return [manglingToken, _ESCAPED, list];
 | 
| +    } else {
 | 
| +      return list;
 | 
| +    }
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +class _IsolateDecoder {
 | 
| +  final manglingToken;
 | 
| +  final Map _decoded = new Map();
 | 
| +  final Function _unmangle;
 | 
| +  static const int _REFERENCE = _IsolateEncoder._REFERENCE;
 | 
| +  static const int _DECLARATION = _IsolateEncoder._DECLARATION;
 | 
| +  static const int _ESCAPED = _IsolateEncoder._ESCAPED;
 | 
| +  static const int _MANGLED = _IsolateEncoder._MANGLED;
 | 
| +
 | 
| +  _IsolateDecoder(this.manglingToken, unmangle(data))
 | 
| +      : this._unmangle = unmangle;
 | 
| +
 | 
| +  decode(var data) {
 | 
| +    if (data is num || data is String || data is bool || data == null) {
 | 
| +      return data;
 | 
| +    }
 | 
| +
 | 
| +    if (_decoded.containsKey(data)) return _decoded[data];
 | 
| +
 | 
| +    if (_isDeclaration(data)) {
 | 
| +      var reference = _extractReference(data);
 | 
| +      var declared = _extractDeclared(data);
 | 
| +      return _decodeObject(declared, reference);
 | 
| +    } else {
 | 
| +      return _decodeObject(data, null);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  _decodeObject(data, reference) {
 | 
| +    if (_decoded.containsKey(data)) {
 | 
| +      assert(reference == null);
 | 
| +      return _decoded[data];
 | 
| +    }
 | 
| +
 | 
| +    // If the data was a reference then we would have found it in the _decoded
 | 
| +    // map.
 | 
| +    assert(!_isReference(data));
 | 
| +
 | 
| +    var result;
 | 
| +    if (_isMangled(data)) {
 | 
| +      assert(reference == null);
 | 
| +      List mangled = _extractMangled(data);
 | 
| +      var decoded = decode(mangled);
 | 
| +      result = _unmangle(decoded);
 | 
| +    } else if (data is List) {
 | 
| +      if (_isEscaped(data)) data = _extractEscaped(data);
 | 
| +      assert(!_isMarked(data));
 | 
| +      result = data;
 | 
| +      bool hasBeenDuplicated = false;
 | 
| +      List duplicate() {
 | 
| +        assert(!hasBeenDuplicated);
 | 
| +        result = new List();
 | 
| +        result.length = data.length;
 | 
| +        if (reference != null) _decoded[reference] = result;
 | 
| +        hasBeenDuplicated = true;
 | 
| +      }
 | 
| +
 | 
| +      if (reference != null) duplicate();
 | 
| +      for (int i = 0; i < data.length; i++) {
 | 
| +        var decoded = decode(data[i]);
 | 
| +        if (decoded != data[i] && !hasBeenDuplicated) {
 | 
| +          duplicate();
 | 
| +          for (int j = 0; j < i; j++) {
 | 
| +            result[j] = data[j];
 | 
| +          }
 | 
| +        }
 | 
| +        if (hasBeenDuplicated) {
 | 
| +          result[i] = decoded;
 | 
| +        }
 | 
| +      }
 | 
| +    } else if (data is Set) {
 | 
| +      bool needsCopy = reference != null;
 | 
| +      if (!needsCopy) {
 | 
| +        for (var entry in data) {
 | 
| +          var decoded = decode(entry);
 | 
| +          if (decoded != entry) {
 | 
| +            needsCopy = true;
 | 
| +            break;
 | 
| +          }
 | 
| +        }
 | 
| +      }
 | 
| +      result = data;
 | 
| +      if (needsCopy) {
 | 
| +        result = new Set();
 | 
| +        if (reference != null) _decoded[reference] = result;
 | 
| +        for (var entry in data) {
 | 
| +          result.add(decode(entry));
 | 
| +        }
 | 
| +      }
 | 
| +    } else if (data is Map) {
 | 
| +      bool needsCopy = reference != null;
 | 
| +      if (!needsCopy) {
 | 
| +        data.forEach((key, value) {
 | 
| +          var decodedKey = decode(key);
 | 
| +          var decodedValue = decode(value);
 | 
| +          if (decodedKey != key) needsCopy = true;
 | 
| +          if (decodedValue != value) needsCopy = true;
 | 
| +        });
 | 
| +      }
 | 
| +      result = data;
 | 
| +      if (needsCopy) {
 | 
| +        result = new Map();
 | 
| +        if (reference != null) _decoded[reference] = result;
 | 
| +        data.forEach((key, value) {
 | 
| +          result[decode(key)] = decode(value);
 | 
| +        });
 | 
| +      }
 | 
| +    } else {
 | 
| +      result = data;
 | 
| +    }
 | 
| +    _decoded[data] = result;
 | 
| +    return result;
 | 
| +  }
 | 
| +
 | 
| +  _isMarked(data) {
 | 
| +    if (data is List && !data.isEmpty && data[0] == manglingToken) {
 | 
| +      assert(data.length > 1);
 | 
| +      return true;
 | 
| +    }
 | 
| +    return false;
 | 
| +  }
 | 
| +  _isReference(data) => _isMarked(data) && data[1] == _REFERENCE;
 | 
| +  _isDeclaration(data) => _isMarked(data) && data[1] == _DECLARATION;
 | 
| +  _isMangled(data) => _isMarked(data) && data[1] == _MANGLED;
 | 
| +  _isEscaped(data) => _isMarked(data) && data[1] == _ESCAPED;
 | 
| +
 | 
| +  _extractReference(declaration) {
 | 
| +    assert(_isDeclaration(declaration));
 | 
| +    return declaration[2];
 | 
| +  }
 | 
| +  _extractDeclared(declaration) {
 | 
| +    assert(_isDeclaration(declaration));
 | 
| +    return declaration[3];
 | 
| +  }
 | 
| +  _extractMangled(wrappedMangled) {
 | 
| +    assert(_isMangled(wrappedMangled));
 | 
| +    return wrappedMangled[2];
 | 
| +  }
 | 
| +  _extractEscaped(data) {
 | 
| +    assert(_isEscaped(data));
 | 
| +    return data[2];
 | 
| +  }
 | 
| +}
 | 
| 
 |