Skip to content

Commit d1bf046

Browse files
committed
deps: cherry-pick f4376ec801e1ded from V8 upstream
Original commit message: [heap] Make maximum regular code object size a runtime value. Executable V8 pages include 3 reserved OS pages: one for the writable header and two as guards. On systems with 64k OS pages, the amount of allocatable space left for objects can then be quite smaller than the page size, only 64k for each 256k page. This means regular code objects cannot be larger than 64k, while the maximum regular object size is fixed to 128k, half of the page size. As a result code object never reach this limit and we can end up filling regular pages with few large code objects. To fix this, we change the maximum code object size to be runtime value, set to half of the allocatable space per page. On systems with 64k OS pages, the limit will be 32k. Alternatively, we could increase the V8 page size to 512k on Arm64 linux so we wouldn't waste code space. However, systems with 4k OS pages are more common, and those with 64k pages tend to have more memory available so we should be able to live with it. Bug: v8:10808 Change-Id: I5d807e7a3df89f1e9c648899e9ba2f8e2648264c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2460809 Reviewed-by: Igor Sheludko <[email protected]> Reviewed-by: Georg Neis <[email protected]> Reviewed-by: Ulan Degenbaev <[email protected]> Commit-Queue: Pierre Langlois <[email protected]> Cr-Commit-Position: refs/heads/master@{#70569} PR-URL: #37225 Refs: nodejs/help#3202 Reviewed-By: Michael Dawson <[email protected]> Reviewed-By: Stewart X Addison <[email protected]> Reviewed-By: Juan José Arboleda <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 93f7f9e commit d1bf046

18 files changed

+143
-21
lines changed

deps/v8/src/base/build_config.h

+4
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@
205205
// PPC has large (64KB) physical pages.
206206
const int kPageSizeBits = 19;
207207
#else
208+
// Arm64 supports up to 64k OS pages on Linux, however 4k pages are more common
209+
// so we keep the V8 page size at 256k. Nonetheless, we need to make sure we
210+
// don't decrease it further in the future due to reserving 3 OS pages for every
211+
// executable V8 page.
208212
const int kPageSizeBits = 18;
209213
#endif
210214

