Skip to content

Commit 41a5a24

Browse files
isheludkoV8 LUCI CQ
authored andcommitted
[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/+/3204968 Reviewed-by: Michael Lippautz <[email protected]> Commit-Queue: Igor Sheludko <[email protected]> Cr-Commit-Position: refs/heads/main@{#77244}
1 parent d78d8b7 commit 41a5a24

8 files changed

Lines changed: 91 additions & 44 deletions

File tree

src/heap/heap.cc

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -978,10 +978,11 @@ size_t Heap::UsedGlobalHandlesSize() {
978978

979979
void Heap::MergeAllocationSitePretenuringFeedback(
980980
const PretenuringFeedbackMap& local_pretenuring_feedback) {
981+
PtrComprCageBase cage_base(isolate());
981982
AllocationSite site;
982983
for (auto& site_and_count : local_pretenuring_feedback) {
983984
site = site_and_count.first;
984-
MapWord map_word = site_and_count.first.map_word(kRelaxedLoad);
985+
MapWord map_word = site.map_word(cage_base, kRelaxedLoad);
985986
if (map_word.IsForwardingAddress()) {
986987
site = AllocationSite::cast(map_word.ToForwardingAddress());
987988
}
@@ -2731,18 +2732,19 @@ void Heap::UpdateExternalString(String string, size_t old_payload,
27312732

27322733
String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
27332734
FullObjectSlot p) {
2735+
PtrComprCageBase cage_base(heap->isolate());
27342736
HeapObject obj = HeapObject::cast(*p);
2735-
MapWord first_word = obj.map_word(kRelaxedLoad);
2737+
MapWord first_word = obj.map_word(cage_base, kRelaxedLoad);
27362738

27372739
String new_string;
27382740

27392741
if (InFromPage(obj)) {
27402742
if (!first_word.IsForwardingAddress()) {
27412743
// Unreachable external string can be finalized.
27422744
String string = String::cast(obj);
2743-
if (!string.IsExternalString()) {
2745+
if (!string.IsExternalString(cage_base)) {
27442746
// Original external string has been internalized.
2745-
DCHECK(string.IsThinString());
2747+
DCHECK(string.IsThinString(cage_base));
27462748
return String();
27472749
}
27482750
heap->FinalizeExternalString(string);
@@ -2754,10 +2756,10 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
27542756
}
27552757

27562758
// String is still reachable.
2757-
if (new_string.IsThinString()) {
2759+
if (new_string.IsThinString(cage_base)) {
27582760
// Filtering Thin strings out of the external string table.
27592761
return String();
2760-
} else if (new_string.IsExternalString()) {
2762+
} else if (new_string.IsExternalString(cage_base)) {
27612763
MemoryChunk::MoveExternalBackingStoreBytes(
27622764
ExternalBackingStoreType::kExternalString,
27632765
Page::FromAddress((*p).ptr()), Page::FromHeapObject(new_string),
@@ -2766,7 +2768,7 @@ String Heap::UpdateYoungReferenceInExternalStringTableEntry(Heap* heap,
27662768
}
27672769

27682770
// Internalization can replace external strings with non-external strings.
2769-
return new_string.IsExternalString() ? new_string : String();
2771+
return new_string.IsExternalString(cage_base) ? new_string : String();
27702772
}
27712773

27722774
void Heap::ExternalStringTable::VerifyYoung() {
@@ -6995,9 +6997,17 @@ void Heap::CreateObjectStats() {
69956997
}
69966998

69976999
Map Heap::GcSafeMapOfCodeSpaceObject(HeapObject object) {
6998-
MapWord map_word = object.map_word(kRelaxedLoad);
6999-
return map_word.IsForwardingAddress() ? map_word.ToForwardingAddress().map()
7000-
: map_word.ToMap();
7000+
PtrComprCageBase cage_base(isolate());
7001+
MapWord map_word = object.map_word(cage_base, kRelaxedLoad);
7002+
if (map_word.IsForwardingAddress()) {
7003+
#if V8_EXTERNAL_CODE_SPACE
7004+
PtrComprCageBase code_cage_base(isolate()->code_cage_base());
7005+
#else
7006+
PtrComprCageBase code_cage_base = cage_base;
7007+
#endif
7008+
return map_word.ToForwardingAddress(code_cage_base).map(cage_base);
7009+
}
7010+
return map_word.ToMap();
70017011
}
70027012

70037013
Code Heap::GcSafeCastToCode(HeapObject object, Address inner_pointer) {

src/heap/large-spaces.cc

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
354354
external_backing_store_bytes[static_cast<ExternalBackingStoreType>(i)] = 0;
355355
}
356356

357+
PtrComprCageBase cage_base(isolate);
357358
for (LargePage* chunk = first_page(); chunk != nullptr;
358359
chunk = chunk->next_page()) {
359360
// Each chunk contains an object that starts at the large object page's
@@ -364,23 +365,26 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
364365

365366
// The first word should be a map, and we expect all map pointers to be
366367
// in map space or read-only space.
367-
Map map = object.map();
368-
CHECK(map.IsMap());
368+
Map map = object.map(cage_base);
369+
CHECK(map.IsMap(cage_base));
369370
CHECK(ReadOnlyHeap::Contains(map) || heap()->map_space()->Contains(map));
370371

371372
// We have only the following types in the large object space:
372-
if (!(object.IsAbstractCode() || object.IsSeqString() ||
373-
object.IsExternalString() || object.IsThinString() ||
374-
object.IsFixedArray() || object.IsFixedDoubleArray() ||
375-
object.IsWeakFixedArray() || object.IsWeakArrayList() ||
376-
object.IsPropertyArray() || object.IsByteArray() ||
377-
object.IsFeedbackVector() || object.IsBigInt() ||
378-
object.IsFreeSpace() || object.IsFeedbackMetadata() ||
379-
object.IsContext() || object.IsUncompiledDataWithoutPreparseData() ||
380-
object.IsPreparseData()) &&
373+
if (!(object.IsAbstractCode(cage_base) || object.IsSeqString(cage_base) ||
374+
object.IsExternalString(cage_base) ||
375+
object.IsThinString(cage_base) || object.IsFixedArray(cage_base) ||
376+
object.IsFixedDoubleArray(cage_base) ||
377+
object.IsWeakFixedArray(cage_base) ||
378+
object.IsWeakArrayList(cage_base) ||
379+
object.IsPropertyArray(cage_base) || object.IsByteArray(cage_base) ||
380+
object.IsFeedbackVector(cage_base) || object.IsBigInt(cage_base) ||
381+
object.IsFreeSpace(cage_base) ||
382+
object.IsFeedbackMetadata(cage_base) || object.IsContext(cage_base) ||
383+
object.IsUncompiledDataWithoutPreparseData(cage_base) ||
384+
object.IsPreparseData(cage_base)) &&
381385
!FLAG_young_generation_large_objects) {
382386
FATAL("Found invalid Object (instance_type=%i) in large object space.",
383-
object.map().instance_type());
387+
object.map(cage_base).instance_type());
384388
}
385389

386390
// The object itself should look OK.
@@ -391,27 +395,27 @@ void LargeObjectSpace::Verify(Isolate* isolate) {
391395
}
392396

393397
// Byte arrays and strings don't have interior pointers.
394-
if (object.IsAbstractCode()) {
398+
if (object.IsAbstractCode(cage_base)) {
395399
VerifyPointersVisitor code_visitor(heap());
396400
object.IterateBody(map, object.Size(), &code_visitor);
397-
} else if (object.IsFixedArray()) {
401+
} else if (object.IsFixedArray(cage_base)) {
398402
FixedArray array = FixedArray::cast(object);
399403
for (int j = 0; j < array.length(); j++) {
400404
Object element = array.get(j);
401405
if (element.IsHeapObject()) {
402406
HeapObject element_object = HeapObject::cast(element);
403407
CHECK(IsValidHeapObject(heap(), element_object));
404-
CHECK(element_object.map().IsMap());
408+
CHECK(element_object.map(cage_base).IsMap(cage_base));
405409
}
406410
}
407-
} else if (object.IsPropertyArray()) {
411+
} else if (object.IsPropertyArray(cage_base)) {
408412
PropertyArray array = PropertyArray::cast(object);
409413
for (int j = 0; j < array.length(); j++) {
410414
Object property = array.get(j);
411415
if (property.IsHeapObject()) {
412416
HeapObject property_object = HeapObject::cast(property);
413417
CHECK(heap()->Contains(property_object));
414-
CHECK(property_object.map().IsMap());
418+
CHECK(property_object.map(cage_base).IsMap(cage_base));
415419
}
416420
}
417421
}

src/heap/mark-compact-inl.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ operator++(int) {
163163

164164
template <LiveObjectIterationMode mode>
165165
void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
166+
PtrComprCageBase cage_base(chunk_->heap()->isolate());
166167
while (!it_.Done()) {
167168
HeapObject object;
168169
int size = 0;
@@ -198,10 +199,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
198199
// make sure that we skip all set bits in the black area until the
199200
// object ends.
200201
HeapObject black_object = HeapObject::FromAddress(addr);
201-
Object map_object = black_object.map(kAcquireLoad);
202-
CHECK(map_object.IsMap());
202+
Object map_object = black_object.map(cage_base, kAcquireLoad);
203+
CHECK(map_object.IsMap(cage_base));
203204
map = Map::cast(map_object);
204-
DCHECK(map.IsMap());
205+
DCHECK(map.IsMap(cage_base));
205206
size = black_object.SizeFromMap(map);
206207
CHECK_LE(addr + size, chunk_->area_end());
207208
Address end = addr + size - kTaggedSize;
@@ -230,10 +231,10 @@ void LiveObjectRange<mode>::iterator::AdvanceToNextValidObject() {
230231
}
231232
} else if ((mode == kGreyObjects || mode == kAllLiveObjects)) {
232233
object = HeapObject::FromAddress(addr);
233-
Object map_object = object.map(kAcquireLoad);
234-
CHECK(map_object.IsMap());
234+
Object map_object = object.map(cage_base, kAcquireLoad);
235+
CHECK(map_object.IsMap(cage_base));
235236
map = Map::cast(map_object);
236-
DCHECK(map.IsMap());
237+
DCHECK(map.IsMap(cage_base));
237238
size = object.SizeFromMap(map);
238239
CHECK_LE(addr + size, chunk_->area_end());
239240
}

src/heap/mark-compact.cc

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2879,8 +2879,10 @@ static inline SlotCallbackResult UpdateSlot(PtrComprCageBase cage_base,
28792879
MarkCompactCollector::IsOnEvacuationCandidate(heap_obj) ||
28802880
Page::FromHeapObject(heap_obj)->IsFlagSet(
28812881
Page::COMPACTION_WAS_ABORTED));
2882-
typename TSlot::TObject target =
2883-
MakeSlotValue<TSlot, reference_type>(map_word.ToForwardingAddress());
2882+
PtrComprCageBase host_cage_base =
2883+
V8_EXTERNAL_CODE_SPACE_BOOL ? GetPtrComprCageBase(heap_obj) : cage_base;
2884+
typename TSlot::TObject target = MakeSlotValue<TSlot, reference_type>(
2885+
map_word.ToForwardingAddress(host_cage_base));
28842886
if (access_mode == AccessMode::NON_ATOMIC) {
28852887
slot.store(target);
28862888
} else {
@@ -4019,7 +4021,11 @@ class RememberedSetUpdatingItem : public UpdatingItem {
40194021
(chunk_->slot_set<OLD_TO_CODE, AccessMode::NON_ATOMIC>() !=
40204022
nullptr)) {
40214023
PtrComprCageBase cage_base = heap_->isolate();
4022-
PtrComprCageBase code_cage_base = heap_->isolate();
4024+
#if V8_EXTERNAL_CODE_SPACE
4025+
PtrComprCageBase code_cage_base(heap_->isolate()->code_cage_base());
4026+
#else
4027+
PtrComprCageBase code_cage_base = cage_base;
4028+
#endif
40234029
RememberedSet<OLD_TO_CODE>::Iterate(
40244030
chunk_,
40254031
[=](MaybeObjectSlot slot) {
@@ -4153,25 +4159,26 @@ class EphemeronTableUpdatingItem : public UpdatingItem {
41534159
void Process() override {
41544160
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
41554161
"EphemeronTableUpdatingItem::Process");
4162+
PtrComprCageBase cage_base(heap_->isolate());
41564163

41574164
for (auto it = heap_->ephemeron_remembered_set_.begin();
41584165
it != heap_->ephemeron_remembered_set_.end();) {
41594166
EphemeronHashTable table = it->first;
41604167
auto& indices = it->second;
4161-
if (table.map_word(kRelaxedLoad).IsForwardingAddress()) {
4168+
if (table.map_word(cage_base, kRelaxedLoad).IsForwardingAddress()) {
41624169
// The table has moved, and RecordMigratedSlotVisitor::VisitEphemeron
41634170
// inserts entries for the moved table into ephemeron_remembered_set_.
41644171
it = heap_->ephemeron_remembered_set_.erase(it);
41654172
continue;
41664173
}
4167-
DCHECK(table.map().IsMap());
4168-
DCHECK(table.Object::IsEphemeronHashTable());
4174+
DCHECK(table.map(cage_base).IsMap(cage_base));
4175+
DCHECK(table.IsEphemeronHashTable(cage_base));
41694176
for (auto iti = indices.begin(); iti != indices.end();) {
41704177
// EphemeronHashTable keys must be heap objects.
41714178
HeapObjectSlot key_slot(table.RawFieldOfElementAt(
41724179
EphemeronHashTable::EntryToIndex(InternalIndex(*iti))));
41734180
HeapObject key = key_slot.ToHeapObject();
4174-
MapWord map_word = key.map_word(kRelaxedLoad);
4181+
MapWord map_word = key.map_word(cage_base, kRelaxedLoad);
41754182
if (map_word.IsForwardingAddress()) {
41764183
key = map_word.ToForwardingAddress();
41774184
key_slot.StoreHeapObject(key);

src/heap/paged-spaces.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) {
688688
external_space_bytes[static_cast<ExternalBackingStoreType>(i)] = 0;
689689
}
690690

691+
PtrComprCageBase cage_base(isolate);
691692
for (Page* page : *this) {
692693
CHECK_EQ(page->owner(), this);
693694

@@ -729,7 +730,7 @@ void PagedSpace::Verify(Isolate* isolate, ObjectVisitor* visitor) {
729730
CHECK(object.address() + size <= top);
730731
end_of_previous_object = object.address() + size;
731732

732-
if (object.IsExternalString()) {
733+
if (object.IsExternalString(cage_base)) {
733734
ExternalString external_string = ExternalString::cast(object);
734735
size_t payload_size = external_string.ExternalPayloadSize();
735736
external_page_bytes[ExternalBackingStoreType::kExternalString] +=

src/heap/sweeper.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ int Sweeper::RawSweep(
366366
// Iterate over the page using the live objects and free the memory before
367367
// the given live object.
368368
Address free_start = p->area_start();
369+
PtrComprCageBase cage_base(heap_->isolate());
369370
for (auto object_and_size :
370371
LiveObjectRange<kBlackObjects>(p, marking_state_->bitmap(p))) {
371372
HeapObject const object = object_and_size.first;
@@ -383,8 +384,8 @@ int Sweeper::RawSweep(
383384
free_start, free_end, p, non_empty_typed_slots, &free_ranges_map,
384385
&old_to_new_cleanup);
385386
}
386-
Map map = object.map(kAcquireLoad);
387-
DCHECK(map.IsMap());
387+
Map map = object.map(cage_base, kAcquireLoad);
388+
DCHECK(map.IsMap(cage_base));
388389
int size = object.SizeFromMap(map);
389390
live_bytes += size;
390391
free_start = free_end + size;

src/objects/objects-inl.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "src/builtins/builtins.h"
1919
#include "src/common/external-pointer-inl.h"
2020
#include "src/common/globals.h"
21+
#include "src/common/ptr-compr-inl.h"
2122
#include "src/handles/handles-inl.h"
2223
#include "src/heap/factory.h"
2324
#include "src/heap/heap-write-barrier-inl.h"
@@ -679,6 +680,22 @@ MapWord MapWord::FromForwardingAddress(HeapObject object) {
679680

680681
HeapObject MapWord::ToForwardingAddress() {
681682
DCHECK(IsForwardingAddress());
683+
HeapObject obj = HeapObject::FromAddress(value_);
684+
// For objects allocated outside of the main pointer compression cage the
685+
// variant with explicit cage base must be used.
686+
DCHECK_IMPLIES(V8_EXTERNAL_CODE_SPACE_BOOL, !obj.IsCode());
687+
return obj;
688+
}
689+
690+
HeapObject MapWord::ToForwardingAddress(PtrComprCageBase host_cage_base) {
691+
DCHECK(IsForwardingAddress());
692+
if (V8_EXTERNAL_CODE_SPACE_BOOL) {
693+
// Recompress value_ using proper host_cage_base since the map word
694+
// has the upper 32 bits that correspond to the main cage base value.
695+
Address value =
696+
DecompressTaggedPointer(host_cage_base, CompressTagged(value_));
697+
return HeapObject::FromAddress(value);
698+
}
682699
return HeapObject::FromAddress(value_);
683700
}
684701

src/objects/objects.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,8 +787,14 @@ class MapWord {
787787
// Create a map word from a forwarding address.
788788
static inline MapWord FromForwardingAddress(HeapObject object);
789789

790-
// View this map word as a forwarding address.
790+
// View this map word as a forwarding address. The parameterless version
791+
// is allowed to be used for objects allocated in the main pointer compression
792+
// cage, while the second variant uses the value of the cage base explicitly
793+
// and thus can be used in situations where one has to deal with both cases.
794+
// Note, that the parameterless version is preferred because it avoids
795+
// unnecessary recompressions.
791796
inline HeapObject ToForwardingAddress();
797+
inline HeapObject ToForwardingAddress(PtrComprCageBase host_cage_base);
792798

793799
inline Address ptr() { return value_; }
794800

0 commit comments

Comments
 (0)