| Index: vm/dart_api_message.cc
 | 
| ===================================================================
 | 
| --- vm/dart_api_message.cc	(revision 8515)
 | 
| +++ vm/dart_api_message.cc	(working copy)
 | 
| @@ -166,6 +166,17 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +ApiMessageReader::BackRefNode* ApiMessageReader::AllocateBackRefNode(
 | 
| +    Dart_CObject* reference,
 | 
| +    DeserializeState state) {
 | 
| +  BackRefNode* value =
 | 
| +      reinterpret_cast<BackRefNode*>(alloc_(NULL, 0, sizeof(BackRefNode)));
 | 
| +  value->set_reference(reference);
 | 
| +  value->set_state(state);
 | 
| +  return value;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  Dart_CObject* ApiMessageReader::ReadInlinedObject(intptr_t object_id) {
 | 
|    // Read the class header information and lookup the class.
 | 
|    intptr_t class_header = ReadIntptrValue();
 | 
| @@ -180,6 +191,77 @@
 | 
|  
 | 
|    ASSERT((class_header & kSmiTagMask) != 0);
 | 
|    class_id = LookupInternalClass(class_header);
 | 
| +  if (class_id == ObjectStore::kArrayClass ||
 | 
| +      class_id == ObjectStore::kImmutableArrayClass) {
 | 
| +    intptr_t len = ReadSmiValue();
 | 
| +    Dart_CObject* value = GetBackRef(object_id);
 | 
| +    if (value == NULL) {
 | 
| +      value = AllocateDartCObjectArray(len);
 | 
| +      AddBackRef(object_id, value, kIsDeserialized);
 | 
| +    }
 | 
| +    // Skip type arguments.
 | 
| +    // TODO(sjesse): Remove this when message serialization format is
 | 
| +    // updated (currently type_arguments is leaked).
 | 
| +    Dart_CObject* type_arguments = ReadObjectImpl();
 | 
| +    if (type_arguments != &type_arguments_marker &&
 | 
| +        type_arguments->type != Dart_CObject::kNull) {
 | 
| +      return AllocateDartCObjectUnsupported();
 | 
| +    }
 | 
| +    for (int i = 0; i < len; i++) {
 | 
| +      value->value.as_array.values[i] = ReadObjectRef();
 | 
| +    }
 | 
| +    return value;
 | 
| +  }
 | 
| +
 | 
| +  return ReadInternalVMObject(class_id, object_id);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Dart_CObject* ApiMessageReader::ReadObjectRef() {
 | 
| +  int64_t value = Read<int64_t>();
 | 
| +  if ((value & kSmiTagMask) == 0) {
 | 
| +    int64_t untagged_value = value >> kSmiTagShift;
 | 
| +    if (kMinInt32 <= untagged_value && untagged_value <= kMaxInt32) {
 | 
| +      return AllocateDartCObjectInt32(untagged_value);
 | 
| +    } else {
 | 
| +      return AllocateDartCObjectInt64(untagged_value);
 | 
| +    }
 | 
| +  }
 | 
| +  ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
 | 
| +  SerializedHeaderType header_type = SerializedHeaderTag::decode(value);
 | 
| +  intptr_t header_value = SerializedHeaderData::decode(value);
 | 
| +
 | 
| +  if (header_type == kObjectId) {
 | 
| +    return ReadIndexedObject(header_value);
 | 
| +  }
 | 
| +  ASSERT(header_type == kInlined);
 | 
| +  // Read the class header information and lookup the class.
 | 
| +  intptr_t class_header = ReadIntptrValue();
 | 
| +
 | 
| +  // Reading of regular dart instances is not supported.
 | 
| +  if (SerializedHeaderData::decode(class_header) == kInstanceId) {
 | 
| +    return AllocateDartCObjectUnsupported();
 | 
| +  }
 | 
| +  ASSERT((class_header & kSmiTagMask) != 0);
 | 
| +  intptr_t object_id = header_value;
 | 
| +  intptr_t class_id = LookupInternalClass(class_header);
 | 
| +  if (class_id == ObjectStore::kArrayClass ||
 | 
| +      class_id == ObjectStore::kImmutableArrayClass) {
 | 
| +    ASSERT(GetBackRef(object_id) == NULL);
 | 
| +    intptr_t len = ReadSmiValue();
 | 
| +    Dart_CObject* value = AllocateDartCObjectArray(len);
 | 
| +    AddBackRef(object_id, value, kIsNotDeserialized);
 | 
| +    return value;
 | 
| +  }
 | 
| +  intptr_t tags = ReadIntptrValue();
 | 
| +  USE(tags);
 | 
| +
 | 
| +  return ReadInternalVMObject(class_id, object_id);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +Dart_CObject* ApiMessageReader::ReadInternalVMObject(intptr_t class_id,
 | 
| +                                                     intptr_t object_id) {
 | 
|    switch (class_id) {
 | 
|      case Object::kClassClass: {
 | 
|        return AllocateDartCObjectUnsupported();
 | 
| @@ -188,11 +270,11 @@
 | 
|        // TODO(sjesse): Remove this when message serialization format is
 | 
|        // updated (currently length is leaked).
 | 
|        Dart_CObject* value = &type_arguments_marker;
 | 
| -      AddBackwardReference(object_id, value);
 | 
| -      Dart_CObject* length = ReadObject();
 | 
| +      AddBackRef(object_id, value, kIsDeserialized);
 | 
| +      Dart_CObject* length = ReadObjectImpl();
 | 
|        ASSERT(length->type == Dart_CObject::kInt32);
 | 
|        for (int i = 0; i < length->value.as_int32; i++) {
 | 
| -        Dart_CObject* type = ReadObject();
 | 
| +        Dart_CObject* type = ReadObjectImpl();
 | 
|          if (type != &dynamic_type_marker) {
 | 
|            return AllocateDartCObjectUnsupported();
 | 
|          }
 | 
| @@ -202,37 +284,20 @@
 | 
|      case Object::kTypeParameterClass: {
 | 
|        // TODO(sgjesse): Fix this workaround ignoring the type parameter.
 | 
|        Dart_CObject* value = &dynamic_type_marker;
 | 
| -      AddBackwardReference(object_id, value);
 | 
| +      AddBackRef(object_id, value, kIsDeserialized);
 | 
|        intptr_t index = ReadIntptrValue();
 | 
|        USE(index);
 | 
|        intptr_t token_index = ReadIntptrValue();
 | 
|        USE(token_index);
 | 
|        int8_t type_state = Read<int8_t>();
 | 
|        USE(type_state);
 | 
| -      Dart_CObject* parameterized_class = ReadObject();
 | 
| +      Dart_CObject* parameterized_class = ReadObjectImpl();
 | 
|        // The type parameter is finalized, therefore parameterized_class is null.
 | 
|        ASSERT(parameterized_class->type == Dart_CObject::kNull);
 | 
| -      Dart_CObject* name = ReadObject();
 | 
| +      Dart_CObject* name = ReadObjectImpl();
 | 
|        ASSERT(name->type == Dart_CObject::kString);
 | 
|        return value;
 | 
|      }
 | 
| -    case ObjectStore::kArrayClass: {
 | 
| -      intptr_t len = ReadSmiValue();
 | 
| -      Dart_CObject* value = AllocateDartCObjectArray(len);
 | 
| -      AddBackwardReference(object_id, value);
 | 
| -      // Skip type arguments.
 | 
| -      // TODO(sjesse): Remove this when message serialization format is
 | 
| -      // updated (currently type_arguments is leaked).
 | 
| -      Dart_CObject* type_arguments = ReadObject();
 | 
| -      if (type_arguments != &type_arguments_marker &&
 | 
| -          type_arguments->type != Dart_CObject::kNull) {
 | 
| -        return AllocateDartCObjectUnsupported();
 | 
| -      }
 | 
| -      for (int i = 0; i < len; i++) {
 | 
| -        value->value.as_array.values[i] = ReadObject();
 | 
| -      }
 | 
| -      return value;
 | 
| -    }
 | 
|      case ObjectStore::kMintClass: {
 | 
|        int64_t value = Read<int64_t>();
 | 
|        Dart_CObject* object;
 | 
| @@ -241,14 +306,14 @@
 | 
|        } else {
 | 
|          object = AllocateDartCObjectInt64(value);
 | 
|        }
 | 
| -      AddBackwardReference(object_id, object);
 | 
| +      AddBackRef(object_id, object, kIsDeserialized);
 | 
|        return object;
 | 
|      }
 | 
|      case ObjectStore::kBigintClass: {
 | 
|        // Read in the hex string representation of the bigint.
 | 
|        intptr_t len = ReadIntptrValue();
 | 
|        Dart_CObject* object = AllocateDartCObjectBigint(len);
 | 
| -      AddBackwardReference(object_id, object);
 | 
| +      AddBackRef(object_id, object, kIsDeserialized);
 | 
|        char* p = object->value.as_bigint;
 | 
|        for (intptr_t i = 0; i < len; i++) {
 | 
|          p[i] = Read<uint8_t>();
 | 
| @@ -259,7 +324,7 @@
 | 
|      case ObjectStore::kDoubleClass: {
 | 
|        // Read the double value for the object.
 | 
|        Dart_CObject* object = AllocateDartCObjectDouble(Read<double>());
 | 
| -      AddBackwardReference(object_id, object);
 | 
| +      AddBackRef(object_id, object, kIsDeserialized);
 | 
|        return object;
 | 
|      }
 | 
|      case ObjectStore::kOneByteStringClass: {
 | 
| @@ -267,7 +332,7 @@
 | 
|        intptr_t hash = ReadSmiValue();
 | 
|        USE(hash);
 | 
|        Dart_CObject* object = AllocateDartCObjectString(len);
 | 
| -      AddBackwardReference(object_id, object);
 | 
| +      AddBackRef(object_id, object, kIsDeserialized);
 | 
|        char* p = object->value.as_string;
 | 
|        for (intptr_t i = 0; i < len; i++) {
 | 
|          p[i] = Read<uint8_t>();
 | 
| @@ -284,7 +349,7 @@
 | 
|      case ObjectStore::kUint8ArrayClass: {
 | 
|        intptr_t len = ReadSmiValue();
 | 
|        Dart_CObject* object = AllocateDartCObjectUint8Array(len);
 | 
| -      AddBackwardReference(object_id, object);
 | 
| +      AddBackRef(object_id, object, kIsDeserialized);
 | 
|        if (len > 0) {
 | 
|          uint8_t* p = object->value.as_byte_array.values;
 | 
|          for (intptr_t i = 0; i < len; i++) {
 | 
| @@ -320,24 +385,24 @@
 | 
|    }
 | 
|    intptr_t index = object_id - kMaxPredefinedObjectIds;
 | 
|    ASSERT((0 <= index) && (index < backward_references_.length()));
 | 
| -  ASSERT(backward_references_[index] != NULL);
 | 
| -  return backward_references_[index];
 | 
| +  ASSERT(backward_references_[index]->reference() != NULL);
 | 
| +  return backward_references_[index]->reference();
 | 
|  }
 | 
|  
 | 
|  
 | 
| -Dart_CObject* ApiMessageReader::ReadObjectImpl(intptr_t header) {
 | 
| -  SerializedHeaderType header_type = SerializedHeaderTag::decode(header);
 | 
| -  intptr_t header_value = SerializedHeaderData::decode(header);
 | 
| -
 | 
| -  if (header_type == kObjectId) {
 | 
| -    return ReadIndexedObject(header_value);
 | 
| +Dart_CObject* ApiMessageReader::ReadObject() {
 | 
| +  Dart_CObject* value = ReadObjectImpl();
 | 
| +  for (intptr_t i = 0; i < backward_references_.length(); i++) {
 | 
| +    if (!backward_references_[i]->is_deserialized()) {
 | 
| +      ReadObjectImpl();
 | 
| +      backward_references_[i]->set_state(kIsDeserialized);
 | 
| +    }
 | 
|    }
 | 
| -  ASSERT(header_type == kInlined);
 | 
| -  return ReadInlinedObject(header_value);
 | 
| +  return value;
 | 
|  }
 | 
|  
 | 
|  
 | 
| -Dart_CObject* ApiMessageReader::ReadObject() {
 | 
| +Dart_CObject* ApiMessageReader::ReadObjectImpl() {
 | 
|    int64_t value = Read<int64_t>();
 | 
|    if ((value & kSmiTagMask) == 0) {
 | 
|      int64_t untagged_value = value >> kSmiTagShift;
 | 
| @@ -348,15 +413,38 @@
 | 
|      }
 | 
|    }
 | 
|    ASSERT((value <= kIntptrMax) && (value >= kIntptrMin));
 | 
| -  return ReadObjectImpl(value);
 | 
| +  SerializedHeaderType header_type = SerializedHeaderTag::decode(value);
 | 
| +  intptr_t header_value = SerializedHeaderData::decode(value);
 | 
| +
 | 
| +  if (header_type == kObjectId) {
 | 
| +    return ReadIndexedObject(header_value);
 | 
| +  }
 | 
| +  ASSERT(header_type == kInlined);
 | 
| +  return ReadInlinedObject(header_value);
 | 
|  }
 | 
|  
 | 
|  
 | 
| -void ApiMessageReader::AddBackwardReference(intptr_t id, Dart_CObject* obj) {
 | 
| -  ASSERT((id - kMaxPredefinedObjectIds) == backward_references_.length());
 | 
| -  backward_references_.Add(obj);
 | 
| +void ApiMessageReader::AddBackRef(intptr_t id,
 | 
| +                                  Dart_CObject* obj,
 | 
| +                                  DeserializeState state) {
 | 
| +  intptr_t index = (id - kMaxPredefinedObjectIds);
 | 
| +  ASSERT(index == backward_references_.length());
 | 
| +  BackRefNode* node = AllocateBackRefNode(obj, state);
 | 
| +  ASSERT(node != NULL);
 | 
| +  backward_references_.Add(node);
 | 
|  }
 | 
|  
 | 
| +
 | 
| +Dart_CObject* ApiMessageReader::GetBackRef(intptr_t id) {
 | 
| +  ASSERT(id >= kMaxPredefinedObjectIds);
 | 
| +  intptr_t index = (id - kMaxPredefinedObjectIds);
 | 
| +  if (index < backward_references_.length()) {
 | 
| +    return backward_references_[index]->reference();
 | 
| +  }
 | 
| +  return NULL;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void ApiMessageWriter::WriteMessage(intptr_t field_count, intptr_t *data) {
 | 
|    // Write out the serialization header value for this object.
 | 
|    WriteSerializationMarker(kInlined, kMaxPredefinedObjectIds);
 | 
| @@ -423,6 +511,18 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| +void ApiMessageWriter::AddToForwardList(Dart_CObject* object) {
 | 
| +  if (forward_id_ >= forward_list_length_) {
 | 
| +    intptr_t new_size = (forward_list_length_ * sizeof(object)) * 2;
 | 
| +    void* new_list = ::realloc(forward_list_, new_size);
 | 
| +    ASSERT(new_list != NULL);
 | 
| +    forward_list_ = reinterpret_cast<Dart_CObject**>(new_list);
 | 
| +  }
 | 
| +  forward_list_[forward_id_] = object;
 | 
| +  forward_id_ += 1;
 | 
| +}
 | 
| +
 | 
| +
 | 
|  void ApiMessageWriter::WriteSmi(int64_t value) {
 | 
|    ASSERT(Smi::IsValid64(value));
 | 
|    Write<RawObject*>(Smi::New(value));
 | 
| @@ -477,7 +577,72 @@
 | 
|      return;
 | 
|    }
 | 
|  
 | 
| -  switch (object->type) {
 | 
| +  Dart_CObject::Type type = object->type;
 | 
| +  if (type == Dart_CObject::kArray) {
 | 
| +    // Write out the serialization header value for this object.
 | 
| +    WriteInlinedHeader(object);
 | 
| +    // Write out the class and tags information.
 | 
| +    WriteObjectHeader(ObjectStore::kArrayClass, 0);
 | 
| +    WriteSmi(object->value.as_array.length);
 | 
| +    // Write out the type arguments.
 | 
| +    WriteIndexedObject(Object::kNullObject);
 | 
| +    // Write out array elements.
 | 
| +    for (int i = 0; i < object->value.as_array.length; i++) {
 | 
| +      WriteCObjectRef(object->value.as_array.values[i]);
 | 
| +    }
 | 
| +    return;
 | 
| +  }
 | 
| +  return WriteCObjectInlined(object, type);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ApiMessageWriter::WriteCObjectRef(Dart_CObject* object) {
 | 
| +  if (IsCObjectMarked(object)) {
 | 
| +    intptr_t object_id = GetMarkedCObjectMark(object);
 | 
| +    WriteIndexedObject(kMaxPredefinedObjectIds + object_id);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  Dart_CObject::Type type = object->type;
 | 
| +  if (type == Dart_CObject::kArray) {
 | 
| +    // Write out the serialization header value for this object.
 | 
| +    WriteInlinedHeader(object);
 | 
| +    // Write out the class information.
 | 
| +    WriteIndexedObject(ObjectStore::kArrayClass);
 | 
| +    // Write out the length information.
 | 
| +    WriteSmi(object->value.as_array.length);
 | 
| +    // Add object to forward list so that this object is serialized later.
 | 
| +    AddToForwardList(object);
 | 
| +    return;
 | 
| +  }
 | 
| +  return WriteCObjectInlined(object, type);
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ApiMessageWriter::WriteForwardedCObject(Dart_CObject* object) {
 | 
| +  ASSERT(IsCObjectMarked(object));
 | 
| +  Dart_CObject::Type type =
 | 
| +      static_cast<Dart_CObject::Type>(object->type & kDartCObjectTypeMask);
 | 
| +  ASSERT(type == Dart_CObject::kArray);
 | 
| +
 | 
| +  // Write out the serialization header value for this object.
 | 
| +  intptr_t object_id = GetMarkedCObjectMark(object);
 | 
| +  WriteSerializationMarker(kInlined, kMaxPredefinedObjectIds + object_id);
 | 
| +  // Write out the class and tags information.
 | 
| +  WriteObjectHeader(ObjectStore::kArrayClass, 0);
 | 
| +  WriteSmi(object->value.as_array.length);
 | 
| +  // Write out the type arguments.
 | 
| +  WriteIndexedObject(Object::kNullObject);
 | 
| +  // Write out array elements.
 | 
| +  for (int i = 0; i < object->value.as_array.length; i++) {
 | 
| +    WriteCObjectRef(object->value.as_array.values[i]);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void ApiMessageWriter::WriteCObjectInlined(Dart_CObject* object,
 | 
| +                                           Dart_CObject::Type type) {
 | 
| +  switch (type) {
 | 
|      case Dart_CObject::kNull:
 | 
|        WriteIndexedObject(Object::kNullObject);
 | 
|        break;
 | 
| @@ -531,20 +696,6 @@
 | 
|        }
 | 
|        break;
 | 
|      }
 | 
| -    case Dart_CObject::kArray: {
 | 
| -      // Write out the serialization header value for this object.
 | 
| -      WriteInlinedHeader(object);
 | 
| -      // Write out the class and tags information.
 | 
| -      WriteObjectHeader(ObjectStore::kArrayClass, 0);
 | 
| -      WriteSmi(object->value.as_array.length);
 | 
| -      // Write out the type arguments.
 | 
| -      WriteIndexedObject(Object::kNullObject);
 | 
| -      // Write out array elements.
 | 
| -      for (int i = 0; i < object->value.as_array.length; i++) {
 | 
| -        WriteCObject(object->value.as_array.values[i]);
 | 
| -      }
 | 
| -      break;
 | 
| -    }
 | 
|      case Dart_CObject::kUint8Array: {
 | 
|        // Write out the serialization header value for this object.
 | 
|        WriteInlinedHeader(object);
 | 
| @@ -566,6 +717,12 @@
 | 
|  
 | 
|  void ApiMessageWriter::WriteCMessage(Dart_CObject* object) {
 | 
|    WriteCObject(object);
 | 
| +  // Write out all objects that were added to the forward list and have
 | 
| +  // not been serialized yet. These would typically be fields of arrays.
 | 
| +  // NOTE: The forward list might grow as we process the list.
 | 
| +  for (intptr_t i = 0; i < forward_id_; i++) {
 | 
| +    WriteForwardedCObject(forward_list_[i]);
 | 
| +  }
 | 
|    UnmarkAllCObjects(object);
 | 
|    FinalizeBuffer();
 | 
|  }
 | 
| 
 |