deps/v8/src/compiler/allocation-builder.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ class AllocationBuilder final {
2727
// Primitive allocation of static size.
2828
void Allocate(int size, AllocationType allocation = AllocationType::kYoung,
2929
Type type = Type::Any()) {
30-
DCHECK_LE(size, kMaxRegularHeapObjectSize);
30+
DCHECK_LE(size, Heap::MaxRegularHeapObjectSize(allocation));
3131
effect_ = graph()->NewNode(
3232
common()->BeginRegion(RegionObservability::kNotObservable), effect_);
3333
allocation_ =

deps/v8/src/compiler/memory-lowering.cc

+4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ Reduction MemoryLowering::ReduceAllocateRaw(
9898
DCHECK_EQ(IrOpcode::kAllocateRaw, node->opcode());
9999
DCHECK_IMPLIES(allocation_folding_ == AllocationFolding::kDoAllocationFolding,
100100
state_ptr != nullptr);
101+
// Code objects may have a maximum size smaller than kMaxHeapObjectSize due to
102+
// guard pages. If we need to support allocating code here we would need to
103+
// call MemoryChunkLayout::MaxRegularCodeObjectSize() at runtime.
104+
DCHECK_NE(allocation_type, AllocationType::kCode);
101105
Node* value;
102106
Node* size = node->InputAt(0);
103107
Node* effect = node->InputAt(1);

deps/v8/src/diagnostics/objects-debug.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,8 @@ void Code::CodeVerify(Isolate* isolate) {
955955
// everything is set up.
956956
// CHECK_EQ(ReadOnlyHeap::Contains(*this), !IsExecutable());
957957
relocation_info().ObjectVerify(isolate);
958-
CHECK(Code::SizeFor(body_size()) <= kMaxRegularHeapObjectSize ||
958+
CHECK(Code::SizeFor(body_size()) <=
959+
MemoryChunkLayout::MaxRegularCodeObjectSize() ||
959960
isolate->heap()->InSpace(*this, CODE_LO_SPACE));
960961
Address last_gc_pc = kNullAddress;
961962

deps/v8/src/heap/factory-base.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -721,7 +721,8 @@ template <typename Impl>
721721
HeapObject FactoryBase<Impl>::AllocateRawArray(int size,
722722
AllocationType allocation) {
723723
HeapObject result = AllocateRaw(size, allocation);
724-
if (size > kMaxRegularHeapObjectSize && FLAG_use_marking_progress_bar) {
724+
if ((size > Heap::MaxRegularHeapObjectSize(allocation)) &&
725+
FLAG_use_marking_progress_bar) {
725726
MemoryChunk* chunk = MemoryChunk::FromHeapObject(result);
726727
chunk->SetFlag<AccessMode::ATOMIC>(MemoryChunk::HAS_PROGRESS_BAR);
727728
}

deps/v8/src/heap/factory.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,8 @@ MaybeHandle<FixedArray> Factory::TryNewFixedArray(
346346
AllocationResult allocation = heap->AllocateRaw(size, allocation_type);
347347
HeapObject result;
348348
if (!allocation.To(&result)) return MaybeHandle<FixedArray>();
349-
if (size > kMaxRegularHeapObjectSize && FLAG_use_marking_progress_bar) {
349+
if ((size > Heap::MaxRegularHeapObjectSize(allocation_type)) &&
350+
FLAG_use_marking_progress_bar) {
350351
MemoryChunk* chunk = MemoryChunk::FromHeapObject(result);
351352
chunk->SetFlag<AccessMode::ATOMIC>(MemoryChunk::HAS_PROGRESS_BAR);
352353
}

deps/v8/src/heap/heap-inl.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,9 @@ AllocationResult Heap::AllocateRaw(int size_in_bytes, AllocationType type,
192192
IncrementObjectCounters();
193193
#endif
194194

195-
bool large_object = size_in_bytes > kMaxRegularHeapObjectSize;
195+
size_t large_object_threshold = MaxRegularHeapObjectSize(type);
196+
bool large_object =
197+
static_cast<size_t>(size_in_bytes) > large_object_threshold;
196198

197199
HeapObject object;
198200
AllocationResult allocation;
@@ -279,7 +281,7 @@ HeapObject Heap::AllocateRawWith(int size, AllocationType allocation,
279281
Address* limit = heap->NewSpaceAllocationLimitAddress();
280282
if (allocation == AllocationType::kYoung &&
281283
alignment == AllocationAlignment::kWordAligned &&
282-
size <= kMaxRegularHeapObjectSize &&
284+
size <= MaxRegularHeapObjectSize(allocation) &&
283285
(*limit - *top >= static_cast<unsigned>(size)) &&
284286
V8_LIKELY(!FLAG_single_generation && FLAG_inline_new &&
285287
FLAG_gc_interval == 0)) {

deps/v8/src/heap/heap.cc

+8
Original file line numberDiff line numberDiff line change
@@ -4963,6 +4963,14 @@ bool Heap::AllocationLimitOvershotByLargeMargin() {
49634963
return v8_overshoot >= v8_margin || global_overshoot >= global_margin;
49644964
}
49654965

4966+
// static
4967+
int Heap::MaxRegularHeapObjectSize(AllocationType allocation) {
4968+
if (allocation == AllocationType::kCode) {
4969+
return MemoryChunkLayout::MaxRegularCodeObjectSize();
4970+
}
4971+
return kMaxRegularHeapObjectSize;
4972+
}
4973+
49664974
bool Heap::ShouldOptimizeForLoadTime() {
49674975
return isolate()->rail_mode() == PERFORMANCE_LOAD &&
49684976
!AllocationLimitOvershotByLargeMargin() &&

deps/v8/src/heap/heap.h

+13-3
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ class Heap {
481481

482482
bool IsImmovable(HeapObject object);
483483

484-
static bool IsLargeObject(HeapObject object);
484+
V8_EXPORT_PRIVATE static bool IsLargeObject(HeapObject object);
485485

486486
// This method supports the deserialization allocator. All allocations
487487
// are word-aligned. The method should never fail to allocate since the
@@ -1316,6 +1316,14 @@ class Heap {
13161316
// more eager to finalize incremental marking.
13171317
bool AllocationLimitOvershotByLargeMargin();
13181318

1319+
// Return the maximum size objects can be before having to allocate them as
1320+
// large objects. This takes into account allocating in the code space for
1321+
// which the size of the allocatable space per V8 page may depend on the OS
1322+
// page size at runtime. You may use kMaxRegularHeapObjectSize as a constant
1323+
// instead if you know the allocation isn't in the code spaces.
1324+
V8_EXPORT_PRIVATE static int MaxRegularHeapObjectSize(
1325+
AllocationType allocation);
1326+
13191327
// ===========================================================================
13201328
// Prologue/epilogue callback methods.========================================
13211329
// ===========================================================================
@@ -1404,8 +1412,10 @@ class Heap {
14041412
// Heap object allocation tracking. ==========================================
14051413
// ===========================================================================
14061414

1407-
void AddHeapObjectAllocationTracker(HeapObjectAllocationTracker* tracker);
1408-
void RemoveHeapObjectAllocationTracker(HeapObjectAllocationTracker* tracker);
1415+
V8_EXPORT_PRIVATE void AddHeapObjectAllocationTracker(
1416+
HeapObjectAllocationTracker* tracker);
1417+
V8_EXPORT_PRIVATE void RemoveHeapObjectAllocationTracker(
1418+
HeapObjectAllocationTracker* tracker);
14091419
bool has_heap_object_allocation_tracker() const {
14101420
return !allocation_trackers_.empty();
14111421
}

deps/v8/src/heap/memory-chunk.cc

+6-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ intptr_t MemoryChunkLayout::ObjectEndOffsetInCodePage() {
4747

4848
size_t MemoryChunkLayout::AllocatableMemoryInCodePage() {
4949
size_t memory = ObjectEndOffsetInCodePage() - ObjectStartOffsetInCodePage();
50-
DCHECK_LE(kMaxRegularHeapObjectSize, memory);
5150
return memory;
5251
}
5352

@@ -77,6 +76,12 @@ size_t MemoryChunkLayout::AllocatableMemoryInMemoryChunk(
7776
return AllocatableMemoryInDataPage();
7877
}
7978

79+
int MemoryChunkLayout::MaxRegularCodeObjectSize() {
80+
int size = static_cast<int>(AllocatableMemoryInCodePage() / 2);
81+
DCHECK_LE(size, kMaxRegularHeapObjectSize);
82+
return size;
83+
}
84+
8085
#ifdef THREAD_SANITIZER
8186
void MemoryChunk::SynchronizedHeapLoad() {
8287
CHECK(reinterpret_cast<Heap*>(base::Acquire_Load(

deps/v8/src/heap/memory-chunk.h

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ class V8_EXPORT_PRIVATE MemoryChunkLayout {
3232
static size_t AllocatableMemoryInDataPage();
3333
static size_t ObjectStartOffsetInMemoryChunk(AllocationSpace space);
3434
static size_t AllocatableMemoryInMemoryChunk(AllocationSpace space);
35+
36+
static int MaxRegularCodeObjectSize();
3537
};
3638

3739
// MemoryChunk represents a memory region owned by a specific space.

deps/v8/src/heap/spaces.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ class Space;
127127
#define DCHECK_OBJECT_SIZE(size) \
128128
DCHECK((0 < size) && (size <= kMaxRegularHeapObjectSize))
129129

130-
#define DCHECK_CODEOBJECT_SIZE(size, code_space) \
131-
DCHECK((0 < size) && (size <= code_space->AreaSize()))
130+
#define DCHECK_CODEOBJECT_SIZE(size, code_space) \
131+
DCHECK((0 < size) && \
132+
(size <= std::min(MemoryChunkLayout::MaxRegularCodeObjectSize(), \
133+
code_space->AreaSize())))
132134

133135
using FreeListCategoryType = int32_t;
134136

deps/v8/src/utils/allocation.cc

+1-2
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ void* GetRandomMmapAddr() {
165165
void* AllocatePages(v8::PageAllocator* page_allocator, void* hint, size_t size,
166166
size_t alignment, PageAllocator::Permission access) {
167167
DCHECK_NOT_NULL(page_allocator);
168-
DCHECK_EQ(hint, AlignedAddress(hint, alignment));
169-
DCHECK(IsAligned(size, page_allocator->AllocatePageSize()));
168+
DCHECK(IsAligned(size, page_allocator->CommitPageSize()));
170169
if (FLAG_randomize_all_allocations) {
171170
hint = page_allocator->GetRandomMmapAddr();
172171
}

deps/v8/test/cctest/heap/heap-tester.h

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
V(InvalidatedSlotsSomeInvalidatedRanges) \
3535
V(TestNewSpaceRefsInCopiedCode) \
3636
V(GCFlags) \
37+
V(CodeLargeObjectSpace64k) \
3738
V(MarkCompactCollector) \
3839
V(MarkCompactEpochCounter) \
3940
V(MemoryReducerActivationForSmallHeaps) \

deps/v8/test/cctest/heap/test-heap.cc

+83-2
Original file line numberDiff line numberDiff line change
@@ -6404,7 +6404,7 @@ HEAP_TEST(Regress5831) {
64046404

64056405
// Generate the code.
64066406
Handle<Code> code = GenerateDummyImmovableCode(isolate);
6407-
CHECK_GE(i::kMaxRegularHeapObjectSize, code->Size());
6407+
CHECK_GE(MemoryChunkLayout::MaxRegularCodeObjectSize(), code->Size());
64086408
CHECK(!heap->code_space()->first_page()->Contains(code->address()));
64096409

64106410
// Ensure it's not in large object space.
@@ -6889,7 +6889,7 @@ TEST(CodeObjectRegistry) {
68896889
{
68906890
// Ensure that both code objects end up on the same page.
68916891
CHECK(HeapTester::CodeEnsureLinearAllocationArea(
6892-
heap, kMaxRegularHeapObjectSize));
6892+
heap, MemoryChunkLayout::MaxRegularCodeObjectSize()));
68936893
code1 = DummyOptimizedCode(isolate);
68946894
Handle<Code> code2 = DummyOptimizedCode(isolate);
68956895
code2_address = code2->address();
@@ -7002,6 +7002,87 @@ TEST(Regress978156) {
70027002
marking_state->GreyToBlack(filler);
70037003
}
70047004

7005+
class TestAllocationTracker : public HeapObjectAllocationTracker {
7006+
public:
7007+
explicit TestAllocationTracker(int expected_size)
7008+
: expected_size_(expected_size) {}
7009+
7010+
void AllocationEvent(Address addr, int size) {
7011+
CHECK(expected_size_ == size);
7012+
address_ = addr;
7013+
}
7014+
7015+
Address address() { return address_; }
7016+
7017+
private:
7018+
int expected_size_;
7019+
Address address_;
7020+
};
7021+
7022+
UNINITIALIZED_HEAP_TEST(CodeLargeObjectSpace64k) {
7023+
// Simulate having a system with 64k OS pages.
7024+
i::FLAG_v8_os_page_size = 64;
7025+
7026+
// Initialize the isolate manually to make sure --v8-os-page-size is taken
7027+
// into account.
7028+
v8::Isolate::CreateParams create_params;
7029+
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
7030+
v8::Isolate* isolate = v8::Isolate::New(create_params);
7031+
7032+
Heap* heap = reinterpret_cast<Isolate*>(isolate)->heap();
7033+
7034+
// Allocate a regular code object.
7035+
{
7036+
int size_in_bytes =
7037+
MemoryChunkLayout::MaxRegularCodeObjectSize() - kTaggedSize;
7038+
TestAllocationTracker allocation_tracker{size_in_bytes};
7039+
heap->AddHeapObjectAllocationTracker(&allocation_tracker);
7040+
7041+
HeapObject obj;
7042+
{
7043+
AllocationResult allocation = heap->AllocateRaw(
7044+
size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime,
7045+
AllocationAlignment::kCodeAligned);
7046+
CHECK(allocation.To(&obj));
7047+
CHECK_EQ(allocation.ToObjectChecked().address(),
7048+
allocation_tracker.address());
7049+
7050+
heap->CreateFillerObjectAt(obj.address(), size_in_bytes,
7051+
ClearRecordedSlots::kNo);
7052+
}
7053+
7054+
CHECK(!Heap::IsLargeObject(obj));
7055+
heap->RemoveHeapObjectAllocationTracker(&allocation_tracker);
7056+
}
7057+
7058+
// Allocate a large code object.
7059+
{
7060+
int size_in_bytes =
7061+
MemoryChunkLayout::MaxRegularCodeObjectSize() + kTaggedSize;
7062+
TestAllocationTracker allocation_tracker{size_in_bytes};
7063+
heap->AddHeapObjectAllocationTracker(&allocation_tracker);
7064+
7065+
HeapObject obj;
7066+
{
7067+
AllocationResult allocation = heap->AllocateRaw(
7068+
size_in_bytes, AllocationType::kCode, AllocationOrigin::kRuntime,
7069+
AllocationAlignment::kCodeAligned);
7070+
CHECK(allocation.To(&obj));
7071+
CHECK_EQ(allocation.ToObjectChecked().address(),
7072+
allocation_tracker.address());
7073+
7074+
heap->CreateFillerObjectAt(obj.address(), size_in_bytes,
7075+
ClearRecordedSlots::kNo);
7076+
}
7077+
7078+
CHECK(Heap::IsLargeObject(obj));
7079+
heap->RemoveHeapObjectAllocationTracker(&allocation_tracker);
7080+
}
7081+
7082+
isolate->Dispose();
7083+
}
7084+
7085+
70057086
} // namespace heap
70067087
} // namespace internal
70077088
} // namespace v8

deps/v8/test/cctest/test-code-pages.cc

+3-3
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ TEST(LargeCodeObject) {
263263

264264
// Create a big function that ends up in CODE_LO_SPACE.
265265
const int instruction_size = Page::kPageSize + 1;
266-
STATIC_ASSERT(instruction_size > kMaxRegularHeapObjectSize);
266+
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
267267
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
268268

269269
CodeDesc desc;
@@ -379,7 +379,7 @@ TEST(LargeCodeObjectWithSignalHandler) {
379379

380380
// Create a big function that ends up in CODE_LO_SPACE.
381381
const int instruction_size = Page::kPageSize + 1;
382-
STATIC_ASSERT(instruction_size > kMaxRegularHeapObjectSize);
382+
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
383383
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
384384

385385
CodeDesc desc;
@@ -455,7 +455,7 @@ TEST(Sorted) {
455455

456456
// Create a big function that ends up in CODE_LO_SPACE.
457457
const int instruction_size = Page::kPageSize + 1;
458-
STATIC_ASSERT(instruction_size > kMaxRegularHeapObjectSize);
458+
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
459459
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
460460

461461
CodeDesc desc;

deps/v8/test/cctest/test-factory.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ TEST(Factory_CodeBuilder) {
6060
HandleScope scope(isolate);
6161

6262
// Create a big function that ends up in CODE_LO_SPACE.
63-
const int instruction_size = kMaxRegularHeapObjectSize + 1;
63+
const int instruction_size =
64+
MemoryChunkLayout::MaxRegularCodeObjectSize() + 1;
6465
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
6566

6667
CodeDesc desc;

deps/v8/test/cctest/test-unwinder-code-pages.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ TEST(PCIsInV8_LargeCodeObject_CodePagesAPI) {
564564

565565
// Create a big function that ends up in CODE_LO_SPACE.
566566
const int instruction_size = Page::kPageSize + 1;
567-
STATIC_ASSERT(instruction_size > kMaxRegularHeapObjectSize);
567+
CHECK_GT(instruction_size, MemoryChunkLayout::MaxRegularCodeObjectSize());
568568
std::unique_ptr<byte[]> instructions(new byte[instruction_size]);
569569

570570
CodeDesc desc;

0 commit comments

Comments
 (0)