blob: 47fa0092bddbe8913420aaaf15d9adfe8588b777 [file] [log] [blame]
// 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.
#include "vm/raw_object.h"
#include "vm/class_table.h"
#include "vm/dart.h"
#include "vm/freelist.h"
#include "vm/isolate.h"
#include "vm/object.h"
#include "vm/visitor.h"
namespace dart {
#if defined(DEBUG)
DEFINE_FLAG(bool, validate_overwrite, true, "Verify overwritten fields.");
#endif // DEBUG
void RawObject::Validate(Isolate* isolate) const {
if (Object::void_class_ == reinterpret_cast<RawClass*>(kHeapObjectTag)) {
// Validation relies on properly initialized class classes. Skip if the
// VM is still being initialized.
return;
}
// All Smi values are valid.
if (!IsHeapObject()) {
return;
}
// Slightly more readable than a segfault.
if (this == reinterpret_cast<RawObject*>(kHeapObjectTag)) {
FATAL("RAW_NULL encountered");
}
// Validate that the tags_ field is sensible.
uword tags = ptr()->tags_;
intptr_t reserved = ReservedBits::decode(tags);
if (reserved != 0) {
FATAL1("Invalid tags field encountered %#" Px "\n", tags);
}
intptr_t class_id = ClassIdTag::decode(tags);
if (!isolate->class_table()->IsValidIndex(class_id)) {
FATAL1("Invalid class id encountered %" Pd "\n", class_id);
}
if ((class_id == kNullCid) &&
(isolate->class_table()->At(class_id) == NULL)) {
// Null class not yet initialized; skip.
return;
}
intptr_t size = SizeTag::decode(tags);
if (size != 0 && size != SizeFromClass()) {
FATAL1("Inconsistent class size encountered %" Pd "\n", size);
}
}
intptr_t RawObject::SizeFromClass() const {
// Only reasonable to be called on heap objects.
ASSERT(IsHeapObject());
intptr_t class_id = GetClassId();
intptr_t instance_size = 0;
switch (class_id) {
case kCodeCid: {
const RawCode* raw_code = reinterpret_cast<const RawCode*>(this);
intptr_t pointer_offsets_length =
Code::PtrOffBits::decode(raw_code->ptr()->state_bits_);
instance_size = Code::InstanceSize(pointer_offsets_length);
break;
}
case kInstructionsCid: {
const RawInstructions* raw_instructions =
reinterpret_cast<const RawInstructions*>(this);
intptr_t instructions_size = raw_instructions->ptr()->size_;
instance_size = Instructions::InstanceSize(instructions_size);
break;
}
case kContextCid: {
const RawContext* raw_context =
reinterpret_cast<const RawContext*>(this);
intptr_t num_variables = raw_context->ptr()->num_variables_;
instance_size = Context::InstanceSize(num_variables);
break;
}
case kContextScopeCid: {
const RawContextScope* raw_context_scope =
reinterpret_cast<const RawContextScope*>(this);
intptr_t num_variables = raw_context_scope->ptr()->num_variables_;
instance_size = ContextScope::InstanceSize(num_variables);
break;
}
case kOneByteStringCid: {
const RawOneByteString* raw_string =
reinterpret_cast<const RawOneByteString*>(this);
intptr_t string_length = Smi::Value(raw_string->ptr()->length_);
instance_size = OneByteString::InstanceSize(string_length);
break;
}
case kTwoByteStringCid: {
const RawTwoByteString* raw_string =
reinterpret_cast<const RawTwoByteString*>(this);
intptr_t string_length = Smi::Value(raw_string->ptr()->length_);
instance_size = TwoByteString::InstanceSize(string_length);
break;
}
case kArrayCid:
case kImmutableArrayCid: {
const RawArray* raw_array = reinterpret_cast<const RawArray*>(this);
intptr_t array_length = Smi::Value(raw_array->ptr()->length_);
instance_size = Array::InstanceSize(array_length);
break;
}
case kObjectPoolCid: {
const RawObjectPool* raw_object_pool =
reinterpret_cast<const RawObjectPool*>(this);
intptr_t len = raw_object_pool->ptr()->length_;
instance_size = ObjectPool::InstanceSize(len);
break;
}
#define SIZE_FROM_CLASS(clazz) \
case kTypedData##clazz##Cid:
CLASS_LIST_TYPED_DATA(SIZE_FROM_CLASS) {
const RawTypedData* raw_obj =
reinterpret_cast<const RawTypedData*>(this);
intptr_t cid = raw_obj->GetClassId();
intptr_t array_len = Smi::Value(raw_obj->ptr()->length_);
intptr_t lengthInBytes = array_len * TypedData::ElementSizeInBytes(cid);
instance_size = TypedData::InstanceSize(lengthInBytes);
break;
}
#undef SIZE_FROM_CLASS
case kTypeArgumentsCid: {
const RawTypeArguments* raw_array =
reinterpret_cast<const RawTypeArguments*>(this);
intptr_t array_length = Smi::Value(raw_array->ptr()->length_);
instance_size = TypeArguments::InstanceSize(array_length);
break;
}
case kPcDescriptorsCid: {
const RawPcDescriptors* raw_descriptors =
reinterpret_cast<const RawPcDescriptors*>(this);
intptr_t length = raw_descriptors->ptr()->length_;
instance_size = PcDescriptors::InstanceSize(length);
break;
}
case kStackmapCid: {
const RawStackmap* map = reinterpret_cast<const RawStackmap*>(this);
intptr_t length = map->ptr()->length_;
instance_size = Stackmap::InstanceSize(length);
break;
}
case kLocalVarDescriptorsCid: {
const RawLocalVarDescriptors* raw_descriptors =
reinterpret_cast<const RawLocalVarDescriptors*>(this);
intptr_t num_descriptors = raw_descriptors->ptr()->num_entries_;
instance_size = LocalVarDescriptors::InstanceSize(num_descriptors);
break;
}
case kExceptionHandlersCid: {
const RawExceptionHandlers* raw_handlers =
reinterpret_cast<const RawExceptionHandlers*>(this);
intptr_t num_handlers = raw_handlers->ptr()->num_entries_;
instance_size = ExceptionHandlers::InstanceSize(num_handlers);
break;
}
case kFreeListElement: {
uword addr = RawObject::ToAddr(const_cast<RawObject*>(this));
FreeListElement* element = reinterpret_cast<FreeListElement*>(addr);
instance_size = element->Size();
break;
}
default: {
// Get the (constant) instance size out of the class object.
// TODO(koda): Add Size(ClassTable*) interface to allow caching in loops.
Isolate* isolate = Isolate::Current();
ClassTable* class_table = isolate->class_table();
#if defined(DEBUG)
if (!class_table->IsValidIndex(class_id) ||
!class_table->HasValidClassAt(class_id)) {
FATAL2("Invalid class id: %" Pd " from tags %" Px "\n",
class_id, ptr()->tags_);
}
#endif // DEBUG
RawClass* raw_class = class_table->At(class_id);
ASSERT(raw_class->ptr()->id_ == class_id);
instance_size =
raw_class->ptr()->instance_size_in_words_ << kWordSizeLog2;
}
}
ASSERT(instance_size != 0);
#if defined(DEBUG)
uword tags = ptr()->tags_;
intptr_t tags_size = SizeTag::decode(tags);
if ((class_id == kArrayCid) && (instance_size > tags_size && tags_size > 0)) {
// TODO(22501): Array::MakeArray could be in the process of shrinking
// the array (see comment therein), having already updated the tags but not
// yet set the new length. Wait a millisecond and try again.
int retries_remaining = 1000; // ... but not forever.
do {
OS::Sleep(1);
const RawArray* raw_array = reinterpret_cast<const RawArray*>(this);
intptr_t array_length = Smi::Value(raw_array->ptr()->length_);
instance_size = Array::InstanceSize(array_length);
} while ((instance_size > tags_size) && (--retries_remaining > 0));
}
if ((instance_size != tags_size) && (tags_size != 0)) {
FATAL3("Size mismatch: %" Pd " from class vs %" Pd " from tags %" Px "\n",
instance_size, tags_size, tags);
}
#endif // DEBUG
return instance_size;
}
#if defined(DEBUG)
void RawObject::ValidateOverwrittenPointer(RawObject* raw) {
if (FLAG_validate_overwrite) {
raw->Validate(Isolate::Current());
}
}
void RawObject::ValidateOverwrittenSmi(RawSmi* raw) {
if (FLAG_validate_overwrite && raw->IsHeapObject() && raw != Object::null()) {
FATAL1("Expected smi/null, found: %" Px "\n", reinterpret_cast<uword>(raw));
}
}
#endif // DEBUG
intptr_t RawObject::VisitPointers(ObjectPointerVisitor* visitor) {
intptr_t size = 0;
// Only reasonable to be called on heap objects.
ASSERT(IsHeapObject());
// Read the necessary data out of the class before visting the class itself.
intptr_t class_id = GetClassId();
if (class_id < kNumPredefinedCids) {
switch (class_id) {
#define RAW_VISITPOINTERS(clazz) \
case k##clazz##Cid: { \
Raw##clazz* raw_obj = reinterpret_cast<Raw##clazz*>(this); \
size = Raw##clazz::Visit##clazz##Pointers(raw_obj, visitor); \
break; \
}
CLASS_LIST_NO_OBJECT(RAW_VISITPOINTERS)
#undef RAW_VISITPOINTERS
#define RAW_VISITPOINTERS(clazz) \
case kTypedData##clazz##Cid:
CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS) {
RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(this);
size = RawTypedData::VisitTypedDataPointers(raw_obj, visitor);
break;
}
#undef RAW_VISITPOINTERS
#define RAW_VISITPOINTERS(clazz) \
case kExternalTypedData##clazz##Cid:
CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS) {
RawExternalTypedData* raw_obj =
reinterpret_cast<RawExternalTypedData*>(this);
size = RawExternalTypedData::VisitExternalTypedDataPointers(raw_obj,
visitor);
break;
}
#undef RAW_VISITPOINTERS
#define RAW_VISITPOINTERS(clazz) \
case kTypedData##clazz##ViewCid:
CLASS_LIST_TYPED_DATA(RAW_VISITPOINTERS)
case kByteDataViewCid:
case kByteBufferCid: {
RawInstance* raw_obj = reinterpret_cast<RawInstance*>(this);
size = RawInstance::VisitInstancePointers(raw_obj, visitor);
break;
}
#undef RAW_VISITPOINTERS
case kFreeListElement: {
uword addr = RawObject::ToAddr(const_cast<RawObject*>(this));
FreeListElement* element = reinterpret_cast<FreeListElement*>(addr);
size = element->Size();
break;
}
case kNullCid:
size = Size();
break;
default:
OS::Print("Class Id: %" Pd "\n", class_id);
UNREACHABLE();
break;
}
} else {
RawInstance* raw_obj = reinterpret_cast<RawInstance*>(this);
size = RawInstance::VisitInstancePointers(raw_obj, visitor);
}
ASSERT(size != 0);
ASSERT(size == Size());
return size;
}
bool RawObject::FindObject(FindObjectVisitor* visitor) {
ASSERT(visitor != NULL);
return visitor->FindObject(const_cast<RawObject*>(this));
}
intptr_t RawClass::VisitClassPointers(RawClass* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Class::InstanceSize();
}
intptr_t RawUnresolvedClass::VisitUnresolvedClassPointers(
RawUnresolvedClass* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return UnresolvedClass::InstanceSize();
}
intptr_t RawAbstractType::VisitAbstractTypePointers(
RawAbstractType* raw_obj, ObjectPointerVisitor* visitor) {
// RawAbstractType is an abstract class.
UNREACHABLE();
return 0;
}
intptr_t RawType::VisitTypePointers(
RawType* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Type::InstanceSize();
}
intptr_t RawTypeRef::VisitTypeRefPointers(
RawTypeRef* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return TypeRef::InstanceSize();
}
intptr_t RawTypeParameter::VisitTypeParameterPointers(
RawTypeParameter* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return TypeParameter::InstanceSize();
}
intptr_t RawBoundedType::VisitBoundedTypePointers(
RawBoundedType* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return BoundedType::InstanceSize();
}
intptr_t RawMixinAppType::VisitMixinAppTypePointers(
RawMixinAppType* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return MixinAppType::InstanceSize();
}
intptr_t RawTypeArguments::VisitTypeArgumentsPointers(
RawTypeArguments* raw_obj, ObjectPointerVisitor* visitor) {
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
visitor->VisitPointers(raw_obj->from(), raw_obj->to(length));
return TypeArguments::InstanceSize(length);
}
intptr_t RawPatchClass::VisitPatchClassPointers(RawPatchClass* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return PatchClass::InstanceSize();
}
intptr_t RawClosureData::VisitClosureDataPointers(
RawClosureData* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ClosureData::InstanceSize();
}
intptr_t RawRedirectionData::VisitRedirectionDataPointers(
RawRedirectionData* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return RedirectionData::InstanceSize();
}
bool RawFunction::CheckUsageCounter(RawFunction* raw_fun) {
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not okay to use regular Zone or
// Scope handles. We use direct stack handles, and so the raw pointers in
// these handles are not traversed. The use of handles is mainly to
// be able to reuse the handle based code and avoid having to add
// helper functions to the raw object interface.
Function fn;
fn = raw_fun;
// The function may not have code.
if (!fn.HasCode()) return false;
// These may not increment the usage counter.
if (fn.is_intrinsic()) return false;
if (fn.usage_counter() >= 0) {
fn.set_usage_counter(fn.usage_counter() / 2);
}
return FLAG_always_drop_code || (fn.usage_counter() == 0);
}
bool RawFunction::ShouldVisitCode(RawCode* raw_code) {
// NOTE: This code runs while GC is in progress and runs within
// a NoHandleScope block. Hence it is not okay to use regular Zone or
// Scope handles. We use direct stack handles, and so the raw pointers in
// these handles are not traversed. The use of handles is mainly to
// be able to reuse the handle based code and avoid having to add
// helper functions to the raw object interface.
Code code;
code = raw_code;
if (code.IsNull()) return true;
if (code.is_optimized()) return true;
if (code.HasBreakpoint()) return true;
return false;
}
intptr_t RawFunction::VisitFunctionPointers(RawFunction* raw_obj,
ObjectPointerVisitor* visitor) {
if (visitor->visit_function_code() || !CheckUsageCounter(raw_obj)) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Function::InstanceSize();
}
visitor->VisitPointers(raw_obj->from(), raw_obj->to_no_code());
if (ShouldVisitCode(raw_obj->ptr()->code_)) {
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&raw_obj->ptr()->code_));
} else {
visitor->add_skipped_code_function(raw_obj);
}
if (ShouldVisitCode(raw_obj->ptr()->unoptimized_code_)) {
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&raw_obj->ptr()->unoptimized_code_));
} else {
visitor->add_skipped_code_function(raw_obj);
}
return Function::InstanceSize();
}
intptr_t RawField::VisitFieldPointers(RawField* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Field::InstanceSize();
}
intptr_t RawLiteralToken::VisitLiteralTokenPointers(
RawLiteralToken* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return LiteralToken::InstanceSize();
}
intptr_t RawTokenStream::VisitTokenStreamPointers(
RawTokenStream* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return TokenStream::InstanceSize();
}
intptr_t RawScript::VisitScriptPointers(RawScript* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Script::InstanceSize();
}
intptr_t RawLibrary::VisitLibraryPointers(RawLibrary* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Library::InstanceSize();
}
intptr_t RawLibraryPrefix::VisitLibraryPrefixPointers(
RawLibraryPrefix* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return LibraryPrefix::InstanceSize();
}
intptr_t RawNamespace::VisitNamespacePointers(
RawNamespace* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Namespace::InstanceSize();
}
bool RawCode::ContainsPC(RawObject* raw_obj, uword pc) {
uword tags = raw_obj->ptr()->tags_;
if (RawObject::ClassIdTag::decode(tags) == kCodeCid) {
RawCode* raw_code = reinterpret_cast<RawCode*>(raw_obj);
return RawInstructions::ContainsPC(raw_code->ptr()->instructions_, pc);
}
return false;
}
intptr_t RawCode::VisitCodePointers(RawCode* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
RawCode* obj = raw_obj->ptr();
intptr_t length = Code::PtrOffBits::decode(obj->state_bits_);
if (Code::AliveBit::decode(obj->state_bits_)) {
// Also visit all the embedded pointers in the corresponding instructions.
uword entry_point = reinterpret_cast<uword>(obj->instructions_->ptr()) +
Instructions::HeaderSize();
for (intptr_t i = 0; i < length; i++) {
int32_t offset = obj->data()[i];
visitor->VisitPointer(
reinterpret_cast<RawObject**>(entry_point + offset));
}
}
return Code::InstanceSize(length);
}
intptr_t RawObjectPool::VisitObjectPoolPointers(
RawObjectPool* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&raw_obj->ptr()->info_array_));
const intptr_t len = raw_obj->ptr()->length_;
RawTypedData* info_array = raw_obj->ptr()->info_array_->ptr();
Entry* first = raw_obj->first_entry();
for (intptr_t i = 0; i < len; ++i) {
ObjectPool::EntryType entry_type =
static_cast<ObjectPool::EntryType>(info_array->data()[i]);
if (entry_type == ObjectPool::kTaggedObject) {
visitor->VisitPointer(&(first + i)->raw_obj_);
}
}
return ObjectPool::InstanceSize(raw_obj->ptr()->length_);
}
intptr_t RawInstructions::VisitInstructionsPointers(
RawInstructions* raw_obj, ObjectPointerVisitor* visitor) {
RawInstructions* obj = raw_obj->ptr();
if (!Dart::IsRunningPrecompiledCode()) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
}
return Instructions::InstanceSize(obj->size_);
}
bool RawInstructions::ContainsPC(RawInstructions* raw_instr, uword pc) {
uword start_pc =
reinterpret_cast<uword>(raw_instr->ptr()) + Instructions::HeaderSize();
uword end_pc = start_pc + raw_instr->ptr()->size_;
ASSERT(end_pc > start_pc);
return (pc >= start_pc) && (pc < end_pc);
}
intptr_t RawPcDescriptors::VisitPcDescriptorsPointers(
RawPcDescriptors* raw_obj, ObjectPointerVisitor* visitor) {
return PcDescriptors::InstanceSize(raw_obj->ptr()->length_);
}
intptr_t RawStackmap::VisitStackmapPointers(RawStackmap* raw_obj,
ObjectPointerVisitor* visitor) {
return Stackmap::InstanceSize(raw_obj->ptr()->length_);
}
intptr_t RawLocalVarDescriptors::VisitLocalVarDescriptorsPointers(
RawLocalVarDescriptors* raw_obj, ObjectPointerVisitor* visitor) {
intptr_t num_entries = raw_obj->ptr()->num_entries_;
visitor->VisitPointers(raw_obj->from(), raw_obj->to(num_entries));
return LocalVarDescriptors::InstanceSize(num_entries);
}
intptr_t RawExceptionHandlers::VisitExceptionHandlersPointers(
RawExceptionHandlers* raw_obj, ObjectPointerVisitor* visitor) {
RawExceptionHandlers* obj = raw_obj->ptr();
intptr_t len = obj->num_entries_;
visitor->VisitPointer(
reinterpret_cast<RawObject**>(&obj->handled_types_data_));
return ExceptionHandlers::InstanceSize(len);
}
intptr_t RawContext::VisitContextPointers(RawContext* raw_obj,
ObjectPointerVisitor* visitor) {
intptr_t num_variables = raw_obj->ptr()->num_variables_;
visitor->VisitPointers(raw_obj->from(), raw_obj->to(num_variables));
return Context::InstanceSize(num_variables);
}
intptr_t RawContextScope::VisitContextScopePointers(
RawContextScope* raw_obj, ObjectPointerVisitor* visitor) {
intptr_t num_variables = raw_obj->ptr()->num_variables_;
visitor->VisitPointers(raw_obj->from(), raw_obj->to(num_variables));
return ContextScope::InstanceSize(num_variables);
}
intptr_t RawICData::VisitICDataPointers(RawICData* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ICData::InstanceSize();
}
intptr_t RawMegamorphicCache::VisitMegamorphicCachePointers(
RawMegamorphicCache* raw_obj,
ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return MegamorphicCache::InstanceSize();
}
intptr_t RawSubtypeTestCache::VisitSubtypeTestCachePointers(
RawSubtypeTestCache* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
RawSubtypeTestCache* obj = raw_obj->ptr();
visitor->VisitPointer(reinterpret_cast<RawObject**>(&obj->cache_));
return SubtypeTestCache::InstanceSize();
}
intptr_t RawError::VisitErrorPointers(RawError* raw_obj,
ObjectPointerVisitor* visitor) {
// Error is an abstract class.
UNREACHABLE();
return 0;
}
intptr_t RawApiError::VisitApiErrorPointers(
RawApiError* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ApiError::InstanceSize();
}
intptr_t RawLanguageError::VisitLanguageErrorPointers(
RawLanguageError* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return LanguageError::InstanceSize();
}
intptr_t RawUnhandledException::VisitUnhandledExceptionPointers(
RawUnhandledException* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return UnhandledException::InstanceSize();
}
intptr_t RawUnwindError::VisitUnwindErrorPointers(
RawUnwindError* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return UnwindError::InstanceSize();
}
intptr_t RawInstance::VisitInstancePointers(RawInstance* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
uword tags = raw_obj->ptr()->tags_;
intptr_t instance_size = SizeTag::decode(tags);
if (instance_size == 0) {
RawClass* cls =
visitor->isolate()->class_table()->At(raw_obj->GetClassId());
instance_size = cls->ptr()->instance_size_in_words_ << kWordSizeLog2;
}
// Calculate the first and last raw object pointer fields.
uword obj_addr = RawObject::ToAddr(raw_obj);
uword from = obj_addr + sizeof(RawObject);
uword to = obj_addr + instance_size - kWordSize;
visitor->VisitPointers(reinterpret_cast<RawObject**>(from),
reinterpret_cast<RawObject**>(to));
return instance_size;
}
intptr_t RawNumber::VisitNumberPointers(RawNumber* raw_obj,
ObjectPointerVisitor* visitor) {
// Number is an abstract class.
UNREACHABLE();
return 0;
}
intptr_t RawInteger::VisitIntegerPointers(RawInteger* raw_obj,
ObjectPointerVisitor* visitor) {
// Integer is an abstract class.
UNREACHABLE();
return 0;
}
intptr_t RawSmi::VisitSmiPointers(RawSmi* raw_obj,
ObjectPointerVisitor* visitor) {
// Smi does not have a heap representation.
UNREACHABLE();
return 0;
}
intptr_t RawMint::VisitMintPointers(RawMint* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
return Mint::InstanceSize();
}
intptr_t RawBigint::VisitBigintPointers(RawBigint* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Bigint::InstanceSize();
}
intptr_t RawDouble::VisitDoublePointers(RawDouble* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
return Double::InstanceSize();
}
intptr_t RawString::VisitStringPointers(RawString* raw_obj,
ObjectPointerVisitor* visitor) {
// String is an abstract class.
UNREACHABLE();
return 0;
}
intptr_t RawOneByteString::VisitOneByteStringPointers(
RawOneByteString* raw_obj, ObjectPointerVisitor* visitor) {
ASSERT(!raw_obj->ptr()->length_->IsHeapObject());
ASSERT(!raw_obj->ptr()->hash_->IsHeapObject());
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
return OneByteString::InstanceSize(length);
}
intptr_t RawTwoByteString::VisitTwoByteStringPointers(
RawTwoByteString* raw_obj, ObjectPointerVisitor* visitor) {
ASSERT(!raw_obj->ptr()->length_->IsHeapObject());
ASSERT(!raw_obj->ptr()->hash_->IsHeapObject());
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
return TwoByteString::InstanceSize(length);
}
intptr_t RawExternalOneByteString::VisitExternalOneByteStringPointers(
RawExternalOneByteString* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ExternalOneByteString::InstanceSize();
}
intptr_t RawExternalTwoByteString::VisitExternalTwoByteStringPointers(
RawExternalTwoByteString* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ExternalTwoByteString::InstanceSize();
}
intptr_t RawBool::VisitBoolPointers(RawBool* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
return Bool::InstanceSize();
}
intptr_t RawArray::VisitArrayPointers(RawArray* raw_obj,
ObjectPointerVisitor* visitor) {
intptr_t length = Smi::Value(raw_obj->ptr()->length_);
visitor->VisitPointers(raw_obj->from(), raw_obj->to(length));
return Array::InstanceSize(length);
}
intptr_t RawImmutableArray::VisitImmutableArrayPointers(
RawImmutableArray* raw_obj, ObjectPointerVisitor* visitor) {
return RawArray::VisitArrayPointers(raw_obj, visitor);
}
intptr_t RawGrowableObjectArray::VisitGrowableObjectArrayPointers(
RawGrowableObjectArray* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return GrowableObjectArray::InstanceSize();
}
intptr_t RawLinkedHashMap::VisitLinkedHashMapPointers(
RawLinkedHashMap* raw_obj, ObjectPointerVisitor* visitor) {
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return LinkedHashMap::InstanceSize();
}
intptr_t RawFloat32x4::VisitFloat32x4Pointers(
RawFloat32x4* raw_obj,
ObjectPointerVisitor* visitor) {
ASSERT(raw_obj->IsHeapObject());
return Float32x4::InstanceSize();
}
intptr_t RawInt32x4::VisitInt32x4Pointers(
RawInt32x4* raw_obj,
ObjectPointerVisitor* visitor) {
ASSERT(raw_obj->IsHeapObject());
return Int32x4::InstanceSize();
}
intptr_t RawFloat64x2::VisitFloat64x2Pointers(
RawFloat64x2* raw_obj,
ObjectPointerVisitor* visitor) {
ASSERT(raw_obj->IsHeapObject());
return Float64x2::InstanceSize();
}
intptr_t RawTypedData::VisitTypedDataPointers(
RawTypedData* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
intptr_t cid = raw_obj->GetClassId();
intptr_t array_len = Smi::Value(raw_obj->ptr()->length_);
intptr_t lengthInBytes = array_len * TypedData::ElementSizeInBytes(cid);
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return TypedData::InstanceSize(lengthInBytes);
}
intptr_t RawExternalTypedData::VisitExternalTypedDataPointers(
RawExternalTypedData* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ExternalTypedData::InstanceSize();
}
intptr_t RawCapability::VisitCapabilityPointers(RawCapability* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
return Capability::InstanceSize();
}
intptr_t RawReceivePort::VisitReceivePortPointers(
RawReceivePort* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return ReceivePort::InstanceSize();
}
intptr_t RawSendPort::VisitSendPortPointers(RawSendPort* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
return SendPort::InstanceSize();
}
intptr_t RawStacktrace::VisitStacktracePointers(RawStacktrace* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return Stacktrace::InstanceSize();
}
intptr_t RawJSRegExp::VisitJSRegExpPointers(RawJSRegExp* raw_obj,
ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return JSRegExp::InstanceSize();
}
intptr_t RawWeakProperty::VisitWeakPropertyPointers(
RawWeakProperty* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return WeakProperty::InstanceSize();
}
intptr_t RawMirrorReference::VisitMirrorReferencePointers(
RawMirrorReference* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return MirrorReference::InstanceSize();
}
intptr_t RawUserTag::VisitUserTagPointers(
RawUserTag* raw_obj, ObjectPointerVisitor* visitor) {
// Make sure that we got here with the tagged pointer as this.
ASSERT(raw_obj->IsHeapObject());
visitor->VisitPointers(raw_obj->from(), raw_obj->to());
return UserTag::InstanceSize();
}
} // namespace dart