Chromium Code Reviews| Index: vm/object.cc |
| =================================================================== |
| --- vm/object.cc (revision 14589) |
| +++ vm/object.cc (working copy) |
| @@ -474,6 +474,46 @@ |
| } |
| +// Make unused space in an object whose type has been transformed safe |
| +// for traversing during GC. |
| +// The unused part of the transformed object is marked as an Array |
| +// object or a regular Object so that it can be traversed during garbage |
| +// collection. |
| +void Object::MakeUnusedSpaceTraversable(const Object& obj, |
| + intptr_t original_size, |
| + intptr_t used_size) { |
| + ASSERT(Isolate::Current()->no_gc_scope_depth() > 0); |
| + ASSERT(!obj.IsNull()); |
| + if (original_size > used_size) { |
|
Anton Muhin
2012/11/07 10:05:46
maybe turn that into an assert?
siva
2012/11/07 21:43:27
I did not want it to be an assert because then the
|
| + intptr_t leftover_size = original_size - used_size; |
| + |
| + uword addr = RawObject::ToAddr(obj.raw()) + used_size; |
| + if (leftover_size >= Array::InstanceSize(0)) { |
| + // As we have enough space to use an array object, update the leftover |
| + // space as an Array object. |
| + RawArray* raw = reinterpret_cast<RawArray*>(RawObject::FromAddr(addr)); |
| + uword tags = 0; |
| + tags = RawObject::SizeTag::update(leftover_size, tags); |
|
Anton Muhin
2012/11/07 10:05:46
may there be any issues with alignment? maybe add
siva
2012/11/07 21:43:27
Objects are always aligned, we have asserts for th
|
| + tags = RawObject::ClassIdTag::update(kArrayCid, tags); |
| + raw->ptr()->tags_ = tags; |
| + intptr_t leftover_len = |
| + ((leftover_size - Array::InstanceSize(0)) / kWordSize); |
| + raw->ptr()->tags_ = tags; |
| + raw->ptr()->length_ = Smi::New(leftover_len); |
| + } else { |
| + // Update the leftover space as a basic object. |
| + ASSERT(leftover_size == Object::InstanceSize()); |
| + RawObject* raw = |
| + reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); |
| + uword tags = 0; |
| + tags = RawObject::SizeTag::update(leftover_size, tags); |
| + tags = RawObject::ClassIdTag::update(kInstanceCid, tags); |
| + raw->ptr()->tags_ = tags; |
| + } |
| + } |
| +} |
| + |
| + |
| RawClass* Object::CreateAndRegisterInterface(const char* cname, |
| const Script& script, |
| const Library& lib) { |
| @@ -10294,6 +10334,87 @@ |
| } |
| +static void AddFinalizer(const Object& referent, |
| + void* peer, |
| + Dart_WeakPersistentHandleFinalizer callback) { |
| + ASSERT(callback != NULL); |
| + ApiState* state = Isolate::Current()->api_state(); |
| + ASSERT(state != NULL); |
| + FinalizablePersistentHandle* weak_ref = |
| + state->weak_persistent_handles().AllocateHandle(); |
| + weak_ref->set_raw(referent); |
| + weak_ref->set_peer(peer); |
| + weak_ref->set_callback(callback); |
| +} |
| + |
| + |
| +RawString* String::MakeExternal(void* array, |
| + intptr_t length, |
| + void* peer, |
| + Dart_PeerFinalizer cback) const { |
| + ASSERT(array != NULL); |
| + intptr_t str_length = this->Length(); |
| + ASSERT(length >= (str_length * this->CharSize())); |
| + intptr_t class_id = raw()->GetClassId(); |
| + intptr_t used_size = 0; |
| + intptr_t original_size = 0; |
| + uword tags = 0; |
| + NoGCScope no_gc; |
| + |
| + if (class_id == kOneByteStringCid) { |
| + used_size = ExternalOneByteString::InstanceSize(); |
| + original_size = OneByteString::InstanceSize(str_length); |
| + ASSERT(original_size >= used_size); |
|
Anton Muhin
2012/11/07 10:05:46
is it always true? something like zero length str
siva
2012/11/07 21:43:27
Yes this is always true as we always align objects
Anton Muhin
2012/11/08 08:05:29
Okay. In v8 zero length string would be just a he
|
| + |
| + // Copy the data into the external array. |
| + memmove(array, OneByteString::CharAddr(*this, 0), str_length); |
|
Anton Muhin
2012/11/07 10:05:46
that might be very unpleasant thing when one attem
siva
2012/11/07 21:43:27
I am not sure I understand your suggestion here. T
Anton Muhin
2012/11/08 08:05:29
Yes, the embedder has to do that, but he hasn't to
|
| + |
| + // Update the class information of the object. |
| + const intptr_t class_id = kExternalOneByteStringCid; |
| + tags = RawObject::SizeTag::update(used_size, tags); |
| + tags = RawObject::ClassIdTag::update(class_id, tags); |
| + raw_ptr()->tags_ = tags; |
| + const String& result = String::Handle(this->raw()); |
| + ExternalStringData<uint8_t>* ext_data = new ExternalStringData<uint8_t>( |
| + reinterpret_cast<const uint8_t*>(array), peer, cback); |
| + result.SetLength(str_length); |
| + result.SetHash(0); |
| + ExternalOneByteString::SetExternalData(result, ext_data); |
| + AddFinalizer(result, ext_data, ExternalOneByteString::Finalize); |
| + } else { |
| + ASSERT(class_id == kTwoByteStringCid); |
| + used_size = ExternalTwoByteString::InstanceSize(); |
| + original_size = TwoByteString::InstanceSize(str_length); |
| + ASSERT(original_size >= used_size); |
| + |
| + // Copy the data into the external array. |
| + memmove(array, |
| + TwoByteString::CharAddr(*this, 0), |
| + (str_length * kTwoByteChar)); |
| + |
| + // Update the class information of the object. |
| + const intptr_t class_id = kExternalTwoByteStringCid; |
| + tags = RawObject::SizeTag::update(used_size, tags); |
| + tags = RawObject::ClassIdTag::update(class_id, tags); |
| + raw_ptr()->tags_ = tags; |
| + const String& result = String::Handle(this->raw()); |
| + ExternalStringData<uint16_t>* ext_data = new ExternalStringData<uint16_t>( |
| + reinterpret_cast<const uint16_t*>(array), peer, cback); |
| + result.SetLength(str_length); |
| + result.SetHash(0); |
| + ExternalTwoByteString::SetExternalData(result, ext_data); |
| + AddFinalizer(result, ext_data, ExternalTwoByteString::Finalize); |
| + } |
| + |
| + // If there is any left over space fill it with either an Array object or |
| + // just a plain object (depending on the amount of left over space) so |
| + // that it can be traversed over successfully during garbage collection. |
| + Object::MakeUnusedSpaceTraversable(*this, original_size, used_size); |
| + |
| + return this->raw(); |
| +} |
| + |
| + |
| RawString* String::Transform(int32_t (*mapping)(int32_t ch), |
| const String& str, |
| Heap::Space space) { |
| @@ -10684,20 +10805,6 @@ |
| } |
| -static void AddFinalizer(const Object& referent, |
| - void* peer, |
| - Dart_WeakPersistentHandleFinalizer callback) { |
| - ASSERT(callback != NULL); |
| - ApiState* state = Isolate::Current()->api_state(); |
| - ASSERT(state != NULL); |
| - FinalizablePersistentHandle* weak_ref = |
| - state->weak_persistent_handles().AllocateHandle(); |
| - weak_ref->set_raw(referent); |
| - weak_ref->set_peer(peer); |
| - weak_ref->set_callback(callback); |
| -} |
| - |
| - |
| RawExternalOneByteString* ExternalOneByteString::New( |
| const uint8_t* data, |
| intptr_t len, |
| @@ -10927,33 +11034,8 @@ |
| // If there is any left over space fill it with either an Array object or |
| // just a plain object (depending on the amount of left over space) so |
| // that it can be traversed over successfully during garbage collection. |
| - if (capacity_size != used_size) { |
| - ASSERT(capacity_len > used_len); |
| - intptr_t leftover_size = capacity_size - used_size; |
| + Object::MakeUnusedSpaceTraversable(array, capacity_size, used_size); |
| - uword addr = RawObject::ToAddr(array.raw()) + used_size; |
| - if (leftover_size >= Array::InstanceSize(0)) { |
| - // As we have enough space to use an array object, update the leftover |
| - // space as an Array object. |
| - RawArray* raw = reinterpret_cast<RawArray*>(RawObject::FromAddr(addr)); |
| - tags = 0; |
| - tags = RawObject::SizeTag::update(leftover_size, tags); |
| - tags = RawObject::ClassIdTag::update(kArrayCid, tags); |
| - raw->ptr()->tags_ = tags; |
| - intptr_t leftover_len = |
| - ((leftover_size - Array::InstanceSize(0)) / kWordSize); |
| - raw->ptr()->tags_ = tags; |
| - raw->ptr()->length_ = Smi::New(leftover_len); |
| - } else { |
| - // Update the leftover space as a basic object. |
| - ASSERT(leftover_size == Object::InstanceSize()); |
| - RawObject* raw = reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); |
| - tags = 0; |
| - tags = RawObject::SizeTag::update(leftover_size, tags); |
| - tags = RawObject::ClassIdTag::update(kInstanceCid, tags); |
| - raw->ptr()->tags_ = tags; |
| - } |
| - } |
| return array.raw(); |
| } |