Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/object.h" | 5 #include "vm/object.h" |
| 6 | 6 |
| 7 #include "include/dart_api.h" | 7 #include "include/dart_api.h" |
| 8 #include "platform/assert.h" | 8 #include "platform/assert.h" |
| 9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
| 10 #include "vm/bigint_operations.h" | 10 #include "vm/bigint_operations.h" |
| (...skipping 456 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 467 // pre-allocated in the vm isolate also. | 467 // pre-allocated in the vm isolate also. |
| 468 cls = Dart::vm_isolate()->object_store()->array_class(); | 468 cls = Dart::vm_isolate()->object_store()->array_class(); |
| 469 str = Symbols::ObjectArray(); | 469 str = Symbols::ObjectArray(); |
| 470 cls.set_name(str); | 470 cls.set_name(str); |
| 471 cls = Dart::vm_isolate()->object_store()->one_byte_string_class(); | 471 cls = Dart::vm_isolate()->object_store()->one_byte_string_class(); |
| 472 str = Symbols::OneByteString(); | 472 str = Symbols::OneByteString(); |
| 473 cls.set_name(str); | 473 cls.set_name(str); |
| 474 } | 474 } |
| 475 | 475 |
| 476 | 476 |
| 477 // Make unused space in an object whose type has been transformed safe | |
| 478 // for traversing during GC. | |
| 479 // The unused part of the transformed object is marked as an Array | |
| 480 // object or a regular Object so that it can be traversed during garbage | |
| 481 // collection. | |
| 482 void Object::MakeUnusedSpaceTraversable(const Object& obj, | |
| 483 intptr_t original_size, | |
| 484 intptr_t used_size) { | |
| 485 ASSERT(Isolate::Current()->no_gc_scope_depth() > 0); | |
| 486 ASSERT(!obj.IsNull()); | |
| 487 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
| |
| 488 intptr_t leftover_size = original_size - used_size; | |
| 489 | |
| 490 uword addr = RawObject::ToAddr(obj.raw()) + used_size; | |
| 491 if (leftover_size >= Array::InstanceSize(0)) { | |
| 492 // As we have enough space to use an array object, update the leftover | |
| 493 // space as an Array object. | |
| 494 RawArray* raw = reinterpret_cast<RawArray*>(RawObject::FromAddr(addr)); | |
| 495 uword tags = 0; | |
| 496 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
| |
| 497 tags = RawObject::ClassIdTag::update(kArrayCid, tags); | |
| 498 raw->ptr()->tags_ = tags; | |
| 499 intptr_t leftover_len = | |
| 500 ((leftover_size - Array::InstanceSize(0)) / kWordSize); | |
| 501 raw->ptr()->tags_ = tags; | |
| 502 raw->ptr()->length_ = Smi::New(leftover_len); | |
| 503 } else { | |
| 504 // Update the leftover space as a basic object. | |
| 505 ASSERT(leftover_size == Object::InstanceSize()); | |
| 506 RawObject* raw = | |
| 507 reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); | |
| 508 uword tags = 0; | |
| 509 tags = RawObject::SizeTag::update(leftover_size, tags); | |
| 510 tags = RawObject::ClassIdTag::update(kInstanceCid, tags); | |
| 511 raw->ptr()->tags_ = tags; | |
| 512 } | |
| 513 } | |
| 514 } | |
| 515 | |
| 516 | |
| 477 RawClass* Object::CreateAndRegisterInterface(const char* cname, | 517 RawClass* Object::CreateAndRegisterInterface(const char* cname, |
| 478 const Script& script, | 518 const Script& script, |
| 479 const Library& lib) { | 519 const Library& lib) { |
| 480 const String& name = String::Handle(Symbols::New(cname)); | 520 const String& name = String::Handle(Symbols::New(cname)); |
| 481 const Class& cls = Class::Handle( | 521 const Class& cls = Class::Handle( |
| 482 Class::NewInterface(name, script, Scanner::kDummyTokenIndex)); | 522 Class::NewInterface(name, script, Scanner::kDummyTokenIndex)); |
| 483 lib.AddClass(cls); | 523 lib.AddClass(cls); |
| 484 return cls.raw(); | 524 return cls.raw(); |
| 485 } | 525 } |
| 486 | 526 |
| (...skipping 9800 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10287 if (obj.Length() > 0) { | 10327 if (obj.Length() > 0) { |
| 10288 memmove(utf8_array, OneByteString::CharAddr(obj, 0), obj.Length()); | 10328 memmove(utf8_array, OneByteString::CharAddr(obj, 0), obj.Length()); |
| 10289 } | 10329 } |
| 10290 } else { | 10330 } else { |
| 10291 ASSERT(array_len >= Utf8::Length(*this)); | 10331 ASSERT(array_len >= Utf8::Length(*this)); |
| 10292 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); | 10332 Utf8::Encode(*this, reinterpret_cast<char*>(utf8_array), array_len); |
| 10293 } | 10333 } |
| 10294 } | 10334 } |
| 10295 | 10335 |
| 10296 | 10336 |
| 10337 static void AddFinalizer(const Object& referent, | |
| 10338 void* peer, | |
| 10339 Dart_WeakPersistentHandleFinalizer callback) { | |
| 10340 ASSERT(callback != NULL); | |
| 10341 ApiState* state = Isolate::Current()->api_state(); | |
| 10342 ASSERT(state != NULL); | |
| 10343 FinalizablePersistentHandle* weak_ref = | |
| 10344 state->weak_persistent_handles().AllocateHandle(); | |
| 10345 weak_ref->set_raw(referent); | |
| 10346 weak_ref->set_peer(peer); | |
| 10347 weak_ref->set_callback(callback); | |
| 10348 } | |
| 10349 | |
| 10350 | |
| 10351 RawString* String::MakeExternal(void* array, | |
| 10352 intptr_t length, | |
| 10353 void* peer, | |
| 10354 Dart_PeerFinalizer cback) const { | |
| 10355 ASSERT(array != NULL); | |
| 10356 intptr_t str_length = this->Length(); | |
| 10357 ASSERT(length >= (str_length * this->CharSize())); | |
| 10358 intptr_t class_id = raw()->GetClassId(); | |
| 10359 intptr_t used_size = 0; | |
| 10360 intptr_t original_size = 0; | |
| 10361 uword tags = 0; | |
| 10362 NoGCScope no_gc; | |
| 10363 | |
| 10364 if (class_id == kOneByteStringCid) { | |
| 10365 used_size = ExternalOneByteString::InstanceSize(); | |
| 10366 original_size = OneByteString::InstanceSize(str_length); | |
| 10367 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
| |
| 10368 | |
| 10369 // Copy the data into the external array. | |
| 10370 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
| |
| 10371 | |
| 10372 // Update the class information of the object. | |
| 10373 const intptr_t class_id = kExternalOneByteStringCid; | |
| 10374 tags = RawObject::SizeTag::update(used_size, tags); | |
| 10375 tags = RawObject::ClassIdTag::update(class_id, tags); | |
| 10376 raw_ptr()->tags_ = tags; | |
| 10377 const String& result = String::Handle(this->raw()); | |
| 10378 ExternalStringData<uint8_t>* ext_data = new ExternalStringData<uint8_t>( | |
| 10379 reinterpret_cast<const uint8_t*>(array), peer, cback); | |
| 10380 result.SetLength(str_length); | |
| 10381 result.SetHash(0); | |
| 10382 ExternalOneByteString::SetExternalData(result, ext_data); | |
| 10383 AddFinalizer(result, ext_data, ExternalOneByteString::Finalize); | |
| 10384 } else { | |
| 10385 ASSERT(class_id == kTwoByteStringCid); | |
| 10386 used_size = ExternalTwoByteString::InstanceSize(); | |
| 10387 original_size = TwoByteString::InstanceSize(str_length); | |
| 10388 ASSERT(original_size >= used_size); | |
| 10389 | |
| 10390 // Copy the data into the external array. | |
| 10391 memmove(array, | |
| 10392 TwoByteString::CharAddr(*this, 0), | |
| 10393 (str_length * kTwoByteChar)); | |
| 10394 | |
| 10395 // Update the class information of the object. | |
| 10396 const intptr_t class_id = kExternalTwoByteStringCid; | |
| 10397 tags = RawObject::SizeTag::update(used_size, tags); | |
| 10398 tags = RawObject::ClassIdTag::update(class_id, tags); | |
| 10399 raw_ptr()->tags_ = tags; | |
| 10400 const String& result = String::Handle(this->raw()); | |
| 10401 ExternalStringData<uint16_t>* ext_data = new ExternalStringData<uint16_t>( | |
| 10402 reinterpret_cast<const uint16_t*>(array), peer, cback); | |
| 10403 result.SetLength(str_length); | |
| 10404 result.SetHash(0); | |
| 10405 ExternalTwoByteString::SetExternalData(result, ext_data); | |
| 10406 AddFinalizer(result, ext_data, ExternalTwoByteString::Finalize); | |
| 10407 } | |
| 10408 | |
| 10409 // If there is any left over space fill it with either an Array object or | |
| 10410 // just a plain object (depending on the amount of left over space) so | |
| 10411 // that it can be traversed over successfully during garbage collection. | |
| 10412 Object::MakeUnusedSpaceTraversable(*this, original_size, used_size); | |
| 10413 | |
| 10414 return this->raw(); | |
| 10415 } | |
| 10416 | |
| 10417 | |
| 10297 RawString* String::Transform(int32_t (*mapping)(int32_t ch), | 10418 RawString* String::Transform(int32_t (*mapping)(int32_t ch), |
| 10298 const String& str, | 10419 const String& str, |
| 10299 Heap::Space space) { | 10420 Heap::Space space) { |
| 10300 ASSERT(!str.IsNull()); | 10421 ASSERT(!str.IsNull()); |
| 10301 bool has_mapping = false; | 10422 bool has_mapping = false; |
| 10302 int32_t dst_max = 0; | 10423 int32_t dst_max = 0; |
| 10303 intptr_t len = str.Length(); | 10424 intptr_t len = str.Length(); |
| 10304 // TODO(cshapiro): assume a transform is required, rollback if not. | 10425 // TODO(cshapiro): assume a transform is required, rollback if not. |
| 10305 for (intptr_t i = 0; i < len; ++i) { | 10426 for (intptr_t i = 0; i < len; ++i) { |
| 10306 int32_t src = str.CharAt(i); | 10427 int32_t src = str.CharAt(i); |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10677 const String& result = String::Handle(TwoByteString::New(len, space)); | 10798 const String& result = String::Handle(TwoByteString::New(len, space)); |
| 10678 for (intptr_t i = 0; i < len; ++i) { | 10799 for (intptr_t i = 0; i < len; ++i) { |
| 10679 int32_t ch = mapping(str.CharAt(i)); | 10800 int32_t ch = mapping(str.CharAt(i)); |
| 10680 ASSERT(ch >= 0 && ch <= 0xFFFF); | 10801 ASSERT(ch >= 0 && ch <= 0xFFFF); |
| 10681 *CharAddr(result, i) = ch; | 10802 *CharAddr(result, i) = ch; |
| 10682 } | 10803 } |
| 10683 return TwoByteString::raw(result); | 10804 return TwoByteString::raw(result); |
| 10684 } | 10805 } |
| 10685 | 10806 |
| 10686 | 10807 |
| 10687 static void AddFinalizer(const Object& referent, | |
| 10688 void* peer, | |
| 10689 Dart_WeakPersistentHandleFinalizer callback) { | |
| 10690 ASSERT(callback != NULL); | |
| 10691 ApiState* state = Isolate::Current()->api_state(); | |
| 10692 ASSERT(state != NULL); | |
| 10693 FinalizablePersistentHandle* weak_ref = | |
| 10694 state->weak_persistent_handles().AllocateHandle(); | |
| 10695 weak_ref->set_raw(referent); | |
| 10696 weak_ref->set_peer(peer); | |
| 10697 weak_ref->set_callback(callback); | |
| 10698 } | |
| 10699 | |
| 10700 | |
| 10701 RawExternalOneByteString* ExternalOneByteString::New( | 10808 RawExternalOneByteString* ExternalOneByteString::New( |
| 10702 const uint8_t* data, | 10809 const uint8_t* data, |
| 10703 intptr_t len, | 10810 intptr_t len, |
| 10704 void* peer, | 10811 void* peer, |
| 10705 Dart_PeerFinalizer callback, | 10812 Dart_PeerFinalizer callback, |
| 10706 Heap::Space space) { | 10813 Heap::Space space) { |
| 10707 ASSERT(Isolate::Current()->object_store()-> | 10814 ASSERT(Isolate::Current()->object_store()-> |
| 10708 external_one_byte_string_class() != Class::null()); | 10815 external_one_byte_string_class() != Class::null()); |
| 10709 if (len < 0 || len > kMaxElements) { | 10816 if (len < 0 || len > kMaxElements) { |
| 10710 // This should be caught before we reach here. | 10817 // This should be caught before we reach here. |
| (...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 10920 array.raw_ptr()->tags_ = tags; | 11027 array.raw_ptr()->tags_ = tags; |
| 10921 array.SetLength(used_len); | 11028 array.SetLength(used_len); |
| 10922 | 11029 |
| 10923 // Null the GrowableObjectArray, we are removing it's backing array. | 11030 // Null the GrowableObjectArray, we are removing it's backing array. |
| 10924 growable_array.SetLength(0); | 11031 growable_array.SetLength(0); |
| 10925 growable_array.SetData(new_array); | 11032 growable_array.SetData(new_array); |
| 10926 | 11033 |
| 10927 // If there is any left over space fill it with either an Array object or | 11034 // If there is any left over space fill it with either an Array object or |
| 10928 // just a plain object (depending on the amount of left over space) so | 11035 // just a plain object (depending on the amount of left over space) so |
| 10929 // that it can be traversed over successfully during garbage collection. | 11036 // that it can be traversed over successfully during garbage collection. |
| 10930 if (capacity_size != used_size) { | 11037 Object::MakeUnusedSpaceTraversable(array, capacity_size, used_size); |
| 10931 ASSERT(capacity_len > used_len); | |
| 10932 intptr_t leftover_size = capacity_size - used_size; | |
| 10933 | 11038 |
| 10934 uword addr = RawObject::ToAddr(array.raw()) + used_size; | |
| 10935 if (leftover_size >= Array::InstanceSize(0)) { | |
| 10936 // As we have enough space to use an array object, update the leftover | |
| 10937 // space as an Array object. | |
| 10938 RawArray* raw = reinterpret_cast<RawArray*>(RawObject::FromAddr(addr)); | |
| 10939 tags = 0; | |
| 10940 tags = RawObject::SizeTag::update(leftover_size, tags); | |
| 10941 tags = RawObject::ClassIdTag::update(kArrayCid, tags); | |
| 10942 raw->ptr()->tags_ = tags; | |
| 10943 intptr_t leftover_len = | |
| 10944 ((leftover_size - Array::InstanceSize(0)) / kWordSize); | |
| 10945 raw->ptr()->tags_ = tags; | |
| 10946 raw->ptr()->length_ = Smi::New(leftover_len); | |
| 10947 } else { | |
| 10948 // Update the leftover space as a basic object. | |
| 10949 ASSERT(leftover_size == Object::InstanceSize()); | |
| 10950 RawObject* raw = reinterpret_cast<RawObject*>(RawObject::FromAddr(addr)); | |
| 10951 tags = 0; | |
| 10952 tags = RawObject::SizeTag::update(leftover_size, tags); | |
| 10953 tags = RawObject::ClassIdTag::update(kInstanceCid, tags); | |
| 10954 raw->ptr()->tags_ = tags; | |
| 10955 } | |
| 10956 } | |
| 10957 return array.raw(); | 11039 return array.raw(); |
| 10958 } | 11040 } |
| 10959 | 11041 |
| 10960 | 11042 |
| 10961 RawImmutableArray* ImmutableArray::New(intptr_t len, | 11043 RawImmutableArray* ImmutableArray::New(intptr_t len, |
| 10962 Heap::Space space) { | 11044 Heap::Space space) { |
| 10963 ASSERT(Isolate::Current()->object_store()->immutable_array_class() != | 11045 ASSERT(Isolate::Current()->object_store()->immutable_array_class() != |
| 10964 Class::null()); | 11046 Class::null()); |
| 10965 return reinterpret_cast<RawImmutableArray*>(Array::New(kClassId, len, space)); | 11047 return reinterpret_cast<RawImmutableArray*>(Array::New(kClassId, len, space)); |
| 10966 } | 11048 } |
| (...skipping 946 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 11913 } | 11995 } |
| 11914 return result.raw(); | 11996 return result.raw(); |
| 11915 } | 11997 } |
| 11916 | 11998 |
| 11917 | 11999 |
| 11918 const char* WeakProperty::ToCString() const { | 12000 const char* WeakProperty::ToCString() const { |
| 11919 return "_WeakProperty"; | 12001 return "_WeakProperty"; |
| 11920 } | 12002 } |
| 11921 | 12003 |
| 11922 } // namespace dart | 12004 } // namespace dart |
| OLD | NEW |