1// Copyright 2020 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/heap/large-spaces.h"
6
7#include "src/base/platform/mutex.h"
8#include "src/base/sanitizer/msan.h"
9#include "src/common/globals.h"
10#include "src/execution/isolate.h"
11#include "src/heap/combined-heap.h"
12#include "src/heap/incremental-marking.h"
13#include "src/heap/list.h"
14#include "src/heap/marking.h"
15#include "src/heap/memory-allocator.h"
16#include "src/heap/memory-chunk-inl.h"
17#include "src/heap/remembered-set.h"
18#include "src/heap/slot-set.h"
19#include "src/heap/spaces-inl.h"
20#include "src/logging/log.h"
21#include "src/objects/objects-inl.h"
22#include "src/utils/ostreams.h"
23
24namespace v8 {
25namespace internal {
26
27// This check is here to ensure that the lower 32 bits of any real heap object
28// can't overlap with the lower 32 bits of cleared weak reference value and
29// therefore it's enough to compare only the lower 32 bits of a MaybeObject in
30// order to figure out if it's a cleared weak reference or not.
31STATIC_ASSERT(kClearedWeakHeapObjectLower32 < LargePage::kHeaderSize);
32
33LargePage::LargePage(Heap* heap, BaseSpace* space, size_t chunk_size,
34                     Address area_start, Address area_end,
35                     VirtualMemory reservation, Executability executable)
36    : MemoryChunk(heap, space, chunk_size, area_start, area_end,
37                  std::move(reservation), executable, PageSize::kLarge) {
38  STATIC_ASSERT(LargePage::kMaxCodePageSize <= TypedSlotSet::kMaxOffset);
39
40  if (executable && chunk_size > LargePage::kMaxCodePageSize) {
41    FATAL("Code page is too large.");
42  }
43
44  SetFlag(MemoryChunk::LARGE_PAGE);
45  list_node().Initialize();
46}
47
48LargePage* LargePage::Initialize(Heap* heap, MemoryChunk* chunk,
49                                 Executability executable) {
50  if (executable && chunk->size() > LargePage::kMaxCodePageSize) {
51    STATIC_ASSERT(LargePage::kMaxCodePageSize <= TypedSlotSet::kMaxOffset);
52    FATAL("Code page is too large.");
53  }
54
55  MSAN_ALLOCATED_UNINITIALIZED_MEMORY(chunk->area_start(), chunk->area_size());
56
57  LargePage* page = static_cast<LargePage*>(chunk);
58  page->SetFlag(MemoryChunk::LARGE_PAGE);
59  page->list_node().Initialize();
60  return page;
61}
62
63size_t LargeObjectSpace::Available() const {
64  // We return zero here since we cannot take advantage of already allocated
65  // large object memory.
66  return 0;
67}
68
69Address LargePage::GetAddressToShrink(Address object_address,
70                                      size_t object_size) {
71  if (executable() == EXECUTABLE) {
72    return 0;
73  }
74  size_t used_size = ::RoundUp((object_address - address()) + object_size,
75                               MemoryAllocator::GetCommitPageSize());
76  if (used_size < CommittedPhysicalMemory()) {
77    return address() + used_size;
78  }
79  return 0;
80}
81
82void LargePage::ClearOutOfLiveRangeSlots(Address free_start) {
83  RememberedSet<OLD_TO_NEW>::RemoveRange(this, free_start, area_end(),
84                                         SlotSet::FREE_EMPTY_BUCKETS);
85  RememberedSet<OLD_TO_OLD>::RemoveRange(this, free_start, area_end(),
86                                         SlotSet::FREE_EMPTY_BUCKETS);
87  RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(this, free_start, area_end());
88  RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(this, free_start, area_end());
89}
90
91// -----------------------------------------------------------------------------
92// LargeObjectSpaceObjectIterator
93
94LargeObjectSpaceObjectIterator::LargeObjectSpaceObjectIterator(
95    LargeObjectSpace* space) {
96  current_ = space->first_page();
97}
98
99HeapObject LargeObjectSpaceObjectIterator::Next() {
100  if (current_ == nullptr) return HeapObject();
101
102  HeapObject object = current_->GetObject();
103  current_ = current_->next_page();
104  return object;
105}
106
107// -----------------------------------------------------------------------------
108// OldLargeObjectSpace
109
110LargeObjectSpace::LargeObjectSpace(Heap* heap, AllocationSpace id)
111    : Space(heap, id, new NoFreeList()),
112      size_(0),
113      page_count_(0),
114      objects_size_(0),
115      pending_object_(0) {}
116
117void LargeObjectSpace::TearDown() {
118  while (!memory_chunk_list_.Empty()) {
119    LargePage* page = first_page();
120    LOG(heap()->isolate(),
121        DeleteEvent("LargeObjectChunk",
122                    reinterpret_cast<void*>(page->address())));
123    memory_chunk_list_.Remove(page);
124    heap()->memory_allocator()->Free(MemoryAllocator::FreeMode::kImmediately,
125                                     page);
126  }
127}
128
129void LargeObjectSpace::AdvanceAndInvokeAllocationObservers(Address soon_object,
130                                                           size_t object_size) {
131  if (!allocation_counter_.IsActive()) return;
132
133  if (object_size >= allocation_counter_.NextBytes()) {
134    allocation_counter_.InvokeAllocationObservers(soon_object, object_size,
135                                                  object_size);
136  }
137
138  // Large objects can be accounted immediately since no LAB is involved.
139  allocation_counter_.AdvanceAllocationObservers(object_size);
140}
141
142AllocationResult OldLargeObjectSpace::AllocateRaw(int object_size) {
143  return AllocateRaw(object_size, NOT_EXECUTABLE);
144}
145
146AllocationResult OldLargeObjectSpace::AllocateRaw(int object_size,
147                                                  Executability executable) {
148  DCHECK(!FLAG_enable_third_party_heap);
149  // Check if we want to force a GC before growing the old space further.
150  // If so, fail the allocation.
151  if (!heap()->CanExpandOldGeneration(object_size) ||
152      !heap()->ShouldExpandOldGenerationOnSlowAllocation()) {
153    return AllocationResult::Failure();
154  }
155
156  LargePage* page = AllocateLargePage(object_size, executable);
157  if (page == nullptr) return AllocationResult::Failure();
158  page->SetOldGenerationPageFlags(heap()->incremental_marking()->IsMarking());
159  HeapObject object = page->GetObject();
160  UpdatePendingObject(object);
161  heap()->StartIncrementalMarkingIfAllocationLimitIsReached(
162      heap()->GCFlagsForIncrementalMarking(),
163      kGCCallbackScheduleIdleGarbageCollection);
164  if (heap()->incremental_marking()->black_allocation()) {
165    heap()->incremental_marking()->marking_state()->WhiteToBlack(object);
166  }
167  DCHECK_IMPLIES(
168      heap()->incremental_marking()->black_allocation(),
169      heap()->incremental_marking()->marking_state()->IsBlack(object));
170  page->InitializationMemoryFence();
171  heap()->NotifyOldGenerationExpansion(identity(), page);
172  AdvanceAndInvokeAllocationObservers(object.address(),
173                                      static_cast<size_t>(object_size));
174  return AllocationResult::FromObject(object);
175}
176
177AllocationResult OldLargeObjectSpace::AllocateRawBackground(
178    LocalHeap* local_heap, int object_size) {
179  return AllocateRawBackground(local_heap, object_size, NOT_EXECUTABLE);
180}
181
182AllocationResult OldLargeObjectSpace::AllocateRawBackground(
183    LocalHeap* local_heap, int object_size, Executability executable) {
184  DCHECK(!FLAG_enable_third_party_heap);
185  // Check if we want to force a GC before growing the old space further.
186  // If so, fail the allocation.
187  if (!heap()->CanExpandOldGenerationBackground(local_heap, object_size) ||
188      !heap()->ShouldExpandOldGenerationOnSlowAllocation(local_heap)) {
189    return AllocationResult::Failure();
190  }
191
192  LargePage* page = AllocateLargePage(object_size, executable);
193  if (page == nullptr) return AllocationResult::Failure();
194  page->SetOldGenerationPageFlags(heap()->incremental_marking()->IsMarking());
195  HeapObject object = page->GetObject();
196  heap()->StartIncrementalMarkingIfAllocationLimitIsReachedBackground();
197  if (heap()->incremental_marking()->black_allocation()) {
198    heap()->incremental_marking()->marking_state()->WhiteToBlack(object);
199  }
200  DCHECK_IMPLIES(
201      heap()->incremental_marking()->black_allocation(),
202      heap()->incremental_marking()->marking_state()->IsBlack(object));
203  page->InitializationMemoryFence();
204  if (identity() == CODE_LO_SPACE) {
205    heap()->isolate()->AddCodeMemoryChunk(page);
206  }
207  return AllocationResult::FromObject(object);
208}
209
210LargePage* LargeObjectSpace::AllocateLargePage(int object_size,
211                                               Executability executable) {
212  LargePage* page = heap()->memory_allocator()->AllocateLargePage(
213      this, object_size, executable);
214  if (page == nullptr) return nullptr;
215  DCHECK_GE(page->area_size(), static_cast<size_t>(object_size));
216
217  {
218    base::MutexGuard guard(&allocation_mutex_);
219    AddPage(page, object_size);
220  }
221
222  HeapObject object = page->GetObject();
223
224  heap()->CreateFillerObjectAt(object.address(), object_size,
225                               ClearRecordedSlots::kNo);
226  return page;
227}
228
229size_t LargeObjectSpace::CommittedPhysicalMemory() const {
230  // On a platform that provides lazy committing of memory, we over-account
231  // the actually committed memory. There is no easy way right now to support
232  // precise accounting of committed memory in large object space.
233  return CommittedMemory();
234}
235
236LargePage* CodeLargeObjectSpace::FindPage(Address a) {
237  base::MutexGuard guard(&allocation_mutex_);
238  const Address key = BasicMemoryChunk::FromAddress(a)->address();
239  auto it = chunk_map_.find(key);
240  if (it != chunk_map_.end()) {
241    LargePage* page = it->second;
242    CHECK(page->Contains(a));
243    return page;
244  }
245  return nullptr;
246}
247
248void OldLargeObjectSpace::ClearMarkingStateOfLiveObjects() {
249  IncrementalMarking::NonAtomicMarkingState* marking_state =
250      heap()->incremental_marking()->non_atomic_marking_state();
251  LargeObjectSpaceObjectIterator it(this);
252  for (HeapObject obj = it.Next(); !obj.is_null(); obj = it.Next()) {
253    if (marking_state->IsBlackOrGrey(obj)) {
254      Marking::MarkWhite(marking_state->MarkBitFrom(obj));
255      MemoryChunk* chunk = MemoryChunk::FromHeapObject(obj);
256      RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
257      chunk->ProgressBar().ResetIfEnabled();
258      marking_state->SetLiveBytes(chunk, 0);
259    }
260    DCHECK(marking_state->IsWhite(obj));
261  }
262}
263
264void CodeLargeObjectSpace::InsertChunkMapEntries(LargePage* page) {
265  for (Address current = reinterpret_cast<Address>(page);
266       current < reinterpret_cast<Address>(page) + page->size();
267       current += MemoryChunk::kPageSize) {
268    chunk_map_[current] = page;
269  }
270}
271
272void CodeLargeObjectSpace::RemoveChunkMapEntries(LargePage* page) {
273  for (Address current = page->address();
274       current < reinterpret_cast<Address>(page) + page->size();
275       current += MemoryChunk::kPageSize) {
276    chunk_map_.erase(current);
277  }
278}
279
280void OldLargeObjectSpace::PromoteNewLargeObject(LargePage* page) {
281  DCHECK_EQ(page->owner_identity(), NEW_LO_SPACE);
282  DCHECK(page->IsLargePage());
283  DCHECK(page->IsFlagSet(MemoryChunk::FROM_PAGE));
284  DCHECK(!page->IsFlagSet(MemoryChunk::TO_PAGE));
285  PtrComprCageBase cage_base(heap()->isolate());
286  size_t object_size = static_cast<size_t>(page->GetObject().Size(cage_base));
287  static_cast<LargeObjectSpace*>(page->owner())->RemovePage(page, object_size);
288  page->ClearFlag(MemoryChunk::FROM_PAGE);
289  AddPage(page, object_size);
290}
291
292void LargeObjectSpace::AddPage(LargePage* page, size_t object_size) {
293  size_ += static_cast<int>(page->size());
294  AccountCommitted(page->size());
295  objects_size_ += object_size;
296  page_count_++;
297  memory_chunk_list_.PushBack(page);
298  page->set_owner(this);
299  page->SetOldGenerationPageFlags(!is_off_thread() &&
300                                  heap()->incremental_marking()->IsMarking());
301}
302
303void LargeObjectSpace::RemovePage(LargePage* page, size_t object_size) {
304  size_ -= static_cast<int>(page->size());
305  AccountUncommitted(page->size());
306  objects_size_ -= object_size;
307  page_count_--;
308  memory_chunk_list_.Remove(page);
309  page->set_owner(nullptr);
310}
311
312void LargeObjectSpace::FreeUnmarkedObjects() {
313  LargePage* current = first_page();
314  IncrementalMarking::NonAtomicMarkingState* marking_state =
315      heap()->incremental_marking()->non_atomic_marking_state();
316  // Right-trimming does not update the objects_size_ counter. We are lazily
317  // updating it after every GC.
318  size_t surviving_object_size = 0;
319  PtrComprCageBase cage_base(heap()->isolate());
320  while (current) {
321    LargePage* next_current = current->next_page();
322    HeapObject object = current->GetObject();
323    DCHECK(!marking_state->IsGrey(object));
324    size_t size = static_cast<size_t>(object.Size(cage_base));
325    if (marking_state->IsBlack(object)) {
326      Address free_start;
327      surviving_object_size += size;
328      if ((free_start = current->GetAddressToShrink(object.address(), size)) !=
329          0) {
330        DCHECK(!current->IsFlagSet(Page::IS_EXECUTABLE));
331        current->ClearOutOfLiveRangeSlots(free_start);
332        const size_t bytes_to_free =
333            current->size() - (free_start - current->address());
334        heap()->memory_allocator()->PartialFreeMemory(
335            current, free_start, bytes_to_free,
336            current->area_start() + object.Size(cage_base));
337        size_ -= bytes_to_free;
338        AccountUncommitted(bytes_to_free);
339      }
340    } else {
341      RemovePage(current, size);
342      heap()->memory_allocator()->Free(MemoryAllocator::FreeMode::kConcurrently,
343                                       current);
344    }
345    current = next_current;
346  }
347  objects_size_ = surviving_object_size;
348}
349
350bool LargeObjectSpace::Contains(HeapObject object) const {
351  BasicMemoryChunk* chunk = BasicMemoryChunk::FromHeapObject(object);
352
353  bool owned = (chunk->owner() == this);
354
355  SLOW_DCHECK(!owned || ContainsSlow(object.address()));
356
357  return owned;
358}
359
360bool LargeObjectSpace::ContainsSlow(Address addr) const {
361  for (const LargePage* page : *this) {
362    if (page->Contains(addr)) return true;
363  }
364  return false;
365}
366
367std::unique_ptr<ObjectIterator> LargeObjectSpace::GetObjectIterator(
368    Heap* heap) {
369  return std::unique_ptr<ObjectIterator>(
370      new LargeObjectSpaceObjectIterator(this));
371}
372
373#ifdef VERIFY_HEAP
374// We do not assume that the large object iterator works, because it depends
375// on the invariants we are checking during verification.
376void LargeObjectSpace::Verify(Isolate* isolate) {
377  size_t external_backing_store_bytes[kNumTypes];
378
379  for (int i = 0; i < kNumTypes; i++) {
380    external_backing_store_bytes[static_cast<ExternalBackingStoreType>(i)] = 0;
381  }
382
383  PtrComprCageBase cage_base(isolate);
384  for (LargePage* chunk = first_page(); chunk != nullptr;
385       chunk = chunk->next_page()) {
386    // Each chunk contains an object that starts at the large object page's
387    // object area start.
388    HeapObject object = chunk->GetObject();
389    Page* page = Page::FromHeapObject(object);
390    CHECK(object.address() == page->area_start());
391
392    // The first word should be a map, and we expect all map pointers to be
393    // in map space or read-only space.
394    Map map = object.map(cage_base);
395    CHECK(map.IsMap(cage_base));
396    CHECK(ReadOnlyHeap::Contains(map) ||
397          isolate->heap()->space_for_maps()->Contains(map));
398
399    // We have only the following types in the large object space:
400    const bool is_valid_lo_space_object =                         //
401        object.IsAbstractCode(cage_base) ||                       //
402        object.IsBigInt(cage_base) ||                             //
403        object.IsByteArray(cage_base) ||                          //
404        object.IsContext(cage_base) ||                            //
405        object.IsExternalString(cage_base) ||                     //
406        object.IsFeedbackMetadata(cage_base) ||                   //
407        object.IsFeedbackVector(cage_base) ||                     //
408        object.IsFixedArray(cage_base) ||                         //
409        object.IsFixedDoubleArray(cage_base) ||                   //
410        object.IsFreeSpace(cage_base) ||                          //
411        object.IsPreparseData(cage_base) ||                       //
412        object.IsPropertyArray(cage_base) ||                      //
413        object.IsScopeInfo() ||                                   //
414        object.IsSeqString(cage_base) ||                          //
415        object.IsSloppyArgumentsElements(cage_base) ||            //
416        object.IsSwissNameDictionary() ||                         //
417        object.IsThinString(cage_base) ||                         //
418        object.IsUncompiledDataWithoutPreparseData(cage_base) ||  //
419#if V8_ENABLE_WEBASSEMBLY                                         //
420        object.IsWasmArray() ||                                   //
421#endif                                                            //
422        object.IsWeakArrayList(cage_base) ||                      //
423        object.IsWeakFixedArray(cage_base);
424    if (!is_valid_lo_space_object) {
425      object.Print();
426      FATAL("Found invalid Object (instance_type=%i) in large object space.",
427            object.map(cage_base).instance_type());
428    }
429
430    // The object itself should look OK.
431    object.ObjectVerify(isolate);
432
433    if (!FLAG_verify_heap_skip_remembered_set) {
434      heap()->VerifyRememberedSetFor(object);
435    }
436
437    // Byte arrays and strings don't have interior pointers.
438    if (object.IsAbstractCode(cage_base)) {
439      VerifyPointersVisitor code_visitor(heap());
440      object.IterateBody(map, object.Size(cage_base), &code_visitor);
441    } else if (object.IsFixedArray(cage_base)) {
442      FixedArray array = FixedArray::cast(object);
443      for (int j = 0; j < array.length(); j++) {
444        Object element = array.get(j);
445        if (element.IsHeapObject()) {
446          HeapObject element_object = HeapObject::cast(element);
447          CHECK(IsValidHeapObject(heap(), element_object));
448          CHECK(element_object.map(cage_base).IsMap(cage_base));
449        }
450      }
451    } else if (object.IsPropertyArray(cage_base)) {
452      PropertyArray array = PropertyArray::cast(object);
453      for (int j = 0; j < array.length(); j++) {
454        Object property = array.get(j);
455        if (property.IsHeapObject()) {
456          HeapObject property_object = HeapObject::cast(property);
457          CHECK(heap()->Contains(property_object));
458          CHECK(property_object.map(cage_base).IsMap(cage_base));
459        }
460      }
461    }
462    for (int i = 0; i < kNumTypes; i++) {
463      ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i);
464      external_backing_store_bytes[t] += chunk->ExternalBackingStoreBytes(t);
465    }
466
467    CHECK(!chunk->IsFlagSet(Page::PAGE_NEW_OLD_PROMOTION));
468    CHECK(!chunk->IsFlagSet(Page::PAGE_NEW_NEW_PROMOTION));
469  }
470  for (int i = 0; i < kNumTypes; i++) {
471    ExternalBackingStoreType t = static_cast<ExternalBackingStoreType>(i);
472    CHECK_EQ(external_backing_store_bytes[t], ExternalBackingStoreBytes(t));
473  }
474}
475#endif
476
477#ifdef DEBUG
478void LargeObjectSpace::Print() {
479  StdoutStream os;
480  LargeObjectSpaceObjectIterator it(this);
481  for (HeapObject obj = it.Next(); !obj.is_null(); obj = it.Next()) {
482    obj.Print(os);
483  }
484}
485#endif  // DEBUG
486
487void LargeObjectSpace::UpdatePendingObject(HeapObject object) {
488  base::SharedMutexGuard<base::kExclusive> guard(&pending_allocation_mutex_);
489  pending_object_.store(object.address(), std::memory_order_release);
490}
491
492OldLargeObjectSpace::OldLargeObjectSpace(Heap* heap)
493    : LargeObjectSpace(heap, LO_SPACE) {}
494
495OldLargeObjectSpace::OldLargeObjectSpace(Heap* heap, AllocationSpace id)
496    : LargeObjectSpace(heap, id) {}
497
498NewLargeObjectSpace::NewLargeObjectSpace(Heap* heap, size_t capacity)
499    : LargeObjectSpace(heap, NEW_LO_SPACE),
500      capacity_(capacity) {}
501
502AllocationResult NewLargeObjectSpace::AllocateRaw(int object_size) {
503  DCHECK(!FLAG_enable_third_party_heap);
504  // Do not allocate more objects if promoting the existing object would exceed
505  // the old generation capacity.
506  if (!heap()->CanExpandOldGeneration(SizeOfObjects())) {
507    return AllocationResult::Failure();
508  }
509
510  // Allocation for the first object must succeed independent from the capacity.
511  if (SizeOfObjects() > 0 && static_cast<size_t>(object_size) > Available()) {
512    return AllocationResult::Failure();
513  }
514
515  LargePage* page = AllocateLargePage(object_size, NOT_EXECUTABLE);
516  if (page == nullptr) return AllocationResult::Failure();
517
518  // The size of the first object may exceed the capacity.
519  capacity_ = std::max(capacity_, SizeOfObjects());
520
521  HeapObject result = page->GetObject();
522  page->SetYoungGenerationPageFlags(heap()->incremental_marking()->IsMarking());
523  page->SetFlag(MemoryChunk::TO_PAGE);
524  UpdatePendingObject(result);
525  if (FLAG_minor_mc) {
526    page->AllocateYoungGenerationBitmap();
527    heap()
528        ->minor_mark_compact_collector()
529        ->non_atomic_marking_state()
530        ->ClearLiveness(page);
531  }
532  page->InitializationMemoryFence();
533  DCHECK(page->IsLargePage());
534  DCHECK_EQ(page->owner_identity(), NEW_LO_SPACE);
535  AdvanceAndInvokeAllocationObservers(result.address(),
536                                      static_cast<size_t>(object_size));
537  return AllocationResult::FromObject(result);
538}
539
540size_t NewLargeObjectSpace::Available() const {
541  return capacity_ - SizeOfObjects();
542}
543
544void NewLargeObjectSpace::Flip() {
545  for (LargePage* chunk = first_page(); chunk != nullptr;
546       chunk = chunk->next_page()) {
547    chunk->SetFlag(MemoryChunk::FROM_PAGE);
548    chunk->ClearFlag(MemoryChunk::TO_PAGE);
549  }
550}
551
552void NewLargeObjectSpace::FreeDeadObjects(
553    const std::function<bool(HeapObject)>& is_dead) {
554  bool is_marking = heap()->incremental_marking()->IsMarking();
555  size_t surviving_object_size = 0;
556  bool freed_pages = false;
557  PtrComprCageBase cage_base(heap()->isolate());
558  for (auto it = begin(); it != end();) {
559    LargePage* page = *it;
560    it++;
561    HeapObject object = page->GetObject();
562    size_t size = static_cast<size_t>(object.Size(cage_base));
563    if (is_dead(object)) {
564      freed_pages = true;
565      RemovePage(page, size);
566      heap()->memory_allocator()->Free(MemoryAllocator::FreeMode::kConcurrently,
567                                       page);
568      if (FLAG_concurrent_marking && is_marking) {
569        heap()->concurrent_marking()->ClearMemoryChunkData(page);
570      }
571    } else {
572      surviving_object_size += size;
573    }
574  }
575  // Right-trimming does not update the objects_size_ counter. We are lazily
576  // updating it after every GC.
577  objects_size_ = surviving_object_size;
578  if (freed_pages) {
579    heap()->memory_allocator()->unmapper()->FreeQueuedChunks();
580  }
581}
582
583void NewLargeObjectSpace::SetCapacity(size_t capacity) {
584  capacity_ = std::max(capacity, SizeOfObjects());
585}
586
587CodeLargeObjectSpace::CodeLargeObjectSpace(Heap* heap)
588    : OldLargeObjectSpace(heap, CODE_LO_SPACE),
589      chunk_map_(kInitialChunkMapCapacity) {}
590
591AllocationResult CodeLargeObjectSpace::AllocateRaw(int object_size) {
592  DCHECK(!FLAG_enable_third_party_heap);
593  return OldLargeObjectSpace::AllocateRaw(object_size, EXECUTABLE);
594}
595
596AllocationResult CodeLargeObjectSpace::AllocateRawBackground(
597    LocalHeap* local_heap, int object_size) {
598  DCHECK(!FLAG_enable_third_party_heap);
599  return OldLargeObjectSpace::AllocateRawBackground(local_heap, object_size,
600                                                    EXECUTABLE);
601}
602
603void CodeLargeObjectSpace::AddPage(LargePage* page, size_t object_size) {
604  OldLargeObjectSpace::AddPage(page, object_size);
605  InsertChunkMapEntries(page);
606}
607
608void CodeLargeObjectSpace::RemovePage(LargePage* page, size_t object_size) {
609  RemoveChunkMapEntries(page);
610  heap()->isolate()->RemoveCodeMemoryChunk(page);
611  OldLargeObjectSpace::RemovePage(page, object_size);
612}
613
614}  // namespace internal
615}  // namespace v8
616