Commit 41a5a247 authored by Igor Sheludko's avatar Igor Sheludko Committed by V8 LUCI CQ

[ext-code-space] Introduce MapWord::ToForwardingAddress(...)

... capable of computing the forwarding pointer for objects allocated
outside of the main pointer compression cage.

Drive-by: hoist computation of pointer compression cage base out of
certain loops in GC code.

Bug: v8:11880
Change-Id: I23efdffd1a237d9eedd0e2975e8e40811417ef31
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3204968Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77244}
parent d78d8b7d
...@@ -978,10 +978,11 @@ size_t Heap::UsedGlobalHandlesSize() { ...@@ -978,10 +978,11 @@ size_t Heap::UsedGlobalHandlesSize() {
void Heap::MergeAllocationSitePretenuringFeedback( void Heap::MergeAllocationSitePretenuringFeedback(
const PretenuringFeedbackMap& local_pretenuring_feedback) { const PretenuringFeedbackMap& local_pretenuring_feedback) {
PtrComprCageBase cage_base(isolate());
AllocationSite site; AllocationSite site;
for (auto& site_and_count : local_pretenuring_feedback) { for (auto& site_and_count : local_pretenuring_feedback) {
site = site_and_count.first; site = site_and_count.first;
MapWord map_word = site_and_count.first.map_word(kRelaxedLoad); MapWord map_word = site.map_word(cage_base, kRelaxedLoad);
if (map_word.IsForwardingAddress()) { if (map_word.IsForwardingAddress()) {
site = AllocationSite::cast(map_word.ToForwardingAddress()); site = AllocationSite::cast(map_word.ToForwardingAddress());
} }
...@@ -2731,8 +2732,9 @@ void Heap::UpdateExternalString(String string, size_t old_payload, ...@@ -2731,8 +2732,9 @@ void Heap::UpdateExternalString(String string, size_t old_payload,
String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap, String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
FullObjectSlot p) { FullObjectSlot p) {
PtrComprCageBase cage_base(heap->isolate());
HeapObject obj = HeapObject::cast(*p); HeapObject obj = HeapObject::cast(*p);
MapWord first_word = obj.map_word(kRelaxedLoad); MapWord first_word = obj.map_word(cage_base, kRelaxedLoad);
String new_string; String new_string;
...@@ -2740,9 +2742,9 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap, ...@@ -2740,9 +2742,9 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
if (!first_word.IsForwardingAddress()) { if (!first_word.IsForwardingAddress()) {
// Unreachable external string can be finalized. // Unreachable external string can be finalized.
String string = String::cast(obj); String string = String::cast(obj);
if (!string.IsExternalString()) { if (!string.IsExternalString(cage_base)) {
// Original external string has been internalized. // Original external string has been internalized.
DCHECK(string.IsThinString()); DCHECK(string.IsThinString(cage_base));
return String(); return String();
} }
heap->FinalizeExternalString(string); heap->FinalizeExternalString(string);
...@@ -2754,10 +2756,10 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap, ...@@ -2754,10 +2756,10 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
} }
// String is still reachable. // String is still reachable.
if (new_string.IsThinString()) { if (new_string.IsThinString(cage_base)) {
// Filtering Thin strings out of the external string table. // Filtering Thin strings out of the external string table.
return String(); return String();
} else if (new_string.IsExternalString()) { } else if (new_string.IsExternalString(cage_base)) {
MemoryChunk::MoveExternalBackingStoreBytes( MemoryChunk::MoveExternalBackingStoreBytes(
ExternalBackingStoreType::kExternalString, ExternalBackingStoreType::kExternalString,
Page::FromAddress((*p).ptr()), Page::FromHeapObject(new_string), Page::FromAddress((*p).ptr()), Page::FromHeapObject(new_string),
...@@ -2766,7 +2768,7 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap, ...@@ -2766,7 +2768,7 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
} }
// Internalization can replace external strings with non-external strings. // Internalization can replace external strings with non-external strings.
return new_string.IsExternalString() ? new_string : String(); return new_string.IsExternalString(cage_base) ? new_string : String();
} }
void Heap::ExternalStringTable::VerifyYoung() { void Heap::ExternalStringTable::VerifyYoung() {
...@@ -6995,9 +6997,17 @@ void Heap::CreateObjectStats() { ...@@ -6995,9 +6997,17 @@ void Heap::CreateObjectStats() {
} }
Map Heap::GcSafeMapOfCodeSpaceObject(HeapObject object) { Map Heap::GcSafeMapOfCodeSpaceObject(HeapObject object) {
MapWord map_word = object.map_word(kRelaxedLoad); PtrComprCageBase cage_base(isolate());
return map_word.IsForwardingAddress() ? map_word.ToForwardingAddress().map() MapWord map_word = object.map_word(cage_base, kRelaxedLoad);
: map_word.ToMap(); if (map_word.IsForwardingAddress()) {
#if V8_EXTERNAL_CODE_SPACE
PtrComprCageBase code_cage_base(isolate()->code_cage_base());
#else
PtrComprCageBase code_cage_base = cage_base;
#endif
return map_word.ToForwardingAddress(code_cage_base).map(cage_base);
}
return map_word.ToMap();
} }
Code Heap::GcSafeCastToCode(HeapObject object, Address inner_pointer) { Code Heap::GcSafeCastToCode(HeapObject object, Address inner_pointer) {
......
...@@ -354,6 +354,7 @@ void LargeObjectSpace::Verify(Isolate* isolate) { ...@@ -354,6 +354,7 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
external_backing_store_bytes[static_cast<ExternalBackingStoreType>(i)] = 0; external_backing_store_bytes[static_cast<ExternalBackingStoreType>(i)] = 0;
} }
PtrComprCageBase cage_base(isolate);
for (LargePage* chunk = first_page(); chunk != nullptr; for (LargePage* chunk = first_page(); chunk != nullptr;
chunk = chunk->next_page()) { chunk = chunk->next_page()) {
// Each chunk contains an object that starts at the large object page's // Each chunk contains an object that starts at the large object page's
...@@ -364,23 +365,26 @@ void LargeObjectSpace::Verify(Isolate* isolate) { ...@@ -364,23 +365,26 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
// The first word should be a map, and we expect all map pointers to be // The first word should be a map, and we expect all map pointers to be
// in map space or read-only space. // in map space or read-only space.
Map map = object.map(); Map map = object.map(cage_base);
CHECK(map.IsMap()); CHECK(map.IsMap(cage_base));
CHECK(ReadOnlyHeap::Contains(map) || heap()->map_space()->Contains(map)); CHECK(ReadOnlyHeap::Contains(map) || heap()->map_space()->Contains(map));
// We have only the following types in the large object space: // We have only the following types in the large object space:
if (!(object.IsAbstractCode() || object.IsSeqString() || if (!(object.IsAbstractCode(cage_base) || object.IsSeqString(cage_base) ||
object.IsExternalString() || object.IsThinString() || object.IsExternalString(cage_base) ||
object.IsFixedArray() || object.IsFixedDoubleArray() || object.IsThinString(cage_base) || object.IsFixedArray(cage_base) ||
object.IsWeakFixedArray() || object.IsWeakArrayList() || object.IsFixedDoubleArray(cage_base) ||
object.IsPropertyArray() || object.IsByteArray() || object.IsWeakFixedArray(cage_base) ||
object.IsFeedbackVector() || object.IsBigInt() || object.IsWeakArrayList(cage_base) ||
object.IsFreeSpace() || object.IsFeedbackMetadata() || object.IsPropertyArray(cage_base) || object.IsByteArray(cage_base) ||
object.IsContext() || object.IsUncompiledDataWithoutPreparseData() || object.IsFeedbackVector(cage_base) || object.IsBigInt(cage_base) ||
object.IsPreparseData()) && object.IsFreeSpace(cage_base) ||
object.IsFeedbackMetadata(cage_base) || object.IsContext(cage_base) ||
object.IsUncompiledDataWithoutPreparseData(cage_base) ||
object.IsPreparseData(cage_base)) &&
!FLAG_young_generation_large_objects) { !FLAG_young_generation_large_objects) {
FATAL("Found invalid Object (instance_type=%i) in large object space.", FATAL("Found invalid Object (instance_type=%i) in large object space.",
object.map().instance_type()); object.map(cage_base).instance_type());
} }
// The object itself should look OK. // The object itself should look OK.
...@@ -391,27 +395,27 @@ void LargeObjectSpace::Verify(Isolate* isolate) { ...@@ -391,27 +395,27 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
} }
// Byte arrays and strings don't have interior pointers. // Byte arrays and strings don't have interior pointers.
if (object.IsAbstractCode()) { if (object.IsAbstractCode(cage_base)) {
VerifyPointersVisitor code_visitor(heap()); VerifyPointersVisitor code_visitor(heap());
object.IterateBody(map, object.Size(), &code_visitor); object.IterateBody(map, object.Size(), &code_visitor);
} else if (object.IsFixedArray()) { } else if (object.IsFixedArray(cage_base)) {
FixedArray array = FixedArray::cast(object); FixedArray array = FixedArray::cast(object);
for (int j = 0; j < array.length(); j++) { for (int j = 0; j < array.length(); j++) {
Object element = array.get(j); Object element = array.get(j);
if (element.IsHeapObject()) { if (element.IsHeapObject()) {
HeapObject element_object = HeapObject::cast(element); HeapObject element_object = HeapObject::cast(element);
CHECK(IsValidHeapObject(heap(), element_object)); CHECK(IsValidHeapObject(heap(), element_object));
CHECK(element_object.map().IsMap()); CHECK(element_object.map(cage_base).IsMap(cage_base));
} }
} }
} else if (object.IsPropertyArray()) { } else if (object.IsPropertyArray(cage_base)) {
PropertyArray array = PropertyArray::cast(object); PropertyArray array = PropertyArray::cast(object);
for (int j = 0; j < array.length(); j++) { for (int j = 0; j < array.length(); j++) {
Object property = array.get(j); Object property = array.get(j);
if (property.IsHeapObject()) { if (property.IsHeapObject()) {
HeapObject property_object = HeapObject::cast(property); HeapObject property_object = HeapObject::cast(property);
CHECK(heap()->Contains(property_object)); CHECK(heap()->Contains(property_object));
CHECK(property_object.map().IsMap()); CHECK(property_object.map(cage_base).IsMap(cage_base));
} }
} }
} }
......
...@@ -163,6 +163,7 @@ operator++(int) { ...@@ -163,6 +163,7 @@ operator++(int) {
template <LiveObjectIterationMode mode> template <LiveObjectIterationMode mode>
void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() { void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
PtrComprCageBase cage_base(chunk_->heap()->isolate());
while (!it_.Done()) { while (!it_.Done()) {
HeapObject object; HeapObject object;
int size = 0; int size = 0;
...@@ -198,10 +199,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() { ...@@ -198,10 +199,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
// make sure that we skip all set bits in the black area until the // make sure that we skip all set bits in the black area until the
// object ends. // object ends.
HeapObject black_object = HeapObject::FromAddress(addr); HeapObject black_object = HeapObject::FromAddress(addr);
Object map_object = black_object.map(kAcquireLoad); Object map_object = black_object.map(cage_base, kAcquireLoad);
CHECK(map_object.IsMap()); CHECK(map_object.IsMap(cage_base));
map = Map::cast(map_object); map = Map::cast(map_object);
DCHECK(map.IsMap()); DCHECK(map.IsMap(cage_base));
size = black_object.SizeFromMap(map); size = black_object.SizeFromMap(map);
CHECK_LE(addr + size, chunk_->area_end()); CHECK_LE(addr + size, chunk_->area_end());
Address end = addr + size - kTaggedSize; Address end = addr + size - kTaggedSize;
...@@ -230,10 +231,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() { ...@@ -230,10 +231,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
} }
} else if ((mode == kGreyObjects || mode == kAllLiveObjects)) { } else if ((mode == kGreyObjects || mode == kAllLiveObjects)) {
object = HeapObject::FromAddress(addr); object = HeapObject::FromAddress(addr);
Object map_object = object.map(kAcquireLoad); Object map_object = object.map(cage_base, kAcquireLoad);
CHECK(map_object.IsMap()); CHECK(map_object.IsMap(cage_base));
map = Map::cast(map_object); map = Map::cast(map_object);
DCHECK(map.IsMap()); DCHECK(map.IsMap(cage_base));
size = object.SizeFromMap(map); size = object.SizeFromMap(map);
CHECK_LE(addr + size, chunk_->area_end()); CHECK_LE(addr + size, chunk_->area_end());
} }
......
...@@ -2879,8 +2879,10 @@ static inline SlotCallbackResult UpdateSlot(PtrComprCageBase cage_base, ...@@ -2879,8 +2879,10 @@ static inline SlotCallbackResult UpdateSlot(PtrComprCageBase cage_base,
MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) || MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) ||
Page::FromHeapObject(heap_obj)->IsFlagSet( Page::FromHeapObject(heap_obj)->IsFlagSet(
Page::COMPACTION_WAS_ABORTED)); Page::COMPACTION_WAS_ABORTED));
typename TSlot::TObject target = PtrComprCageBase host_cage_base =
MakeSlotValue<TSlot, reference_type>(map_word.ToForwardingAddress()); V8_EXTERNAL_CODE_SPACE_BOOL ? GetPtrComprCageBase(heap_obj) : cage_base;
typename TSlot::TObject target = MakeSlotValue<TSlot, reference_type>(
map_word.ToForwardingAddress(host_cage_base));
if (access_mode == AccessMode::NON_ATOMIC) { if (access_mode == AccessMode::NON_ATOMIC) {
slot.store(target); slot.store(target);
} else { } else {
...@@ -4019,7 +4021,11 @@ class RememberedSetUpdatingItem : public UpdatingItem { ...@@ -4019,7 +4021,11 @@ class RememberedSetUpdatingItem : public UpdatingItem {
(chunk_->slot_set<OLD_TO_CODE, AccessMode::NON_ATOMIC>() != (chunk_->slot_set<OLD_TO_CODE, AccessMode::NON_ATOMIC>() !=
nullptr)) { nullptr)) {
PtrComprCageBase cage_base = heap_->isolate(); PtrComprCageBase cage_base = heap_->isolate();
PtrComprCageBase code_cage_base = heap_->isolate(); #if V8_EXTERNAL_CODE_SPACE
PtrComprCageBase code_cage_base(heap_->isolate()->code_cage_base());
#else
PtrComprCageBase code_cage_base = cage_base;
#endif
RememberedSet<OLD_TO_CODE>::Iterate( RememberedSet<OLD_TO_CODE>::Iterate(
chunk_, chunk_,
[=](MaybeObjectSlot slot) { [=](MaybeObjectSlot slot) {
...@@ -4153,25 +4159,26 @@ class EphemeronTableUpdatingItem : public UpdatingItem { ...@@ -4153,25 +4159,26 @@ class EphemeronTableUpdatingItem : public UpdatingItem {
void Process() override { void Process() override {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"), TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
"EphemeronTableUpdatingItem::Process"); "EphemeronTableUpdatingItem::Process");
PtrComprCageBase cage_base(heap_->isolate());
for (auto it = heap_->ephemeron_remembered_set_.begin(); for (auto it = heap_->ephemeron_remembered_set_.begin();
it != heap_->ephemeron_remembered_set_.end();) { it != heap_->ephemeron_remembered_set_.end();) {
EphemeronHashTable table = it->first; EphemeronHashTable table = it->first;
auto& indices = it->second; auto& indices = it->second;
if (table.map_word(kRelaxedLoad).IsForwardingAddress()) { if (table.map_word(cage_base, kRelaxedLoad).IsForwardingAddress()) {
// The table has moved, and RecordMigratedSlotVisitor::VisitEphemeron // The table has moved, and RecordMigratedSlotVisitor::VisitEphemeron
// inserts entries for the moved table into ephemeron_remembered_set_. // inserts entries for the moved table into ephemeron_remembered_set_.
it = heap_->ephemeron_remembered_set_.erase(it); it = heap_->ephemeron_remembered_set_.erase(it);
continue; continue;
} }
DCHECK(table.map().IsMap()); DCHECK(table.map(cage_base).IsMap(cage_base));
DCHECK(table.Object::IsEphemeronHashTable()); DCHECK(table.IsEphemeronHashTable(cage_base));
for (auto iti = indices.begin(); iti != indices.end();) { for (auto iti = indices.begin(); iti != indices.end();) {
// EphemeronHashTable keys must be heap objects. // EphemeronHashTable keys must be heap objects.
HeapObjectSlot key_slot(table.RawFieldOfElementAt( HeapObjectSlot key_slot(table.RawFieldOfElementAt(
EphemeronHashTable::EntryToIndex(InternalIndex(*iti)))); EphemeronHashTable::EntryToIndex(InternalIndex(*iti))));
HeapObject key = key_slot.ToHeapObject(); HeapObject key = key_slot.ToHeapObject();
MapWord map_word = key.map_word(kRelaxedLoad); MapWord map_word = key.map_word(cage_base, kRelaxedLoad);
if (map_word.IsForwardingAddress()) { if (map_word.IsForwardingAddress()) {
key = map_word.ToForwardingAddress(); key = map_word.ToForwardingAddress();
key_slot.StoreHeapObject(key); key_slot.StoreHeapObject(key);
......
...@@ -688,6 +688,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) { ...@@ -688,6 +688,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) {
external_space_bytes[static_cast<ExternalBackingStoreType>(i)] = 0; external_space_bytes[static_cast<ExternalBackingStoreType>(i)] = 0;
} }
PtrComprCageBase cage_base(isolate);
for (Page* page : *this) { for (Page* page : *this) {
CHECK_EQ(page->owner(), this); CHECK_EQ(page->owner(), this);
...@@ -729,7 +730,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) { ...@@ -729,7 +730,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) {
CHECK(object.address() + size <= top); CHECK(object.address() + size <= top);
end_of_previous_object = object.address() + size; end_of_previous_object = object.address() + size;
if (object.IsExternalString()) { if (object.IsExternalString(cage_base)) {
ExternalString external_string = ExternalString::cast(object); ExternalString external_string = ExternalString::cast(object);
size_t payload_size = external_string.ExternalPayloadSize(); size_t payload_size = external_string.ExternalPayloadSize();
external_page_bytes[ExternalBackingStoreType::kExternalString] += external_page_bytes[ExternalBackingStoreType::kExternalString] +=
......
...@@ -366,6 +366,7 @@ int Sweeper::RawSweep( ...@@ -366,6 +366,7 @@ int Sweeper::RawSweep(
// Iterate over the page using the live objects and free the memory before // Iterate over the page using the live objects and free the memory before
// the given live object. // the given live object.
Address free_start = p->area_start(); Address free_start = p->area_start();
PtrComprCageBase cage_base(heap_->isolate());
for (auto object_and_size : for (auto object_and_size :
LiveObjectRange<kBlackObjects>(p, marking_state_->bitmap(p))) { LiveObjectRange<kBlackObjects>(p, marking_state_->bitmap(p))) {
HeapObject const object = object_and_size.first; HeapObject const object = object_and_size.first;
...@@ -383,8 +384,8 @@ int Sweeper::RawSweep( ...@@ -383,8 +384,8 @@ int Sweeper::RawSweep(
free_start, free_end, p, non_empty_typed_slots, &free_ranges_map, free_start, free_end, p, non_empty_typed_slots, &free_ranges_map,
&old_to_new_cleanup); &old_to_new_cleanup);
} }
Map map = object.map(kAcquireLoad); Map map = object.map(cage_base, kAcquireLoad);
DCHECK(map.IsMap()); DCHECK(map.IsMap(cage_base));
int size = object.SizeFromMap(map); int size = object.SizeFromMap(map);
live_bytes += size; live_bytes += size;
free_start = free_end + size; free_start = free_end + size;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "src/builtins/builtins.h" #include "src/builtins/builtins.h"
#include "src/common/external-pointer-inl.h" #include "src/common/external-pointer-inl.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/common/ptr-compr-inl.h"
#include "src/handles/handles-inl.h" #include "src/handles/handles-inl.h"
#include "src/heap/factory.h" #include "src/heap/factory.h"
#include "src/heap/heap-write-barrier-inl.h" #include "src/heap/heap-write-barrier-inl.h"
...@@ -679,6 +680,22 @@ MapWord MapWord::FromForwardingAddress(HeapObject object) { ...@@ -679,6 +680,22 @@ MapWord MapWord::FromForwardingAddress(HeapObject object) {
HeapObject MapWord::ToForwardingAddress() { HeapObject MapWord::ToForwardingAddress() {
DCHECK(IsForwardingAddress()); DCHECK(IsForwardingAddress());
HeapObject obj = HeapObject::FromAddress(value_);
// For objects allocated outside of the main pointer compression cage the
// variant with explicit cage base must be used.
DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !obj.IsCode());
return obj;
}
HeapObject MapWord::ToForwardingAddress(PtrComprCageBase host_cage_base) {
DCHECK(IsForwardingAddress());
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
// Recompress value_ using proper host_cage_base since the map word
// has the upper 32 bits that correspond to the main cage base value.
Address value =
DecompressTaggedPointer(host_cage_base, CompressTagged(value_));
return HeapObject::FromAddress(value);
}
return HeapObject::FromAddress(value_); return HeapObject::FromAddress(value_);
} }
......
...@@ -787,8 +787,14 @@ class MapWord { ...@@ -787,8 +787,14 @@ class MapWord {
// Create a map word from a forwarding address. // Create a map word from a forwarding address.
static inline MapWord FromForwardingAddress(HeapObject object); static inline MapWord FromForwardingAddress(HeapObject object);
// View this map word as a forwarding address. // View this map word as a forwarding address. The parameterless version
// is allowed to be used for objects allocated in the main pointer compression
// cage, while the second variant uses the value of the cage base explicitly
// and thus can be used in situations where one has to deal with both cases.
// Note, that the parameterless version is preferred because it avoids
// unnecessary recompressions.
inline HeapObject ToForwardingAddress(); inline HeapObject ToForwardingAddress();
inline HeapObject ToForwardingAddress(PtrComprCageBase host_cage_base);
inline Address ptr() { return value_; } inline Address ptr() { return value_; }
......
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