From 138eb324ea2cd367b2252d199b3b81b18f7b10d5 Mon Sep 17 00:00:00 2001 From: ishell Date: Fri, 13 Nov 2015 04:32:08 -0800 Subject: [PATCH] Object's body descriptors refactoring. 1) Body descriptors moved to their own header files. 2) Missing body descriptors added. 3) Template versions of HeapObject::Iterate*() methods added. 4) Body descriptors support new kind of queries: IsValidSlot(offset) which can be used for invalid slots filtering. This is a first step towards virtual and static visitors unification and support in-object properties in built-in (sub-)classes. Review URL: https://codereview.chromium.org/1440243002 Cr-Commit-Position: refs/heads/master@{#31980} --- BUILD.gn | 2 + src/heap/mark-compact.cc | 9 +- src/heap/objects-visiting-inl.h | 102 +---- src/heap/objects-visiting.cc | 132 ------ src/heap/objects-visiting.h | 1 + src/heap/scavenger.cc | 3 +- src/heap/store-buffer.cc | 3 +- src/objects-body-descriptors-inl.h | 584 ++++++++++++++++++++++++ src/objects-body-descriptors.h | 139 ++++++ src/objects-inl.h | 233 +--------- src/objects.cc | 39 +- src/objects.h | 158 ++----- src/profiler/heap-snapshot-generator.cc | 3 +- tools/gyp/v8.gyp | 2 + 14 files changed, 830 insertions(+), 580 deletions(-) create mode 100644 src/objects-body-descriptors-inl.h create mode 100644 src/objects-body-descriptors.h diff --git a/BUILD.gn b/BUILD.gn index 2dd9aa20b5..b5fe404e5e 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1127,6 +1127,8 @@ source_set("v8_base") { "src/modules.cc", "src/modules.h", "src/msan.h", + "src/objects-body-descriptors-inl.h", + "src/objects-body-descriptors.h", "src/objects-debug.cc", "src/objects-inl.h", "src/objects-printer.cc", diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc index 879bbb6730..bf43a36f20 100644 --- a/src/heap/mark-compact.cc +++ b/src/heap/mark-compact.cc @@ -1813,7 +1813,7 @@ void MarkCompactCollector::ProcessTopOptimizedFrame(ObjectVisitor* visitor) { if (it.frame()->type() == StackFrame::OPTIMIZED) { Code* code = it.frame()->LookupCode(); if (!code->CanDeoptAt(it.frame()->pc())) { - code->CodeIterateBody(visitor); + Code::BodyDescriptor::IterateBody(code, visitor); } ProcessMarkingDeque(); return; @@ -2723,8 +2723,7 @@ void MarkCompactCollector::MigrateObjectMixed( heap()->MoveBlock(dst->address(), src->address(), size); // Visit inherited JSObject properties and byte length of ArrayBuffer - Address regular_slot = - dst->address() + JSArrayBuffer::BodyDescriptor::kStartOffset; + Address regular_slot = dst->address() + JSArrayBuffer::kPropertiesOffset; Address regular_slots_end = dst->address() + JSArrayBuffer::kByteLengthOffset + kPointerSize; while (regular_slot < regular_slots_end) { @@ -2793,7 +2792,7 @@ static inline void UpdateSlot(Isolate* isolate, ObjectVisitor* v, } case SlotsBuffer::RELOCATED_CODE_OBJECT: { HeapObject* obj = HeapObject::FromAddress(addr); - Code::cast(obj)->CodeIterateBody(v); + Code::BodyDescriptor::IterateBody(obj, v); break; } case SlotsBuffer::DEBUG_TARGET_SLOT: { @@ -3140,7 +3139,7 @@ bool MarkCompactCollector::IsSlotInLiveObject(Address slot) { BytecodeArray::kConstantPoolOffset; } else if (object->IsJSArrayBuffer()) { int off = static_cast(slot - object->address()); - return (off >= JSArrayBuffer::BodyDescriptor::kStartOffset && + return (off >= JSArrayBuffer::kPropertiesOffset && off <= JSArrayBuffer::kByteLengthOffset) || (off >= JSArrayBuffer::kSize && off < JSArrayBuffer::kSizeWithInternalFields); diff --git a/src/heap/objects-visiting-inl.h b/src/heap/objects-visiting-inl.h index d6a189a98d..08e9092cb8 100644 --- a/src/heap/objects-visiting-inl.h +++ b/src/heap/objects-visiting-inl.h @@ -9,6 +9,7 @@ #include "src/heap/objects-visiting.h" #include "src/ic/ic-state.h" #include "src/macro-assembler.h" +#include "src/objects-body-descriptors-inl.h" namespace v8 { namespace internal { @@ -94,14 +95,14 @@ void StaticNewSpaceVisitor::Initialize() { template int StaticNewSpaceVisitor::VisitJSArrayBuffer( Map* map, HeapObject* object) { - Heap* heap = map->GetHeap(); + typedef FlexibleBodyVisitor + JSArrayBufferBodyVisitor; - JSArrayBuffer::JSArrayBufferIterateBody< - StaticNewSpaceVisitor >(heap, object); if (!JSArrayBuffer::cast(object)->is_external()) { + Heap* heap = map->GetHeap(); heap->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(object)); } - return JSArrayBuffer::kSizeWithInternalFields; + return JSArrayBufferBodyVisitor::Visit(map, object); } @@ -427,6 +428,8 @@ void StaticMarkingVisitor::VisitWeakCollection( template void StaticMarkingVisitor::VisitCode(Map* map, HeapObject* object) { + typedef FlexibleBodyVisitor + CodeBodyVisitor; Heap* heap = map->GetHeap(); Code* code = Code::cast(object); if (FLAG_age_code && !heap->isolate()->serializer_enabled()) { @@ -439,7 +442,7 @@ void StaticMarkingVisitor::VisitCode(Map* map, MarkInlinedFunctionsCode(heap, code); } } - code->CodeIterateBody(heap); + CodeBodyVisitor::Visit(map, object); } @@ -525,12 +528,9 @@ void StaticMarkingVisitor::VisitJSFunction(Map* map, template void StaticMarkingVisitor::VisitJSRegExp(Map* map, HeapObject* object) { - int last_property_offset = - JSRegExp::kSize + kPointerSize * map->GetInObjectProperties(); - StaticVisitor::VisitPointers( - map->GetHeap(), object, - HeapObject::RawField(object, JSRegExp::kPropertiesOffset), - HeapObject::RawField(object, last_property_offset)); + typedef FlexibleBodyVisitor + JSRegExpBodyVisitor; + JSRegExpBodyVisitor::Visit(map, object); } @@ -539,7 +539,11 @@ void StaticMarkingVisitor::VisitJSArrayBuffer( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); - JSArrayBuffer::JSArrayBufferIterateBody(heap, object); + typedef FlexibleBodyVisitor JSArrayBufferBodyVisitor; + + JSArrayBufferBodyVisitor::Visit(map, object); + if (!JSArrayBuffer::cast(object)->is_external() && !heap->InNewSpace(object)) { heap->array_buffer_tracker()->MarkLive(JSArrayBuffer::cast(object)); @@ -550,20 +554,18 @@ void StaticMarkingVisitor::VisitJSArrayBuffer( template void StaticMarkingVisitor::VisitJSTypedArray( Map* map, HeapObject* object) { - StaticVisitor::VisitPointers( - map->GetHeap(), object, - HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset), - HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields)); + typedef FlexibleBodyVisitor + JSTypedArrayBodyVisitor; + JSTypedArrayBodyVisitor::Visit(map, object); } template void StaticMarkingVisitor::VisitJSDataView(Map* map, HeapObject* object) { - StaticVisitor::VisitPointers( - map->GetHeap(), object, - HeapObject::RawField(object, JSDataView::BodyDescriptor::kStartOffset), - HeapObject::RawField(object, JSDataView::kSizeWithInternalFields)); + typedef FlexibleBodyVisitor + JSDataViewBodyVisitor; + JSDataViewBodyVisitor::Visit(map, object); } @@ -822,66 +824,6 @@ void StaticMarkingVisitor::VisitJSFunctionWeakCode( } -void Code::CodeIterateBody(ObjectVisitor* v) { - int mode_mask = RelocInfo::kCodeTargetMask | - RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | - RelocInfo::ModeMask(RelocInfo::CELL) | - RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | - RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | - RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | - RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | - RelocInfo::kDebugBreakSlotMask; - - // There are two places where we iterate code bodies: here and the - // templated CodeIterateBody (below). They should be kept in sync. - IteratePointer(v, kRelocationInfoOffset); - IteratePointer(v, kHandlerTableOffset); - IteratePointer(v, kDeoptimizationDataOffset); - IteratePointer(v, kTypeFeedbackInfoOffset); - IterateNextCodeLink(v, kNextCodeLinkOffset); - - RelocIterator it(this, mode_mask); - Isolate* isolate = this->GetIsolate(); - for (; !it.done(); it.next()) { - it.rinfo()->Visit(isolate, v); - } -} - - -template -void Code::CodeIterateBody(Heap* heap) { - int mode_mask = RelocInfo::kCodeTargetMask | - RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | - RelocInfo::ModeMask(RelocInfo::CELL) | - RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | - RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | - RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | - RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | - RelocInfo::kDebugBreakSlotMask; - - // There are two places where we iterate code bodies: here and the non- - // templated CodeIterateBody (above). They should be kept in sync. - StaticVisitor::VisitPointer( - heap, this, - reinterpret_cast(this->address() + kRelocationInfoOffset)); - StaticVisitor::VisitPointer( - heap, this, - reinterpret_cast(this->address() + kHandlerTableOffset)); - StaticVisitor::VisitPointer( - heap, this, - reinterpret_cast(this->address() + kDeoptimizationDataOffset)); - StaticVisitor::VisitPointer( - heap, this, - reinterpret_cast(this->address() + kTypeFeedbackInfoOffset)); - StaticVisitor::VisitNextCodeLink( - heap, reinterpret_cast(this->address() + kNextCodeLinkOffset)); - - - RelocIterator it(this, mode_mask); - for (; !it.done(); it.next()) { - it.rinfo()->template Visit(heap); - } -} } // namespace internal } // namespace v8 diff --git a/src/heap/objects-visiting.cc b/src/heap/objects-visiting.cc index 3d6cb73095..22d3aba7ec 100644 --- a/src/heap/objects-visiting.cc +++ b/src/heap/objects-visiting.cc @@ -179,138 +179,6 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( } -void HeapObject::IterateBody(InstanceType type, int object_size, - ObjectVisitor* v) { - // Avoiding ::cast(this) because it accesses the map pointer field. - // During GC, the map pointer field is encoded. - if (type < FIRST_NONSTRING_TYPE) { - switch (type & kStringRepresentationMask) { - case kSeqStringTag: - break; - case kConsStringTag: - ConsString::BodyDescriptor::IterateBody(this, v); - break; - case kSlicedStringTag: - SlicedString::BodyDescriptor::IterateBody(this, v); - break; - case kExternalStringTag: - if ((type & kStringEncodingMask) == kOneByteStringTag) { - reinterpret_cast(this) - ->ExternalOneByteStringIterateBody(v); - } else { - reinterpret_cast(this) - ->ExternalTwoByteStringIterateBody(v); - } - break; - } - return; - } - - switch (type) { - case FIXED_ARRAY_TYPE: - FixedArray::BodyDescriptor::IterateBody(this, object_size, v); - break; - case FIXED_DOUBLE_ARRAY_TYPE: - break; - case JS_OBJECT_TYPE: - case JS_CONTEXT_EXTENSION_OBJECT_TYPE: - case JS_GENERATOR_OBJECT_TYPE: - case JS_MODULE_TYPE: - case JS_VALUE_TYPE: - case JS_DATE_TYPE: - case JS_ARRAY_TYPE: - case JS_TYPED_ARRAY_TYPE: - case JS_DATA_VIEW_TYPE: - case JS_SET_TYPE: - case JS_MAP_TYPE: - case JS_SET_ITERATOR_TYPE: - case JS_MAP_ITERATOR_TYPE: - case JS_ITERATOR_RESULT_TYPE: - case JS_WEAK_MAP_TYPE: - case JS_WEAK_SET_TYPE: - case JS_REGEXP_TYPE: - case JS_GLOBAL_PROXY_TYPE: - case JS_GLOBAL_OBJECT_TYPE: - case JS_MESSAGE_OBJECT_TYPE: - JSObject::BodyDescriptor::IterateBody(this, object_size, v); - break; - case JS_ARRAY_BUFFER_TYPE: - JSArrayBuffer::JSArrayBufferIterateBody(this, v); - break; - case JS_FUNCTION_TYPE: - JSFunction::BodyDescriptor::IterateBody(this, object_size, v); - break; - case ODDBALL_TYPE: - Oddball::BodyDescriptor::IterateBody(this, v); - break; - case JS_PROXY_TYPE: - JSProxy::BodyDescriptor::IterateBody(this, v); - break; - case JS_FUNCTION_PROXY_TYPE: - JSFunctionProxy::BodyDescriptor::IterateBody(this, v); - break; - case FOREIGN_TYPE: - reinterpret_cast(this)->ForeignIterateBody(v); - break; - case MAP_TYPE: - Map::BodyDescriptor::IterateBody(this, v); - break; - case CODE_TYPE: - reinterpret_cast(this)->CodeIterateBody(v); - break; - case CELL_TYPE: - Cell::BodyDescriptor::IterateBody(this, v); - break; - case PROPERTY_CELL_TYPE: - PropertyCell::BodyDescriptor::IterateBody(this, v); - break; - case WEAK_CELL_TYPE: - WeakCell::BodyDescriptor::IterateBody(this, v); - break; - case SYMBOL_TYPE: - Symbol::BodyDescriptor::IterateBody(this, v); - break; - case BYTECODE_ARRAY_TYPE: - reinterpret_cast(this)->BytecodeArrayIterateBody(v); - break; - - case HEAP_NUMBER_TYPE: - case MUTABLE_HEAP_NUMBER_TYPE: - case SIMD128_VALUE_TYPE: - case FILLER_TYPE: - case BYTE_ARRAY_TYPE: - case FREE_SPACE_TYPE: - break; - -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ - case FIXED_##TYPE##_ARRAY_TYPE: \ - reinterpret_cast(this) \ - ->FixedTypedArrayBaseIterateBody(v); \ - break; - TYPED_ARRAYS(TYPED_ARRAY_CASE) -#undef TYPED_ARRAY_CASE - - case SHARED_FUNCTION_INFO_TYPE: { - SharedFunctionInfo::BodyDescriptor::IterateBody(this, v); - break; - } - -#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: - STRUCT_LIST(MAKE_STRUCT_CASE) -#undef MAKE_STRUCT_CASE - if (type == ALLOCATION_SITE_TYPE) { - AllocationSite::BodyDescriptor::IterateBody(this, v); - } else { - StructBodyDescriptor::IterateBody(this, object_size, v); - } - break; - default: - PrintF("Unknown type: %d\n", type); - UNREACHABLE(); - } -} - - // We don't record weak slots during marking or scavenges. Instead we do it // once when we complete mark-compact cycle. Note that write barrier has no // effect if we are already in the middle of compacting mark-sweep cycle and we diff --git a/src/heap/objects-visiting.h b/src/heap/objects-visiting.h index 787410d76f..d2e67565d2 100644 --- a/src/heap/objects-visiting.h +++ b/src/heap/objects-visiting.h @@ -9,6 +9,7 @@ #include "src/heap/heap.h" #include "src/heap/spaces.h" #include "src/layout-descriptor.h" +#include "src/objects-body-descriptors.h" // This file provides base classes and auxiliary methods for defining // static object visitors used during GC. diff --git a/src/heap/scavenger.cc b/src/heap/scavenger.cc index 31f1ee55b7..e2ac8d4ffd 100644 --- a/src/heap/scavenger.cc +++ b/src/heap/scavenger.cc @@ -266,7 +266,8 @@ class ScavengingVisitor : public StaticVisitorBase { static inline void EvacuateFixedArray(Map* map, HeapObject** slot, HeapObject* object) { - int object_size = FixedArray::BodyDescriptor::SizeOf(map, object); + int length = reinterpret_cast(object)->synchronized_length(); + int object_size = FixedArray::SizeFor(length); EvacuateObject(map, slot, object, object_size); } diff --git a/src/heap/store-buffer.cc b/src/heap/store-buffer.cc index 2ed9deccff..048b49f10f 100644 --- a/src/heap/store-buffer.cc +++ b/src/heap/store-buffer.cc @@ -502,8 +502,7 @@ void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) { slot_callback); } else if (heap_object->IsJSArrayBuffer()) { FindPointersToNewSpaceInRegion( - obj_address + - JSArrayBuffer::BodyDescriptor::kStartOffset, + obj_address + JSArrayBuffer::kPropertiesOffset, obj_address + JSArrayBuffer::kByteLengthOffset + kPointerSize, slot_callback); diff --git a/src/objects-body-descriptors-inl.h b/src/objects-body-descriptors-inl.h new file mode 100644 index 0000000000..8fe507ea3c --- /dev/null +++ b/src/objects-body-descriptors-inl.h @@ -0,0 +1,584 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ +#define V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ + +#include "src/objects-body-descriptors.h" + +namespace v8 { +namespace internal { + +template +int FlexibleBodyDescriptor::SizeOf(Map* map, HeapObject* object) { + return object->SizeFromMap(map); +} + + +bool BodyDescriptorBase::IsValidSlotImpl(HeapObject* obj, int offset) { + if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { + return true; + } else { + DCHECK(FLAG_unbox_double_fields); + DCHECK(IsAligned(offset, kPointerSize)); + + LayoutDescriptorHelper helper(obj->map()); + DCHECK(!helper.all_fields_tagged()); + return helper.IsTagged(offset); + } +} + +template +void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset, + int end_offset, ObjectVisitor* v) { + if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { + IteratePointers(obj, start_offset, end_offset, v); + } else { + DCHECK(FLAG_unbox_double_fields); + DCHECK(IsAligned(start_offset, kPointerSize) && + IsAligned(end_offset, kPointerSize)); + + LayoutDescriptorHelper helper(obj->map()); + DCHECK(!helper.all_fields_tagged()); + for (int offset = start_offset; offset < end_offset;) { + int end_of_region_offset; + if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { + IteratePointers(obj, offset, end_of_region_offset, v); + } + offset = end_of_region_offset; + } + } +} + + +template +void BodyDescriptorBase::IterateBodyImpl(Heap* heap, HeapObject* obj, + int start_offset, int end_offset) { + if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { + IteratePointers(heap, obj, start_offset, end_offset); + } else { + DCHECK(FLAG_unbox_double_fields); + DCHECK(IsAligned(start_offset, kPointerSize) && + IsAligned(end_offset, kPointerSize)); + + LayoutDescriptorHelper helper(obj->map()); + DCHECK(!helper.all_fields_tagged()); + for (int offset = start_offset; offset < end_offset;) { + int end_of_region_offset; + if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { + IteratePointers(heap, obj, offset, end_of_region_offset); + } + offset = end_of_region_offset; + } + } +} + + +template +void BodyDescriptorBase::IteratePointers(HeapObject* obj, int start_offset, + int end_offset, ObjectVisitor* v) { + v->VisitPointers(HeapObject::RawField(obj, start_offset), + HeapObject::RawField(obj, end_offset)); +} + + +template +void BodyDescriptorBase::IteratePointers(Heap* heap, HeapObject* obj, + int start_offset, int end_offset) { + StaticVisitor::VisitPointers(heap, obj, + HeapObject::RawField(obj, start_offset), + HeapObject::RawField(obj, end_offset)); +} + + +template +void BodyDescriptorBase::IteratePointer(HeapObject* obj, int offset, + ObjectVisitor* v) { + v->VisitPointer(HeapObject::RawField(obj, offset)); +} + + +template +void BodyDescriptorBase::IteratePointer(Heap* heap, HeapObject* obj, + int offset) { + StaticVisitor::VisitPointer(heap, obj, HeapObject::RawField(obj, offset)); +} + + +// Iterates the function object according to the visiting policy. +template +class JSFunction::BodyDescriptorImpl final : public BodyDescriptorBase { + public: + STATIC_ASSERT(kNonWeakFieldsEndOffset == kCodeEntryOffset); + STATIC_ASSERT(kCodeEntryOffset + kPointerSize == kNextFunctionLinkOffset); + STATIC_ASSERT(kNextFunctionLinkOffset + kPointerSize == kSize); + + static bool IsValidSlot(HeapObject* obj, int offset) { + if (offset < kSize) return true; + // TODO(ishell): v8:4531, fix when JFunctions are allowed to have + // in-object properties + // return IsValidSlotImpl(obj, offset); + return true; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IteratePointers(obj, kPropertiesOffset, kNonWeakFieldsEndOffset, v); + + if (body_visiting_policy & kVisitCodeEntry) { + v->VisitCodeEntry(obj->address() + kCodeEntryOffset); + } + + if (body_visiting_policy & kVisitNextFunction) { + IteratePointers(obj, kNextFunctionLinkOffset, kSize, v); + } + + // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object + // properties + // IterateBodyImpl(obj, kSize, object_size, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IteratePointers(heap, obj, kPropertiesOffset, + kNonWeakFieldsEndOffset); + + if (body_visiting_policy & kVisitCodeEntry) { + StaticVisitor::VisitCodeEntry(heap, obj, + obj->address() + kCodeEntryOffset); + } + + if (body_visiting_policy & kVisitNextFunction) { + IteratePointers(heap, obj, kNextFunctionLinkOffset, kSize); + } + + // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object + // properties + // IterateBodyImpl(heap, obj, kSize, object_size); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object + // properties + return JSFunction::kSize; + } +}; + + +class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase { + public: + STATIC_ASSERT(kByteLengthOffset + kPointerSize == kBackingStoreOffset); + STATIC_ASSERT(kBackingStoreOffset + kPointerSize == kBitFieldSlot); + STATIC_ASSERT(kBitFieldSlot + kPointerSize == kSize); + + static bool IsValidSlot(HeapObject* obj, int offset) { + if (offset < kBackingStoreOffset) return true; + if (offset < kSize) return false; + if (offset < kSizeWithInternalFields) return true; + // TODO(ishell): v8:4531, fix when JSArrayBuffers are allowed to have + // in-object properties + // return IsValidSlotImpl(obj, offset); + return true; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IteratePointers(obj, kPropertiesOffset, kBackingStoreOffset, v); + IteratePointers(obj, kSize, kSizeWithInternalFields, v); + + // TODO(ishell): v8:4531, fix when JSArrayBuffers are allowed to have + // in-object properties + // IterateBodyImpl(obj, kSize, object_size, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IteratePointers(heap, obj, kPropertiesOffset, + kBackingStoreOffset); + IteratePointers(heap, obj, kSize, kSizeWithInternalFields); + + // TODO(ishell): v8:4531, fix when JSArrayBuffers are allowed to have + // in-object properties + // IterateBodyImpl(heap, obj, kSize, object_size); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + // TODO(ishell): v8:4531, fix when JSArrayBuffers are allowed to have + // in-object properties + // return map->instance_size(); + return kSizeWithInternalFields; + } +}; + + +class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { + return offset == kConstantPoolOffset; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IteratePointer(obj, kConstantPoolOffset, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IteratePointer(heap, obj, kConstantPoolOffset); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + return SizeFor( + reinterpret_cast(object)->synchronized_length()); + } +}; + + +class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { + return offset == kBasePointerOffset; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IteratePointer(obj, kBasePointerOffset, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IteratePointer(heap, obj, kBasePointerOffset); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + return reinterpret_cast(object)->size(); + } +}; + + +class JSWeakCollection::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { + // TODO(ishell): v8:4531, fix when JSWeakCollections are allowed to have + // in-object properties + // return IsValidSlotImpl(obj, offset); + return true; + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IteratePointers(obj, kPropertiesOffset, kSize, v); + + // TODO(ishell): v8:4531, fix when JSWeakCollections are allowed to have + // in-object properties + // IterateBodyImpl(obj, kSize, object_size, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IteratePointers(heap, obj, kPropertiesOffset, kSize); + + // TODO(ishell): v8:4531, fix when JSWeakCollections are allowed to have + // in-object properties + // IterateBodyImpl(heap, obj, kSize, object_size); + } + + static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } +}; + + +class Foreign::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { return false; } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + v->VisitExternalReference(reinterpret_cast( + HeapObject::RawField(obj, kForeignAddressOffset))); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + StaticVisitor::VisitExternalReference(reinterpret_cast( + HeapObject::RawField(obj, kForeignAddressOffset))); + } + + static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } +}; + + +class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { return false; } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + typedef v8::String::ExternalOneByteStringResource Resource; + v->VisitExternalOneByteString(reinterpret_cast( + HeapObject::RawField(obj, kResourceOffset))); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + typedef v8::String::ExternalOneByteStringResource Resource; + StaticVisitor::VisitExternalOneByteString(reinterpret_cast( + HeapObject::RawField(obj, kResourceOffset))); + } + + static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } +}; + + +class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase { + public: + static bool IsValidSlot(HeapObject* obj, int offset) { return false; } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + typedef v8::String::ExternalStringResource Resource; + v->VisitExternalTwoByteString(reinterpret_cast( + HeapObject::RawField(obj, kResourceOffset))); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + typedef v8::String::ExternalStringResource Resource; + StaticVisitor::VisitExternalTwoByteString(reinterpret_cast( + HeapObject::RawField(obj, kResourceOffset))); + } + + static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } +}; + + +class Code::BodyDescriptor final : public BodyDescriptorBase { + public: + STATIC_ASSERT(kRelocationInfoOffset + kPointerSize == kHandlerTableOffset); + STATIC_ASSERT(kHandlerTableOffset + kPointerSize == + kDeoptimizationDataOffset); + STATIC_ASSERT(kDeoptimizationDataOffset + kPointerSize == + kTypeFeedbackInfoOffset); + STATIC_ASSERT(kTypeFeedbackInfoOffset + kPointerSize == kNextCodeLinkOffset); + + static bool IsValidSlot(HeapObject* obj, int offset) { + // Slots in code can't be invalid because we never trim code objects. + return true; + } + + template + static inline void IterateBody(HeapObject* obj, ObjectVisitor* v) { + int mode_mask = RelocInfo::kCodeTargetMask | + RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | + RelocInfo::ModeMask(RelocInfo::CELL) | + RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | + RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | + RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | + RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | + RelocInfo::kDebugBreakSlotMask; + + IteratePointers(obj, kRelocationInfoOffset, kNextCodeLinkOffset, v); + v->VisitNextCodeLink(HeapObject::RawField(obj, kNextCodeLinkOffset)); + + RelocIterator it(reinterpret_cast(obj), mode_mask); + Isolate* isolate = obj->GetIsolate(); + for (; !it.done(); it.next()) { + it.rinfo()->Visit(isolate, v); + } + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IterateBody(obj, v); + } + + template + static inline void IterateBody(HeapObject* obj) { + int mode_mask = RelocInfo::kCodeTargetMask | + RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | + RelocInfo::ModeMask(RelocInfo::CELL) | + RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | + RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | + RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | + RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | + RelocInfo::kDebugBreakSlotMask; + + Heap* heap = obj->GetHeap(); + IteratePointers(heap, obj, kRelocationInfoOffset, + kNextCodeLinkOffset); + StaticVisitor::VisitNextCodeLink( + heap, HeapObject::RawField(obj, kNextCodeLinkOffset)); + + RelocIterator it(reinterpret_cast(obj), mode_mask); + for (; !it.done(); it.next()) { + it.rinfo()->template Visit(heap); + } + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + IterateBody(obj); + } + + static inline int SizeOf(Map* map, HeapObject* object) { + return reinterpret_cast(object)->CodeSize(); + } +}; + + +template +ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) { + if (type < FIRST_NONSTRING_TYPE) { + switch (type & kStringRepresentationMask) { + case kSeqStringTag: + return ReturnType(); + case kConsStringTag: + return Op::template apply(p1, p2, p3); + case kSlicedStringTag: + return Op::template apply(p1, p2, p3); + case kExternalStringTag: + if ((type & kStringEncodingMask) == kOneByteStringTag) { + return Op::template apply( + p1, p2, p3); + } else { + return Op::template apply( + p1, p2, p3); + } + } + UNREACHABLE(); + return ReturnType(); + } + + switch (type) { + case FIXED_ARRAY_TYPE: + return Op::template apply(p1, p2, p3); + case FIXED_DOUBLE_ARRAY_TYPE: + return ReturnType(); + case JS_OBJECT_TYPE: + case JS_CONTEXT_EXTENSION_OBJECT_TYPE: + case JS_GENERATOR_OBJECT_TYPE: + case JS_MODULE_TYPE: + case JS_VALUE_TYPE: + case JS_DATE_TYPE: + case JS_ARRAY_TYPE: + case JS_TYPED_ARRAY_TYPE: + case JS_DATA_VIEW_TYPE: + case JS_SET_TYPE: + case JS_MAP_TYPE: + case JS_SET_ITERATOR_TYPE: + case JS_MAP_ITERATOR_TYPE: + case JS_ITERATOR_RESULT_TYPE: + case JS_REGEXP_TYPE: + case JS_GLOBAL_PROXY_TYPE: + case JS_GLOBAL_OBJECT_TYPE: + case JS_MESSAGE_OBJECT_TYPE: + return Op::template apply(p1, p2, p3); + case JS_WEAK_MAP_TYPE: + case JS_WEAK_SET_TYPE: + return Op::template apply(p1, p2, p3); + case JS_ARRAY_BUFFER_TYPE: + return Op::template apply(p1, p2, p3); + case JS_FUNCTION_TYPE: + return Op::template apply(p1, p2, p3); + case ODDBALL_TYPE: + return Op::template apply(p1, p2, p3); + case JS_PROXY_TYPE: + return Op::template apply(p1, p2, p3); + case JS_FUNCTION_PROXY_TYPE: + return Op::template apply(p1, p2, p3); + case FOREIGN_TYPE: + return Op::template apply(p1, p2, p3); + case MAP_TYPE: + return Op::template apply(p1, p2, p3); + case CODE_TYPE: + return Op::template apply(p1, p2, p3); + case CELL_TYPE: + return Op::template apply(p1, p2, p3); + case PROPERTY_CELL_TYPE: + return Op::template apply(p1, p2, p3); + case WEAK_CELL_TYPE: + return Op::template apply(p1, p2, p3); + case SYMBOL_TYPE: + return Op::template apply(p1, p2, p3); + case BYTECODE_ARRAY_TYPE: + return Op::template apply(p1, p2, p3); + + case HEAP_NUMBER_TYPE: + case MUTABLE_HEAP_NUMBER_TYPE: + case SIMD128_VALUE_TYPE: + case FILLER_TYPE: + case BYTE_ARRAY_TYPE: + case FREE_SPACE_TYPE: + return ReturnType(); + +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case FIXED_##TYPE##_ARRAY_TYPE: \ + return Op::template apply(p1, p2, p3); + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE + + case SHARED_FUNCTION_INFO_TYPE: { + return Op::template apply(p1, p2, p3); + } + +#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: + STRUCT_LIST(MAKE_STRUCT_CASE) +#undef MAKE_STRUCT_CASE + if (type == ALLOCATION_SITE_TYPE) { + return Op::template apply(p1, p2, p3); + } else { + return Op::template apply(p1, p2, p3); + } + default: + PrintF("Unknown type: %d\n", type); + UNREACHABLE(); + return ReturnType(); + } +} + + +template +void HeapObject::IterateFast(ObjectVisitor* v) { + BodyDescriptorBase::IteratePointer(this, kMapOffset, v); + IterateBody(v); +} + + +template +void HeapObject::IterateBodyFast(ObjectVisitor* v) { + Map* m = map(); + IterateBody(m->instance_type(), SizeFromMap(m), v); +} + + +struct CallIterateBody { + template + static void apply(HeapObject* obj, int object_size, ObjectVisitor* v) { + BodyDescriptor::IterateBody(obj, object_size, v); + } +}; + +template +void HeapObject::IterateBodyFast(InstanceType type, int object_size, + ObjectVisitor* v) { + BodyDescriptorApply(type, this, object_size, v); +} +} // namespace internal +} // namespace v8 + +#endif // V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ diff --git a/src/objects-body-descriptors.h b/src/objects-body-descriptors.h new file mode 100644 index 0000000000..8168447da6 --- /dev/null +++ b/src/objects-body-descriptors.h @@ -0,0 +1,139 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8_OBJECTS_BODY_DESCRIPTORS_H_ +#define V8_OBJECTS_BODY_DESCRIPTORS_H_ + +#include "src/objects.h" + +namespace v8 { +namespace internal { + +// This is the base class for object's body descriptors. +// +// Each BodyDescriptor subclass must provide the following methods: +// +// 1) Returns true if the object contains a tagged value at given offset. +// It is used for invalid slots filtering. If the offset points outside +// of the object or to the map word, the result is UNDEFINED (!!!). +// +// static bool IsValidSlot(HeapObject* obj, int offset); +// +// +// 2) Iterate object's body using stateful object visitor. +// +// template +// static inline void IterateBody(HeapObject* obj, int object_size, +// ObjectVisitor* v); +// +// +// 3) Iterate object's body using stateless object visitor. +// +// template +// static inline void IterateBody(HeapObject* obj, int object_size); +// +class BodyDescriptorBase BASE_EMBEDDED { + public: + template + static inline void IteratePointers(HeapObject* obj, int start_offset, + int end_offset, ObjectVisitor* v); + + template + static inline void IteratePointers(Heap* heap, HeapObject* obj, + int start_offset, int end_offset); + + template + static inline void IteratePointer(HeapObject* obj, int offset, + ObjectVisitor* v); + + template + static inline void IteratePointer(Heap* heap, HeapObject* obj, int offset); + + protected: + // Returns true for all header fields. + static inline bool IsValidSlotImpl(HeapObject* obj, int offset); + + template + static inline void IterateBodyImpl(HeapObject* obj, int start_offset, + int end_offset, ObjectVisitor* v); + + template + static inline void IterateBodyImpl(Heap* heap, HeapObject* obj, + int start_offset, int end_offset); +}; + + +// This class describes a body of an object of a fixed size +// in which all pointer fields are located in the [start_offset, end_offset) +// interval. +template +class FixedBodyDescriptor final : public BodyDescriptorBase { + public: + static const int kStartOffset = start_offset; + static const int kEndOffset = end_offset; + static const int kSize = size; + + static bool IsValidSlot(HeapObject* obj, int offset) { + return offset >= kStartOffset && offset < kEndOffset; + } + + template + static inline void IterateBody(HeapObject* obj, ObjectVisitor* v) { + IterateBodyImpl(obj, start_offset, end_offset, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IterateBody(obj, v); + } + + template + static inline void IterateBody(HeapObject* obj) { + Heap* heap = obj->GetHeap(); + IterateBodyImpl(heap, obj, start_offset, end_offset); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + IterateBody(obj); + } +}; + + +// This class describes a body of an object of a variable size +// in which all pointer fields are located in the [start_offset, object_size) +// interval. +template +class FlexibleBodyDescriptor final : public BodyDescriptorBase { + public: + static const int kStartOffset = start_offset; + + static bool IsValidSlot(HeapObject* obj, int offset) { + if (offset < kStartOffset) return false; + return IsValidSlotImpl(obj, offset); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size, + ObjectVisitor* v) { + IterateBodyImpl(obj, start_offset, object_size, v); + } + + template + static inline void IterateBody(HeapObject* obj, int object_size) { + Heap* heap = obj->GetHeap(); + IterateBodyImpl(heap, obj, start_offset, object_size); + } + + static inline int SizeOf(Map* map, HeapObject* object); +}; + + +typedef FlexibleBodyDescriptor StructBodyDescriptor; + +} // namespace internal +} // namespace v8 + +#endif // V8_OBJECTS_BODY_DESCRIPTORS_H_ diff --git a/src/objects-inl.h b/src/objects-inl.h index 8d4d545f3f..6a918f824e 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -1530,22 +1530,6 @@ HeapObjectContents HeapObject::ContentType() { } -void HeapObject::IteratePointers(ObjectVisitor* v, int start, int end) { - v->VisitPointers(reinterpret_cast(FIELD_ADDR(this, start)), - reinterpret_cast(FIELD_ADDR(this, end))); -} - - -void HeapObject::IteratePointer(ObjectVisitor* v, int offset) { - v->VisitPointer(reinterpret_cast(FIELD_ADDR(this, offset))); -} - - -void HeapObject::IterateNextCodeLink(ObjectVisitor* v, int offset) { - v->VisitNextCodeLink(reinterpret_cast(FIELD_ADDR(this, offset))); -} - - double HeapNumber::value() const { return READ_DOUBLE_FIELD(this, kValueOffset); } @@ -4173,11 +4157,6 @@ Address ByteArray::GetDataStartAddress() { } -void BytecodeArray::BytecodeArrayIterateBody(ObjectVisitor* v) { - IteratePointer(v, kConstantPoolOffset); -} - - byte BytecodeArray::get(int index) { DCHECK(index >= 0 && index < this->length()); return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize); @@ -4538,7 +4517,8 @@ int HeapObject::SizeFromMap(Map* map) { // Only inline the most frequent cases. InstanceType instance_type = map->instance_type(); if (instance_type == FIXED_ARRAY_TYPE) { - return FixedArray::BodyDescriptor::SizeOf(map, this); + return FixedArray::SizeFor( + reinterpret_cast(this)->synchronized_length()); } if (instance_type == ONE_BYTE_STRING_TYPE || instance_type == ONE_BYTE_INTERNALIZED_STRING_TYPE) { @@ -6677,32 +6657,6 @@ void JSArrayBuffer::set_is_shared(bool value) { } -// static -template -void JSArrayBuffer::JSArrayBufferIterateBody(Heap* heap, HeapObject* obj) { - StaticVisitor::VisitPointers( - heap, obj, - HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset), - HeapObject::RawField(obj, - JSArrayBuffer::kByteLengthOffset + kPointerSize)); - StaticVisitor::VisitPointers( - heap, obj, HeapObject::RawField(obj, JSArrayBuffer::kSize), - HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields)); -} - - -void JSArrayBuffer::JSArrayBufferIterateBody(HeapObject* obj, - ObjectVisitor* v) { - v->VisitPointers( - HeapObject::RawField(obj, JSArrayBuffer::BodyDescriptor::kStartOffset), - HeapObject::RawField(obj, - JSArrayBuffer::kByteLengthOffset + kPointerSize)); - v->VisitPointers( - HeapObject::RawField(obj, JSArrayBuffer::kSize), - HeapObject::RawField(obj, JSArrayBuffer::kSizeWithInternalFields)); -} - - Object* JSArrayBufferView::byte_offset() const { if (WasNeutered()) return Smi::FromInt(0); return Object::cast(READ_FIELD(this, kByteOffsetOffset)); @@ -7835,189 +7789,6 @@ Relocatable::~Relocatable() { } -// static -template -int FlexibleBodyDescriptor::SizeOf(Map* map, HeapObject* object) { - return map->instance_size(); -} - - -// static -int FixedArray::BodyDescriptor::SizeOf(Map* map, HeapObject* object) { - return SizeFor(reinterpret_cast(object)->synchronized_length()); -} - - -void Foreign::ForeignIterateBody(ObjectVisitor* v) { - v->VisitExternalReference( - reinterpret_cast(FIELD_ADDR(this, kForeignAddressOffset))); -} - - -template -void Foreign::ForeignIterateBody() { - StaticVisitor::VisitExternalReference( - reinterpret_cast(FIELD_ADDR(this, kForeignAddressOffset))); -} - - -void FixedTypedArrayBase::FixedTypedArrayBaseIterateBody(ObjectVisitor* v) { - v->VisitPointer( - reinterpret_cast(FIELD_ADDR(this, kBasePointerOffset))); -} - - -template -void FixedTypedArrayBase::FixedTypedArrayBaseIterateBody() { - StaticVisitor::VisitPointer( - reinterpret_cast(FIELD_ADDR(this, kBasePointerOffset))); -} - - -void ExternalOneByteString::ExternalOneByteStringIterateBody(ObjectVisitor* v) { - typedef v8::String::ExternalOneByteStringResource Resource; - v->VisitExternalOneByteString( - reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); -} - - -template -void ExternalOneByteString::ExternalOneByteStringIterateBody() { - typedef v8::String::ExternalOneByteStringResource Resource; - StaticVisitor::VisitExternalOneByteString( - reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); -} - - -void ExternalTwoByteString::ExternalTwoByteStringIterateBody(ObjectVisitor* v) { - typedef v8::String::ExternalStringResource Resource; - v->VisitExternalTwoByteString( - reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); -} - - -template -void ExternalTwoByteString::ExternalTwoByteStringIterateBody() { - typedef v8::String::ExternalStringResource Resource; - StaticVisitor::VisitExternalTwoByteString( - reinterpret_cast(FIELD_ADDR(this, kResourceOffset))); -} - - -void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset, - int end_offset, ObjectVisitor* v) { - if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { - IteratePointers(obj, start_offset, end_offset, v); - } else { - DCHECK(FLAG_unbox_double_fields); - DCHECK(IsAligned(start_offset, kPointerSize) && - IsAligned(end_offset, kPointerSize)); - - LayoutDescriptorHelper helper(obj->map()); - DCHECK(!helper.all_fields_tagged()); - for (int offset = start_offset; offset < end_offset;) { - int end_of_region_offset; - if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { - IteratePointers(obj, offset, end_of_region_offset, v); - } - offset = end_of_region_offset; - } - } -} - - -template -void BodyDescriptorBase::IterateBodyImpl(Heap* heap, HeapObject* obj, - int start_offset, int end_offset) { - if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { - IteratePointers(heap, obj, start_offset, end_offset); - } else { - DCHECK(FLAG_unbox_double_fields); - DCHECK(IsAligned(start_offset, kPointerSize) && - IsAligned(end_offset, kPointerSize)); - - LayoutDescriptorHelper helper(obj->map()); - DCHECK(!helper.all_fields_tagged()); - for (int offset = start_offset; offset < end_offset;) { - int end_of_region_offset; - if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { - IteratePointers(heap, obj, offset, end_of_region_offset); - } - offset = end_of_region_offset; - } - } -} - - -void BodyDescriptorBase::IteratePointers(HeapObject* obj, int start_offset, - int end_offset, ObjectVisitor* v) { - v->VisitPointers(HeapObject::RawField(obj, start_offset), - HeapObject::RawField(obj, end_offset)); -} - - -template -void BodyDescriptorBase::IteratePointers(Heap* heap, HeapObject* obj, - int start_offset, int end_offset) { - StaticVisitor::VisitPointers(heap, obj, - HeapObject::RawField(obj, start_offset), - HeapObject::RawField(obj, end_offset)); -} - - -// Iterates the function object according to the visiting policy. -template -class JSFunction::BodyDescriptorImpl : public BodyDescriptorBase { - public: - STATIC_ASSERT(kNonWeakFieldsEndOffset == kCodeEntryOffset); - STATIC_ASSERT(kCodeEntryOffset + kPointerSize == kNextFunctionLinkOffset); - STATIC_ASSERT(kNextFunctionLinkOffset + kPointerSize == kSize); - - static inline void IterateBody(HeapObject* obj, int object_size, - ObjectVisitor* v) { - IteratePointers(obj, kPropertiesOffset, kNonWeakFieldsEndOffset, v); - - if (body_visiting_policy & kVisitCodeEntry) { - v->VisitCodeEntry(obj->address() + kCodeEntryOffset); - } - - if (body_visiting_policy & kVisitNextFunction) { - IteratePointers(obj, kNextFunctionLinkOffset, kSize, v); - } - - // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object - // properties - // IterateBodyImpl(obj, kSize, object_size, v); - } - - template - static inline void IterateBody(HeapObject* obj, int object_size) { - Heap* heap = obj->GetHeap(); - IteratePointers(heap, obj, kPropertiesOffset, - kNonWeakFieldsEndOffset); - - if (body_visiting_policy & kVisitCodeEntry) { - StaticVisitor::VisitCodeEntry(heap, obj, - obj->address() + kCodeEntryOffset); - } - - if (body_visiting_policy & kVisitNextFunction) { - IteratePointers(heap, obj, kNextFunctionLinkOffset, kSize); - } - - // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object - // properties - // IterateBodyImpl(heap, obj, kSize, object_size); - } - - static inline int SizeOf(Map* map, HeapObject* object) { - // TODO(ishell): v8:4531, fix when JFunctions are allowed to have in-object - // properties - return JSFunction::kSize; - } -}; - - template Object* OrderedHashTableIterator::CurrentKey() { TableType* table(TableType::cast(this->table())); diff --git a/src/objects.cc b/src/objects.cc index 74ee5a32bc..d61250f199 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -37,6 +37,7 @@ #include "src/macro-assembler.h" #include "src/messages.h" #include "src/objects-inl.h" +#include "src/objects-body-descriptors-inl.h" #include "src/profiler/cpu-profiler.h" #include "src/property-descriptor.h" #include "src/prototype.h" @@ -1999,12 +2000,33 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT } -void HeapObject::Iterate(ObjectVisitor* v) { - // Handle header - IteratePointer(v, kMapOffset); - // Handle object body +void HeapObject::Iterate(ObjectVisitor* v) { IterateFast(v); } + + +void HeapObject::IterateBody(ObjectVisitor* v) { Map* m = map(); - IterateBody(m->instance_type(), SizeFromMap(m), v); + IterateBodyFast(m->instance_type(), SizeFromMap(m), v); +} + + +void HeapObject::IterateBody(InstanceType type, int object_size, + ObjectVisitor* v) { + IterateBodyFast(type, object_size, v); +} + + +struct CallIsValidSlot { + template + static bool apply(HeapObject* obj, int offset, int) { + return BodyDescriptor::IsValidSlot(obj, offset); + } +}; + + +bool HeapObject::IsValidSlot(int offset) { + DCHECK_NE(0, offset); + return BodyDescriptorApply(map()->instance_type(), + this, offset, 0); } @@ -15249,15 +15271,14 @@ class InternalizedStringKey : public HashTableKey { template void HashTable::IteratePrefix(ObjectVisitor* v) { - IteratePointers(v, 0, kElementsStartOffset); + BodyDescriptorBase::IteratePointers(this, 0, kElementsStartOffset, v); } template void HashTable::IterateElements(ObjectVisitor* v) { - IteratePointers(v, - kElementsStartOffset, - kHeaderSize + length() * kPointerSize); + BodyDescriptorBase::IteratePointers(this, kElementsStartOffset, + kHeaderSize + length() * kPointerSize, v); } diff --git a/src/objects.h b/src/objects.h index e135bd2dd1..61263631e9 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1555,15 +1555,35 @@ class HeapObject: public Object { return reinterpret_cast
(this) - kHeapObjectTag; } - // Iterates over pointers contained in the object (including the Map) + // Iterates over pointers contained in the object (including the Map). + // If it's not performance critical iteration use the non-templatized + // version. void Iterate(ObjectVisitor* v); + template + inline void IterateFast(ObjectVisitor* v); + // Iterates over all pointers contained in the object except the // first map pointer. The object type is given in the first // parameter. This function does not access the map pointer in the // object, and so is safe to call while the map pointer is modified. + // If it's not performance critical iteration use the non-templatized + // version. + void IterateBody(ObjectVisitor* v); void IterateBody(InstanceType type, int object_size, ObjectVisitor* v); + template + inline void IterateBodyFast(ObjectVisitor* v); + + template + inline void IterateBodyFast(InstanceType type, int object_size, + ObjectVisitor* v); + + // Returns true if the object contains a tagged value at given offset. + // It is used for invalid slots filtering. If the offset points outside + // of the object or to the map word, the result is UNDEFINED (!!!). + bool IsValidSlot(int offset); + // Returns the heap object's size in bytes inline int Size(); @@ -1623,90 +1643,17 @@ class HeapObject: public Object { STATIC_ASSERT(kMapOffset == Internals::kHeapObjectMapOffset); - protected: - // helpers for calling an ObjectVisitor to iterate over pointers in the - // half-open range [start, end) specified as integer offsets - inline void IteratePointers(ObjectVisitor* v, int start, int end); - // as above, for the single element at "offset" - inline void IteratePointer(ObjectVisitor* v, int offset); - // as above, for the next code link of a code object. - inline void IterateNextCodeLink(ObjectVisitor* v, int offset); - private: DISALLOW_IMPLICIT_CONSTRUCTORS(HeapObject); }; -// This is the base class for object's body descriptors. -class BodyDescriptorBase { - protected: - static inline void IterateBodyImpl(HeapObject* obj, int start_offset, - int end_offset, ObjectVisitor* v); - - template - static inline void IterateBodyImpl(Heap* heap, HeapObject* obj, - int start_offset, int end_offset); - - static inline void IteratePointers(HeapObject* obj, int start_offset, - int end_offset, ObjectVisitor* v); - - template - static inline void IteratePointers(Heap* heap, HeapObject* obj, - int start_offset, int end_offset); -}; - - -// This class describes a body of an object of a fixed size -// in which all pointer fields are located in the [start_offset, end_offset) -// interval. template -class FixedBodyDescriptor : public BodyDescriptorBase { - public: - static const int kStartOffset = start_offset; - static const int kEndOffset = end_offset; - static const int kSize = size; - - static inline void IterateBody(HeapObject* obj, ObjectVisitor* v) { - IterateBodyImpl(obj, start_offset, end_offset, v); - } - - template - static inline void IterateBody(HeapObject* obj) { - Heap* heap = obj->GetHeap(); - IterateBodyImpl(heap, obj, start_offset, end_offset); - } -}; +class FixedBodyDescriptor; -// This base class describes a body of an object of a variable size -// in which all pointer fields are located in the [start_offset, object_size) -// interval. template -class FlexibleBodyDescriptorBase : public BodyDescriptorBase { - public: - static const int kStartOffset = start_offset; - - static inline void IterateBody(HeapObject* obj, int object_size, - ObjectVisitor* v) { - IterateBodyImpl(obj, start_offset, object_size, v); - } - - template - static inline void IterateBody(HeapObject* obj, int object_size) { - Heap* heap = obj->GetHeap(); - IterateBodyImpl(heap, obj, start_offset, object_size); - } -}; - - -// This class describes a body of an object of a variable size -// in which all pointer fields are located in the [start_offset, object_size) -// interval. The size of the object is taken from the map. -template -class FlexibleBodyDescriptor : public FlexibleBodyDescriptorBase { - public: - static inline int SizeOf(Map* map, HeapObject* object); -}; +class FlexibleBodyDescriptor; // The HeapNumber class describes heap allocated numbers that cannot be @@ -2688,10 +2635,7 @@ class FixedArray: public FixedArrayBase { // object, the prefix of this array is sorted. void SortPairs(FixedArray* numbers, uint32_t len); - class BodyDescriptor : public FlexibleBodyDescriptorBase { - public: - static inline int SizeOf(Map* map, HeapObject* object); - }; + typedef FlexibleBodyDescriptor BodyDescriptor; protected: // Set operation on FixedArray without using write barriers. Can @@ -4423,7 +4367,6 @@ class BytecodeArray : public FixedArrayBase { // Dispatched behavior. inline int BytecodeArraySize(); - inline void BytecodeArrayIterateBody(ObjectVisitor* v); DECLARE_PRINTER(BytecodeArray) DECLARE_VERIFIER(BytecodeArray) @@ -4443,6 +4386,8 @@ class BytecodeArray : public FixedArrayBase { // Maximal length of a single BytecodeArray. static const int kMaxLength = kMaxSize - kHeaderSize; + class BodyDescriptor; + private: DISALLOW_IMPLICIT_CONSTRUCTORS(BytecodeArray); }; @@ -4508,11 +4453,6 @@ class FixedTypedArrayBase: public FixedArrayBase { DECL_ACCESSORS(external_pointer, void) // Dispatched behavior. - inline void FixedTypedArrayBaseIterateBody(ObjectVisitor* v); - - template - inline void FixedTypedArrayBaseIterateBody(); - DECLARE_CAST(FixedTypedArrayBase) static const int kBasePointerOffset = FixedArrayBase::kHeaderSize; @@ -4522,6 +4462,8 @@ class FixedTypedArrayBase: public FixedArrayBase { static const int kDataOffset = kHeaderSize; + class BodyDescriptor; + inline int size(); static inline int TypedArraySize(InstanceType type, int length); @@ -5192,10 +5134,6 @@ class Code: public HeapObject { // Dispatched behavior. inline int CodeSize(); - inline void CodeIterateBody(ObjectVisitor* v); - - template - inline void CodeIterateBody(Heap* heap); DECLARE_PRINTER(Code) DECLARE_VERIFIER(Code) @@ -5294,6 +5232,8 @@ class Code: public HeapObject { static const int kHeaderSize = (kHeaderPaddingStart + kCodeAlignmentMask) & ~kCodeAlignmentMask; + class BodyDescriptor; + // Byte offsets within kKindSpecificFlags1Offset. static const int kFullCodeFlags = kKindSpecificFlags1Offset; class FullCodeFlagsHasDeoptimizationSupportField: @@ -9204,11 +9144,7 @@ class ExternalOneByteString : public ExternalString { DECLARE_CAST(ExternalOneByteString) - // Garbage collection support. - inline void ExternalOneByteStringIterateBody(ObjectVisitor* v); - - template - inline void ExternalOneByteStringIterateBody(); + class BodyDescriptor; private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalOneByteString); @@ -9243,11 +9179,7 @@ class ExternalTwoByteString: public ExternalString { DECLARE_CAST(ExternalTwoByteString) - // Garbage collection support. - inline void ExternalTwoByteStringIterateBody(ObjectVisitor* v); - - template - inline void ExternalTwoByteStringIterateBody(); + class BodyDescriptor; private: DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalTwoByteString); @@ -9868,6 +9800,8 @@ class JSWeakCollection: public JSObject { static const int kNextOffset = kTableOffset + kPointerSize; static const int kSize = kNextOffset + kPointerSize; + class BodyDescriptor; + private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakCollection); }; @@ -9946,11 +9880,6 @@ class JSArrayBuffer: public JSObject { DECLARE_VERIFIER(JSArrayBuffer) static const int kByteLengthOffset = JSObject::kHeaderSize; - - // NOTE: GC will visit objects fields: - // 1. From JSObject::BodyDescriptor::kStartOffset to kByteLengthOffset + - // kPointerSize - // 2. From start of the internal fields and up to the end of them static const int kBackingStoreOffset = kByteLengthOffset + kPointerSize; static const int kBitFieldSlot = kBackingStoreOffset + kPointerSize; #if V8_TARGET_LITTLE_ENDIAN || !V8_HOST_ARCH_64_BIT @@ -9963,11 +9892,9 @@ class JSArrayBuffer: public JSObject { static const int kSizeWithInternalFields = kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize; - template - static inline void JSArrayBufferIterateBody(Heap* heap, HeapObject* obj); - - static inline void JSArrayBufferIterateBody(HeapObject* obj, - ObjectVisitor* v); + // Iterates all fields in the object including internal ones except + // kBackingStoreOffset and kBitFieldSlot. + class BodyDescriptor; class IsExternal : public BitField {}; class IsNeuterable : public BitField {}; @@ -10072,12 +9999,6 @@ class Foreign: public HeapObject { DECLARE_CAST(Foreign) - // Dispatched behavior. - inline void ForeignIterateBody(ObjectVisitor* v); - - template - inline void ForeignIterateBody(); - // Dispatched behavior. DECLARE_PRINTER(Foreign) DECLARE_VERIFIER(Foreign) @@ -10089,6 +10010,8 @@ class Foreign: public HeapObject { STATIC_ASSERT(kForeignAddressOffset == Internals::kForeignAddressOffset); + class BodyDescriptor; + private: DISALLOW_IMPLICIT_CONSTRUCTORS(Foreign); }; @@ -10752,9 +10675,6 @@ class ObjectVisitor BASE_EMBEDDED { }; -typedef FlexibleBodyDescriptor StructBodyDescriptor; - - // BooleanBit is a helper class for setting and getting a bit in an integer. class BooleanBit : public AllStatic { public: diff --git a/src/profiler/heap-snapshot-generator.cc b/src/profiler/heap-snapshot-generator.cc index 2268db223f..566ebe3820 100644 --- a/src/profiler/heap-snapshot-generator.cc +++ b/src/profiler/heap-snapshot-generator.cc @@ -7,6 +7,7 @@ #include "src/code-stubs.h" #include "src/conversions.h" #include "src/debug/debug.h" +#include "src/objects-body-descriptors.h" #include "src/profiler/allocation-tracker.h" #include "src/profiler/heap-profiler.h" #include "src/profiler/heap-snapshot-generator-inl.h" @@ -1542,7 +1543,7 @@ void V8HeapExplorer::ExtractAllocationSiteReferences(int entry, // Do not visit weak_next as it is not visited by the StaticVisitor, // and we're not very interested in weak_next field here. STATIC_ASSERT(AllocationSite::kWeakNextOffset >= - AllocationSite::BodyDescriptor::kEndOffset); + AllocationSite::BodyDescriptor::kEndOffset); } diff --git a/tools/gyp/v8.gyp b/tools/gyp/v8.gyp index b620f66017..8b86e39ead 100644 --- a/tools/gyp/v8.gyp +++ b/tools/gyp/v8.gyp @@ -867,6 +867,8 @@ '../../src/modules.cc', '../../src/modules.h', '../../src/msan.h', + '../../src/objects-body-descriptors-inl.h', + '../../src/objects-body-descriptors.h', '../../src/objects-debug.cc', '../../src/objects-inl.h', '../../src/objects-printer.cc',