Commit 279bd3e1 authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[runtime] Compress the off-heap string table

Rather than an Object array, use a Tagged_t array to store the
elements of the off-heap string table. This matches the old on-heap
string table's behaviour, and recovers memory regressions from that
work.

To be able to do this, this also introduces a new slot type,
OffHeapObjectSlot. This is because CompressedObjectSlot assumes that
the slot is on-heap, and that it can mask the slot location to
recover the isolate root. OffHeapObjectSlot doesn't define an
operator*, and instead provides a `load(const Isolate*)` method.
The other slots also gain this method so that they can use it in
slot-templated functions. Also, the RootVisitor gains an
OffHeapObjectSlot overload, which is UNREACHABLE by default and only
needs to be defined by visitors that can access the string table.

As a drive-by, fix some non-atomic accesses to the off-heap string
table, also using the new slot.

Bug: chromium:1109553
Bug: chromium:1115116
Bug: chromium:1115559
Bug: chromium:1115683
Change-Id: I819ed7bf820e9ef98ad5d5f9d0d592efbb6f5aa6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2352489
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69381}
parent 5dedee92
...@@ -682,9 +682,11 @@ class CompressedObjectSlot; ...@@ -682,9 +682,11 @@ class CompressedObjectSlot;
class CompressedMaybeObjectSlot; class CompressedMaybeObjectSlot;
class CompressedMapWordSlot; class CompressedMapWordSlot;
class CompressedHeapObjectSlot; class CompressedHeapObjectSlot;
class OffHeapCompressedObjectSlot;
class FullObjectSlot; class FullObjectSlot;
class FullMaybeObjectSlot; class FullMaybeObjectSlot;
class FullHeapObjectSlot; class FullHeapObjectSlot;
class OffHeapFullObjectSlot;
class OldSpace; class OldSpace;
class ReadOnlySpace; class ReadOnlySpace;
class RelocInfo; class RelocInfo;
...@@ -701,46 +703,39 @@ class Struct; ...@@ -701,46 +703,39 @@ class Struct;
class Symbol; class Symbol;
class Variable; class Variable;
enum class SlotLocation { kOnHeap, kOffHeap }; // Slots are either full-pointer slots or compressed slots depending on whether
// pointer compression is enabled or not.
template <SlotLocation slot_location> struct SlotTraits {
struct SlotTraits;
// Off-heap slots are always full-pointer slots.
template <>
struct SlotTraits<SlotLocation::kOffHeap> {
using TObjectSlot = FullObjectSlot;
using TMaybeObjectSlot = FullMaybeObjectSlot;
using THeapObjectSlot = FullHeapObjectSlot;
};
// On-heap slots are either full-pointer slots or compressed slots depending
// on whether the pointer compression is enabled or not.
template <>
struct SlotTraits<SlotLocation::kOnHeap> {
#ifdef V8_COMPRESS_POINTERS #ifdef V8_COMPRESS_POINTERS
using TObjectSlot = CompressedObjectSlot; using TObjectSlot = CompressedObjectSlot;
using TMaybeObjectSlot = CompressedMaybeObjectSlot; using TMaybeObjectSlot = CompressedMaybeObjectSlot;
using THeapObjectSlot = CompressedHeapObjectSlot; using THeapObjectSlot = CompressedHeapObjectSlot;
using TOffHeapObjectSlot = OffHeapCompressedObjectSlot;
#else #else
using TObjectSlot = FullObjectSlot; using TObjectSlot = FullObjectSlot;
using TMaybeObjectSlot = FullMaybeObjectSlot; using TMaybeObjectSlot = FullMaybeObjectSlot;
using THeapObjectSlot = FullHeapObjectSlot; using THeapObjectSlot = FullHeapObjectSlot;
using TOffHeapObjectSlot = OffHeapFullObjectSlot;
#endif #endif
}; };
// An ObjectSlot instance describes a kTaggedSize-sized on-heap field ("slot") // An ObjectSlot instance describes a kTaggedSize-sized on-heap field ("slot")
// holding Object value (smi or strong heap object). // holding an Object value (smi or strong heap object).
using ObjectSlot = SlotTraits<SlotLocation::kOnHeap>::TObjectSlot; using ObjectSlot = SlotTraits::TObjectSlot;
// A MaybeObjectSlot instance describes a kTaggedSize-sized on-heap field // A MaybeObjectSlot instance describes a kTaggedSize-sized on-heap field
// ("slot") holding MaybeObject (smi or weak heap object or strong heap object). // ("slot") holding MaybeObject (smi or weak heap object or strong heap object).
using MaybeObjectSlot = SlotTraits<SlotLocation::kOnHeap>::TMaybeObjectSlot; using MaybeObjectSlot = SlotTraits::TMaybeObjectSlot;
// A HeapObjectSlot instance describes a kTaggedSize-sized field ("slot") // A HeapObjectSlot instance describes a kTaggedSize-sized field ("slot")
// holding a weak or strong pointer to a heap object (think: // holding a weak or strong pointer to a heap object (think:
// HeapObjectReference). // HeapObjectReference).
using HeapObjectSlot = SlotTraits<SlotLocation::kOnHeap>::THeapObjectSlot; using HeapObjectSlot = SlotTraits::THeapObjectSlot;
// An OffHeapObjectSlot instance describes a kTaggedSize-sized field ("slot")
// holding an Object value (smi or strong heap object), whose slot location is
// off-heap.
using OffHeapObjectSlot = SlotTraits::TOffHeapObjectSlot;
using WeakSlotCallback = bool (*)(FullObjectSlot pointer); using WeakSlotCallback = bool (*)(FullObjectSlot pointer);
......
...@@ -14,14 +14,18 @@ ...@@ -14,14 +14,18 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
inline const Isolate* GetIsolateForPtrCompr(HeapObject object) { inline const Isolate* GetIsolateForPtrComprFromOnHeapAddress(Address address) {
#ifdef V8_COMPRESS_POINTERS #ifdef V8_COMPRESS_POINTERS
return Isolate::FromRoot(GetIsolateRoot(object.ptr())); return Isolate::FromRoot(GetIsolateRoot(address));
#else #else
return nullptr; return nullptr;
#endif // V8_COMPRESS_POINTERS #endif // V8_COMPRESS_POINTERS
} }
inline const Isolate* GetIsolateForPtrCompr(HeapObject object) {
return GetIsolateForPtrComprFromOnHeapAddress(object.ptr());
}
inline const Isolate* GetIsolateForPtrCompr(const Isolate* isolate) { inline const Isolate* GetIsolateForPtrCompr(const Isolate* isolate) {
#ifdef V8_COMPRESS_POINTERS #ifdef V8_COMPRESS_POINTERS
return isolate; return isolate;
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h" #include "src/deoptimizer/deoptimizer.h"
#include "src/execution/isolate-utils-inl.h"
#include "src/execution/microtask-queue.h" #include "src/execution/microtask-queue.h"
#include "src/execution/runtime-profiler.h" #include "src/execution/runtime-profiler.h"
#include "src/execution/v8threads.h" #include "src/execution/v8threads.h"
...@@ -1828,22 +1829,33 @@ void Heap::CopyRange(HeapObject dst_object, const TSlot dst_slot, ...@@ -1828,22 +1829,33 @@ void Heap::CopyRange(HeapObject dst_object, const TSlot dst_slot,
// Helper class for verifying the string table. // Helper class for verifying the string table.
class StringTableVerifier : public RootVisitor { class StringTableVerifier : public RootVisitor {
public: public:
explicit StringTableVerifier(Isolate* isolate) : isolate_(isolate) {}
void VisitRootPointers(Root root, const char* description, void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override { FullObjectSlot start, FullObjectSlot end) override {
UNREACHABLE();
}
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
// Visit all HeapObject pointers in [start, end). // Visit all HeapObject pointers in [start, end).
for (FullObjectSlot p = start; p < end; ++p) { for (OffHeapObjectSlot p = start; p < end; ++p) {
DCHECK(!HasWeakHeapObjectTag(*p)); Object o = p.load(isolate_);
if ((*p).IsHeapObject()) { DCHECK(!HasWeakHeapObjectTag(o));
HeapObject object = HeapObject::cast(*p); if (o.IsHeapObject()) {
HeapObject object = HeapObject::cast(o);
// Check that the string is actually internalized. // Check that the string is actually internalized.
CHECK(object.IsInternalizedString()); CHECK(object.IsInternalizedString());
} }
} }
} }
private:
Isolate* isolate_;
}; };
static void VerifyStringTable(Isolate* isolate) { static void VerifyStringTable(Isolate* isolate) {
StringTableVerifier verifier; StringTableVerifier verifier(isolate);
isolate->string_table()->IterateElements(&verifier); isolate->string_table()->IterateElements(&verifier);
} }
#endif // VERIFY_HEAP #endif // VERIFY_HEAP
...@@ -3068,6 +3080,14 @@ class LeftTrimmerVerifierRootVisitor : public RootVisitor { ...@@ -3068,6 +3080,14 @@ class LeftTrimmerVerifierRootVisitor : public RootVisitor {
} }
} }
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
DCHECK_EQ(root, Root::kStringTable);
// We can skip iterating the string table, it doesn't point to any fixed
// arrays.
}
private: private:
FixedArrayBase to_check_; FixedArrayBase to_check_;
...@@ -5942,6 +5962,11 @@ class UnreachableObjectsFilter : public HeapObjectsFilter { ...@@ -5942,6 +5962,11 @@ class UnreachableObjectsFilter : public HeapObjectsFilter {
FullObjectSlot start, FullObjectSlot end) override { FullObjectSlot start, FullObjectSlot end) override {
MarkPointersImpl(start, end); MarkPointersImpl(start, end);
} }
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
MarkPointersImpl(start, end);
}
void TransitiveClosure() { void TransitiveClosure() {
while (!marking_stack_.empty()) { while (!marking_stack_.empty()) {
...@@ -5959,8 +5984,9 @@ class UnreachableObjectsFilter : public HeapObjectsFilter { ...@@ -5959,8 +5984,9 @@ class UnreachableObjectsFilter : public HeapObjectsFilter {
template <typename TSlot> template <typename TSlot>
V8_INLINE void MarkPointersImpl(TSlot start, TSlot end) { V8_INLINE void MarkPointersImpl(TSlot start, TSlot end) {
// Treat weak references as strong. // Treat weak references as strong.
Isolate* isolate = filter_->heap_->isolate();
for (TSlot p = start; p < end; ++p) { for (TSlot p = start; p < end; ++p) {
typename TSlot::TObject object = *p; typename TSlot::TObject object = p.load(isolate);
HeapObject heap_object; HeapObject heap_object;
if (object.GetHeapObject(&heap_object)) { if (object.GetHeapObject(&heap_object)) {
MarkHeapObject(heap_object); MarkHeapObject(heap_object);
...@@ -6393,6 +6419,13 @@ void VerifyPointersVisitor::VisitRootPointers(Root root, ...@@ -6393,6 +6419,13 @@ void VerifyPointersVisitor::VisitRootPointers(Root root,
VerifyPointersImpl(start, end); VerifyPointersImpl(start, end);
} }
void VerifyPointersVisitor::VisitRootPointers(Root root,
const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) {
VerifyPointersImpl(start, end);
}
void VerifyPointersVisitor::VerifyHeapObjectImpl(HeapObject heap_object) { void VerifyPointersVisitor::VerifyHeapObjectImpl(HeapObject heap_object) {
CHECK(IsValidHeapObject(heap_, heap_object)); CHECK(IsValidHeapObject(heap_, heap_object));
CHECK(heap_object.map().IsMap()); CHECK(heap_object.map().IsMap());
...@@ -6400,8 +6433,9 @@ void VerifyPointersVisitor::VerifyHeapObjectImpl(HeapObject heap_object) { ...@@ -6400,8 +6433,9 @@ void VerifyPointersVisitor::VerifyHeapObjectImpl(HeapObject heap_object) {
template <typename TSlot> template <typename TSlot>
void VerifyPointersVisitor::VerifyPointersImpl(TSlot start, TSlot end) { void VerifyPointersVisitor::VerifyPointersImpl(TSlot start, TSlot end) {
Isolate* isolate = heap_->isolate();
for (TSlot slot = start; slot < end; ++slot) { for (TSlot slot = start; slot < end; ++slot) {
typename TSlot::TObject object = *slot; typename TSlot::TObject object = slot.load(isolate);
HeapObject heap_object; HeapObject heap_object;
if (object.GetHeapObject(&heap_object)) { if (object.GetHeapObject(&heap_object)) {
VerifyHeapObjectImpl(heap_object); VerifyHeapObjectImpl(heap_object);
......
...@@ -2460,6 +2460,9 @@ class VerifyPointersVisitor : public ObjectVisitor, public RootVisitor { ...@@ -2460,6 +2460,9 @@ class VerifyPointersVisitor : public ObjectVisitor, public RootVisitor {
void VisitRootPointers(Root root, const char* description, void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override; FullObjectSlot start, FullObjectSlot end) override;
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override;
protected: protected:
V8_INLINE void VerifyHeapObjectImpl(HeapObject heap_object); V8_INLINE void VerifyHeapObjectImpl(HeapObject heap_object);
......
This diff is collapsed.
...@@ -33,6 +33,11 @@ Object CompressedObjectSlot::operator*() const { ...@@ -33,6 +33,11 @@ Object CompressedObjectSlot::operator*() const {
return Object(DecompressTaggedAny(address(), value)); return Object(DecompressTaggedAny(address(), value));
} }
Object CompressedObjectSlot::load(const Isolate* isolate) const {
Tagged_t value = *location();
return Object(DecompressTaggedAny(isolate, value));
}
void CompressedObjectSlot::store(Object value) const { void CompressedObjectSlot::store(Object value) const {
*location() = CompressTagged(value.ptr()); *location() = CompressTagged(value.ptr());
} }
...@@ -47,6 +52,11 @@ Object CompressedObjectSlot::Relaxed_Load() const { ...@@ -47,6 +52,11 @@ Object CompressedObjectSlot::Relaxed_Load() const {
return Object(DecompressTaggedAny(address(), value)); return Object(DecompressTaggedAny(address(), value));
} }
Object CompressedObjectSlot::Relaxed_Load(const Isolate* isolate) const {
AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location());
return Object(DecompressTaggedAny(isolate, value));
}
void CompressedObjectSlot::Relaxed_Store(Object value) const { void CompressedObjectSlot::Relaxed_Store(Object value) const {
Tagged_t ptr = CompressTagged(value.ptr()); Tagged_t ptr = CompressTagged(value.ptr());
AsAtomicTagged::Relaxed_Store(location(), ptr); AsAtomicTagged::Relaxed_Store(location(), ptr);
...@@ -75,6 +85,11 @@ MaybeObject CompressedMaybeObjectSlot::operator*() const { ...@@ -75,6 +85,11 @@ MaybeObject CompressedMaybeObjectSlot::operator*() const {
return MaybeObject(DecompressTaggedAny(address(), value)); return MaybeObject(DecompressTaggedAny(address(), value));
} }
MaybeObject CompressedMaybeObjectSlot::load(const Isolate* isolate) const {
Tagged_t value = *location();
return MaybeObject(DecompressTaggedAny(isolate, value));
}
void CompressedMaybeObjectSlot::store(MaybeObject value) const { void CompressedMaybeObjectSlot::store(MaybeObject value) const {
*location() = CompressTagged(value.ptr()); *location() = CompressTagged(value.ptr());
} }
...@@ -84,6 +99,12 @@ MaybeObject CompressedMaybeObjectSlot::Relaxed_Load() const { ...@@ -84,6 +99,12 @@ MaybeObject CompressedMaybeObjectSlot::Relaxed_Load() const {
return MaybeObject(DecompressTaggedAny(address(), value)); return MaybeObject(DecompressTaggedAny(address(), value));
} }
MaybeObject CompressedMaybeObjectSlot::Relaxed_Load(
const Isolate* isolate) const {
AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location());
return MaybeObject(DecompressTaggedAny(isolate, value));
}
void CompressedMaybeObjectSlot::Relaxed_Store(MaybeObject value) const { void CompressedMaybeObjectSlot::Relaxed_Store(MaybeObject value) const {
Tagged_t ptr = CompressTagged(value.ptr()); Tagged_t ptr = CompressTagged(value.ptr());
AsAtomicTagged::Relaxed_Store(location(), ptr); AsAtomicTagged::Relaxed_Store(location(), ptr);
...@@ -105,6 +126,12 @@ HeapObjectReference CompressedHeapObjectSlot::operator*() const { ...@@ -105,6 +126,12 @@ HeapObjectReference CompressedHeapObjectSlot::operator*() const {
return HeapObjectReference(DecompressTaggedPointer(address(), value)); return HeapObjectReference(DecompressTaggedPointer(address(), value));
} }
HeapObjectReference CompressedHeapObjectSlot::load(
const Isolate* isolate) const {
Tagged_t value = *location();
return HeapObjectReference(DecompressTaggedPointer(isolate, value));
}
void CompressedHeapObjectSlot::store(HeapObjectReference value) const { void CompressedHeapObjectSlot::store(HeapObjectReference value) const {
*location() = CompressTagged(value.ptr()); *location() = CompressTagged(value.ptr());
} }
...@@ -119,6 +146,36 @@ void CompressedHeapObjectSlot::StoreHeapObject(HeapObject value) const { ...@@ -119,6 +146,36 @@ void CompressedHeapObjectSlot::StoreHeapObject(HeapObject value) const {
*location() = CompressTagged(value.ptr()); *location() = CompressTagged(value.ptr());
} }
//
// OffHeapCompressedObjectSlot implementation.
//
Object OffHeapCompressedObjectSlot::load(const Isolate* isolate) const {
Tagged_t value = *location();
return Object(DecompressTaggedAny(isolate, value));
}
void OffHeapCompressedObjectSlot::store(Object value) const {
*location() = CompressTagged(value.ptr());
}
Object OffHeapCompressedObjectSlot::Relaxed_Load(const Isolate* isolate) const {
AtomicTagged_t value = AsAtomicTagged::Relaxed_Load(location());
return Object(DecompressTaggedAny(isolate, value));
}
void OffHeapCompressedObjectSlot::Relaxed_Store(Object value) const {
Tagged_t ptr = CompressTagged(value.ptr());
AsAtomicTagged::Relaxed_Store(location(), ptr);
}
void OffHeapCompressedObjectSlot::Release_CompareAndSwap(Object old,
Object target) const {
Tagged_t old_ptr = CompressTagged(old.ptr());
Tagged_t target_ptr = CompressTagged(target.ptr());
AsAtomicTagged::Release_CompareAndSwap(location(), old_ptr, target_ptr);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -38,11 +38,15 @@ class CompressedObjectSlot : public SlotBase<CompressedObjectSlot, Tagged_t> { ...@@ -38,11 +38,15 @@ class CompressedObjectSlot : public SlotBase<CompressedObjectSlot, Tagged_t> {
// raw value without decompression. // raw value without decompression.
inline bool contains_value(Address raw_value) const; inline bool contains_value(Address raw_value) const;
// TODO(leszeks): Consider deprecating the operator* load, and always pass the
// Isolate.
inline Object operator*() const; inline Object operator*() const;
inline Object load(const Isolate* isolate) const;
inline void store(Object value) const; inline void store(Object value) const;
inline Object Acquire_Load() const; inline Object Acquire_Load() const;
inline Object Relaxed_Load() const; inline Object Relaxed_Load() const;
inline Object Relaxed_Load(const Isolate* isolate) const;
inline void Relaxed_Store(Object value) const; inline void Relaxed_Store(Object value) const;
inline void Release_Store(Object value) const; inline void Release_Store(Object value) const;
inline Object Release_CompareAndSwap(Object old, Object target) const; inline Object Release_CompareAndSwap(Object old, Object target) const;
...@@ -73,9 +77,11 @@ class CompressedMaybeObjectSlot ...@@ -73,9 +77,11 @@ class CompressedMaybeObjectSlot
: SlotBase(slot.address()) {} : SlotBase(slot.address()) {}
inline MaybeObject operator*() const; inline MaybeObject operator*() const;
inline MaybeObject load(const Isolate* isolate) const;
inline void store(MaybeObject value) const; inline void store(MaybeObject value) const;
inline MaybeObject Relaxed_Load() const; inline MaybeObject Relaxed_Load() const;
inline MaybeObject Relaxed_Load(const Isolate* isolate) const;
inline void Relaxed_Store(MaybeObject value) const; inline void Relaxed_Store(MaybeObject value) const;
inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const; inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const;
}; };
...@@ -99,6 +105,7 @@ class CompressedHeapObjectSlot ...@@ -99,6 +105,7 @@ class CompressedHeapObjectSlot
: SlotBase(slot.address()) {} : SlotBase(slot.address()) {}
inline HeapObjectReference operator*() const; inline HeapObjectReference operator*() const;
inline HeapObjectReference load(const Isolate* isolate) const;
inline void store(HeapObjectReference value) const; inline void store(HeapObjectReference value) const;
inline HeapObject ToHeapObject() const; inline HeapObject ToHeapObject() const;
...@@ -106,6 +113,32 @@ class CompressedHeapObjectSlot ...@@ -106,6 +113,32 @@ class CompressedHeapObjectSlot
inline void StoreHeapObject(HeapObject value) const; inline void StoreHeapObject(HeapObject value) const;
}; };
// An OffHeapCompressedObjectSlot instance describes a kTaggedSize-sized field
// ("slot") holding a compressed tagged pointer (smi or heap object).
// Unlike CompressedObjectSlot, it does not assume that the slot is on the heap,
// and so does not provide an operator* with implicit Isolate* calculation.
// Its address() is the address of the slot.
// The slot's contents can be read and written using load() and store().
class OffHeapCompressedObjectSlot
: public SlotBase<OffHeapCompressedObjectSlot, Tagged_t> {
public:
using TObject = Object;
using THeapObjectSlot = OffHeapCompressedObjectSlot;
static constexpr bool kCanBeWeak = false;
OffHeapCompressedObjectSlot() : SlotBase(kNullAddress) {}
explicit OffHeapCompressedObjectSlot(const uint32_t* ptr)
: SlotBase(reinterpret_cast<Address>(ptr)) {}
inline Object load(const Isolate* isolate) const;
inline void store(Object value) const;
inline Object Relaxed_Load(const Isolate* isolate) const;
inline void Relaxed_Store(Object value) const;
inline void Release_CompareAndSwap(Object old, Object target) const;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
#ifndef V8_OBJECTS_SLOTS_INL_H_ #ifndef V8_OBJECTS_SLOTS_INL_H_
#define V8_OBJECTS_SLOTS_INL_H_ #define V8_OBJECTS_SLOTS_INL_H_
#include "src/objects/slots.h"
#include "src/base/atomic-utils.h" #include "src/base/atomic-utils.h"
#include "src/common/globals.h"
#include "src/common/ptr-compr-inl.h" #include "src/common/ptr-compr-inl.h"
#include "src/objects/compressed-slots.h" #include "src/objects/compressed-slots.h"
#include "src/objects/heap-object.h" #include "src/objects/heap-object.h"
#include "src/objects/maybe-object.h" #include "src/objects/maybe-object.h"
#include "src/objects/objects.h" #include "src/objects/objects.h"
#include "src/objects/slots.h"
#include "src/utils/memcopy.h" #include "src/utils/memcopy.h"
namespace v8 { namespace v8 {
...@@ -29,7 +29,9 @@ bool FullObjectSlot::contains_value(Address raw_value) const { ...@@ -29,7 +29,9 @@ bool FullObjectSlot::contains_value(Address raw_value) const {
return base::AsAtomicPointer::Relaxed_Load(location()) == raw_value; return base::AsAtomicPointer::Relaxed_Load(location()) == raw_value;
} }
const Object FullObjectSlot::operator*() const { return Object(*location()); } Object FullObjectSlot::operator*() const { return Object(*location()); }
Object FullObjectSlot::load(const Isolate* isolate) const { return **this; }
void FullObjectSlot::store(Object value) const { *location() = value.ptr(); } void FullObjectSlot::store(Object value) const { *location() = value.ptr(); }
...@@ -41,6 +43,10 @@ Object FullObjectSlot::Relaxed_Load() const { ...@@ -41,6 +43,10 @@ Object FullObjectSlot::Relaxed_Load() const {
return Object(base::AsAtomicPointer::Relaxed_Load(location())); return Object(base::AsAtomicPointer::Relaxed_Load(location()));
} }
Object FullObjectSlot::Relaxed_Load(const Isolate* isolate) const {
return Relaxed_Load();
}
void FullObjectSlot::Relaxed_Store(Object value) const { void FullObjectSlot::Relaxed_Store(Object value) const {
base::AsAtomicPointer::Relaxed_Store(location(), value.ptr()); base::AsAtomicPointer::Relaxed_Store(location(), value.ptr());
} }
...@@ -65,10 +71,14 @@ Object FullObjectSlot::Release_CompareAndSwap(Object old, Object target) const { ...@@ -65,10 +71,14 @@ Object FullObjectSlot::Release_CompareAndSwap(Object old, Object target) const {
// FullMaybeObjectSlot implementation. // FullMaybeObjectSlot implementation.
// //
const MaybeObject FullMaybeObjectSlot::operator*() const { MaybeObject FullMaybeObjectSlot::operator*() const {
return MaybeObject(*location()); return MaybeObject(*location());
} }
MaybeObject FullMaybeObjectSlot::load(const Isolate* isolate) const {
return **this;
}
void FullMaybeObjectSlot::store(MaybeObject value) const { void FullMaybeObjectSlot::store(MaybeObject value) const {
*location() = value.ptr(); *location() = value.ptr();
} }
...@@ -77,6 +87,10 @@ MaybeObject FullMaybeObjectSlot::Relaxed_Load() const { ...@@ -77,6 +87,10 @@ MaybeObject FullMaybeObjectSlot::Relaxed_Load() const {
return MaybeObject(base::AsAtomicPointer::Relaxed_Load(location())); return MaybeObject(base::AsAtomicPointer::Relaxed_Load(location()));
} }
MaybeObject FullMaybeObjectSlot::Relaxed_Load(const Isolate* isolate) const {
return Relaxed_Load();
}
void FullMaybeObjectSlot::Relaxed_Store(MaybeObject value) const { void FullMaybeObjectSlot::Relaxed_Store(MaybeObject value) const {
base::AsAtomicPointer::Relaxed_Store(location(), value->ptr()); base::AsAtomicPointer::Relaxed_Store(location(), value->ptr());
} }
...@@ -91,10 +105,14 @@ void FullMaybeObjectSlot::Release_CompareAndSwap(MaybeObject old, ...@@ -91,10 +105,14 @@ void FullMaybeObjectSlot::Release_CompareAndSwap(MaybeObject old,
// FullHeapObjectSlot implementation. // FullHeapObjectSlot implementation.
// //
const HeapObjectReference FullHeapObjectSlot::operator*() const { HeapObjectReference FullHeapObjectSlot::operator*() const {
return HeapObjectReference(*location()); return HeapObjectReference(*location());
} }
HeapObjectReference FullHeapObjectSlot::load(const Isolate* isolate) const {
return **this;
}
void FullHeapObjectSlot::store(HeapObjectReference value) const { void FullHeapObjectSlot::store(HeapObjectReference value) const {
*location() = value.ptr(); *location() = value.ptr();
} }
...@@ -121,17 +139,23 @@ inline void CopyTagged(Address dst, const Address src, size_t num_tagged) { ...@@ -121,17 +139,23 @@ inline void CopyTagged(Address dst, const Address src, size_t num_tagged) {
} }
// Sets |counter| number of kTaggedSize-sized values starting at |start| slot. // Sets |counter| number of kTaggedSize-sized values starting at |start| slot.
inline void MemsetTagged(ObjectSlot start, Object value, size_t counter) { inline void MemsetTagged(Tagged_t* start, Object value, size_t counter) {
#ifdef V8_COMPRESS_POINTERS #ifdef V8_COMPRESS_POINTERS
Tagged_t raw_value = CompressTagged(value.ptr()); Tagged_t raw_value = CompressTagged(value.ptr());
STATIC_ASSERT(kTaggedSize == kInt32Size); MemsetUint32(start, raw_value, counter);
MemsetInt32(reinterpret_cast<int32_t*>(start.location()), raw_value, counter);
#else #else
Address raw_value = value.ptr(); Address raw_value = value.ptr();
MemsetPointer(start.location(), raw_value, counter); MemsetPointer(start, raw_value, counter);
#endif #endif
} }
// Sets |counter| number of kTaggedSize-sized values starting at |start| slot.
template <typename T>
inline void MemsetTagged(SlotBase<T, Tagged_t> start, Object value,
size_t counter) {
MemsetTagged(start.location(), value, counter);
}
// Sets |counter| number of kSystemPointerSize-sized values starting at |start| // Sets |counter| number of kSystemPointerSize-sized values starting at |start|
// slot. // slot.
inline void MemsetPointer(FullObjectSlot start, Object value, size_t counter) { inline void MemsetPointer(FullObjectSlot start, Object value, size_t counter) {
......
...@@ -109,11 +109,13 @@ class FullObjectSlot : public SlotBase<FullObjectSlot, Address> { ...@@ -109,11 +109,13 @@ class FullObjectSlot : public SlotBase<FullObjectSlot, Address> {
// raw value. // raw value.
inline bool contains_value(Address raw_value) const; inline bool contains_value(Address raw_value) const;
inline const Object operator*() const; inline Object operator*() const;
inline Object load(const Isolate* isolate) const;
inline void store(Object value) const; inline void store(Object value) const;
inline Object Acquire_Load() const; inline Object Acquire_Load() const;
inline Object Relaxed_Load() const; inline Object Relaxed_Load() const;
inline Object Relaxed_Load(const Isolate* isolate) const;
inline void Relaxed_Store(Object value) const; inline void Relaxed_Store(Object value) const;
inline void Release_Store(Object value) const; inline void Release_Store(Object value) const;
inline Object Relaxed_CompareAndSwap(Object old, Object target) const; inline Object Relaxed_CompareAndSwap(Object old, Object target) const;
...@@ -143,10 +145,12 @@ class FullMaybeObjectSlot ...@@ -143,10 +145,12 @@ class FullMaybeObjectSlot
explicit FullMaybeObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) explicit FullMaybeObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot)
: SlotBase(slot.address()) {} : SlotBase(slot.address()) {}
inline const MaybeObject operator*() const; inline MaybeObject operator*() const;
inline MaybeObject load(const Isolate* isolate) const;
inline void store(MaybeObject value) const; inline void store(MaybeObject value) const;
inline MaybeObject Relaxed_Load() const; inline MaybeObject Relaxed_Load() const;
inline MaybeObject Relaxed_Load(const Isolate* isolate) const;
inline void Relaxed_Store(MaybeObject value) const; inline void Relaxed_Store(MaybeObject value) const;
inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const; inline void Release_CompareAndSwap(MaybeObject old, MaybeObject target) const;
}; };
...@@ -168,7 +172,8 @@ class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> { ...@@ -168,7 +172,8 @@ class FullHeapObjectSlot : public SlotBase<FullHeapObjectSlot, Address> {
explicit FullHeapObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot) explicit FullHeapObjectSlot(SlotBase<T, TData, kSlotDataAlignment> slot)
: SlotBase(slot.address()) {} : SlotBase(slot.address()) {}
inline const HeapObjectReference operator*() const; inline HeapObjectReference operator*() const;
inline HeapObjectReference load(const Isolate* isolate) const;
inline void store(HeapObjectReference value) const; inline void store(HeapObjectReference value) const;
inline HeapObject ToHeapObject() const; inline HeapObject ToHeapObject() const;
...@@ -254,6 +259,19 @@ class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> { ...@@ -254,6 +259,19 @@ class UnalignedSlot : public SlotBase<UnalignedSlot<T>, T, 1> {
} }
}; };
// An off-heap uncompressed object slot can be the same as an on-heap one, with
// a few methods deleted.
class OffHeapFullObjectSlot : public FullObjectSlot {
public:
OffHeapFullObjectSlot() : FullObjectSlot() {}
explicit OffHeapFullObjectSlot(const Address* ptr) : FullObjectSlot(ptr) {}
inline Object operator*() const = delete;
using FullObjectSlot::Relaxed_Load;
inline Object Relaxed_Load() const = delete;
};
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
This diff is collapsed.
...@@ -74,7 +74,7 @@ class V8_EXPORT_PRIVATE StringTable { ...@@ -74,7 +74,7 @@ class V8_EXPORT_PRIVATE StringTable {
static Address TryStringToIndexOrLookupExisting(Isolate* isolate, static Address TryStringToIndexOrLookupExisting(Isolate* isolate,
Address raw_string); Address raw_string);
void Print() const; void Print(const Isolate* isolate) const;
size_t GetCurrentMemoryUsage() const; size_t GetCurrentMemoryUsage() const;
// The following methods must be called either while holding the write lock, // The following methods must be called either while holding the write lock,
...@@ -84,7 +84,7 @@ class V8_EXPORT_PRIVATE StringTable { ...@@ -84,7 +84,7 @@ class V8_EXPORT_PRIVATE StringTable {
void NotifyElementsRemoved(int count); void NotifyElementsRemoved(int count);
private: private:
void EnsureCapacity(int additional_elements); void EnsureCapacity(const Isolate* isolate, int additional_elements);
class Data; class Data;
std::unique_ptr<Data> data_; std::unique_ptr<Data> data_;
......
...@@ -72,6 +72,20 @@ class RootVisitor { ...@@ -72,6 +72,20 @@ class RootVisitor {
VisitRootPointers(root, description, p, p + 1); VisitRootPointers(root, description, p, p + 1);
} }
// Visits a contiguous arrays of off-heap pointers in the half-open range
// [start, end). Any or all of the values may be modified on return.
virtual void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) {
// This should be implemented for any visitor that visits the string table.
// If we ever add new off-heap data-structures that we want to walk as roots
// using this function, we should make it generic, by
//
// 1) Making this function pure virtual, and
// 2) Implementing it for all visitors.
UNREACHABLE();
}
// Intended for serialization/deserialization checking: insert, or // Intended for serialization/deserialization checking: insert, or
// check for the presence of, a tag at this position in the stream. // check for the presence of, a tag at this position in the stream.
// Also used for marking up GC roots in heap snapshots. // Also used for marking up GC roots in heap snapshots.
......
...@@ -1468,6 +1468,17 @@ class RootsReferencesExtractor : public RootVisitor { ...@@ -1468,6 +1468,17 @@ class RootsReferencesExtractor : public RootVisitor {
} }
} }
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
DCHECK_EQ(root, Root::kStringTable);
const Isolate* isolate = Isolate::FromHeap(explorer_->heap_);
for (OffHeapObjectSlot p = start; p < end; ++p) {
explorer_->SetGcSubrootReference(root, description, visiting_weak_roots_,
p.load(isolate));
}
}
private: private:
V8HeapExplorer* explorer_; V8HeapExplorer* explorer_;
bool visiting_weak_roots_; bool visiting_weak_roots_;
...@@ -1766,22 +1777,38 @@ void V8HeapExplorer::TagObject(Object obj, const char* tag) { ...@@ -1766,22 +1777,38 @@ void V8HeapExplorer::TagObject(Object obj, const char* tag) {
class GlobalObjectsEnumerator : public RootVisitor { class GlobalObjectsEnumerator : public RootVisitor {
public: public:
explicit GlobalObjectsEnumerator(Isolate* isolate) : isolate_(isolate) {}
void VisitRootPointers(Root root, const char* description, void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override { FullObjectSlot start, FullObjectSlot end) override {
for (FullObjectSlot p = start; p < end; ++p) { VisitRootPointersImpl(root, description, start, end);
if (!(*p).IsNativeContext()) continue;
JSObject proxy = Context::cast(*p).global_proxy();
if (!proxy.IsJSGlobalProxy()) continue;
Object global = proxy.map().prototype();
if (!global.IsJSGlobalObject()) continue;
objects_.push_back(Handle<JSGlobalObject>(JSGlobalObject::cast(global),
proxy.GetIsolate()));
} }
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
VisitRootPointersImpl(root, description, start, end);
} }
int count() const { return static_cast<int>(objects_.size()); } int count() const { return static_cast<int>(objects_.size()); }
Handle<JSGlobalObject>& at(int i) { return objects_[i]; } Handle<JSGlobalObject>& at(int i) { return objects_[i]; }
private: private:
template <typename TSlot>
void VisitRootPointersImpl(Root root, const char* description, TSlot start,
TSlot end) {
for (TSlot p = start; p < end; ++p) {
Object o = p.load(isolate_);
if (!o.IsNativeContext(isolate_)) continue;
JSObject proxy = Context::cast(o).global_proxy();
if (!proxy.IsJSGlobalProxy(isolate_)) continue;
Object global = proxy.map(isolate_).prototype(isolate_);
if (!global.IsJSGlobalObject(isolate_)) continue;
objects_.push_back(handle(JSGlobalObject::cast(global), isolate_));
}
}
Isolate* isolate_;
std::vector<Handle<JSGlobalObject>> objects_; std::vector<Handle<JSGlobalObject>> objects_;
}; };
...@@ -1790,7 +1817,7 @@ class GlobalObjectsEnumerator : public RootVisitor { ...@@ -1790,7 +1817,7 @@ class GlobalObjectsEnumerator : public RootVisitor {
void V8HeapExplorer::TagGlobalObjects() { void V8HeapExplorer::TagGlobalObjects() {
Isolate* isolate = Isolate::FromHeap(heap_); Isolate* isolate = Isolate::FromHeap(heap_);
HandleScope scope(isolate); HandleScope scope(isolate);
GlobalObjectsEnumerator enumerator; GlobalObjectsEnumerator enumerator(isolate);
isolate->global_handles()->IterateAllRoots(&enumerator); isolate->global_handles()->IterateAllRoots(&enumerator);
std::vector<const char*> urls(enumerator.count()); std::vector<const char*> urls(enumerator.count());
for (int i = 0, l = enumerator.count(); i < l; ++i) { for (int i = 0, l = enumerator.count(); i < l; ++i) {
......
...@@ -213,9 +213,16 @@ void StartupSerializer::SerializeStringTable(StringTable* string_table) { ...@@ -213,9 +213,16 @@ void StartupSerializer::SerializeStringTable(StringTable* string_table) {
void VisitRootPointers(Root root, const char* description, void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override { FullObjectSlot start, FullObjectSlot end) override {
UNREACHABLE();
}
void VisitRootPointers(Root root, const char* description,
OffHeapObjectSlot start,
OffHeapObjectSlot end) override {
DCHECK_EQ(root, Root::kStringTable); DCHECK_EQ(root, Root::kStringTable);
for (FullObjectSlot current = start; current < end; ++current) { Isolate* isolate = serializer_->isolate();
Object obj = *current; for (OffHeapObjectSlot current = start; current < end; ++current) {
Object obj = current.load(isolate);
if (obj.IsHeapObject()) { if (obj.IsHeapObject()) {
DCHECK(obj.IsInternalizedString()); DCHECK(obj.IsInternalizedString());
serializer_->SerializeObject(HeapObject::cast(obj)); serializer_->SerializeObject(HeapObject::cast(obj));
......
...@@ -187,7 +187,7 @@ inline void CopyBytes(T* dst, const T* src, size_t num_bytes) { ...@@ -187,7 +187,7 @@ inline void CopyBytes(T* dst, const T* src, size_t num_bytes) {
CopyImpl<kMinComplexMemCopy>(dst, src, num_bytes); CopyImpl<kMinComplexMemCopy>(dst, src, num_bytes);
} }
inline void MemsetInt32(int32_t* dest, int32_t value, size_t counter) { inline void MemsetUint32(uint32_t* dest, uint32_t value, size_t counter) {
#if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64 #if V8_HOST_ARCH_IA32 || V8_HOST_ARCH_X64
#define STOS "stosl" #define STOS "stosl"
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment