%PDF- %PDF-
Mini Shell

Mini Shell

Direktori : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/heap/
Upload File :
Create Path :
Current File : /home/vacivi36/vittasync.vacivitta.com.br/vittasync/node/deps/v8/src/heap/main-allocator.cc

// Copyright 2023 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/heap/main-allocator-inl.h"
#include "src/heap/spaces.h"

namespace v8 {
namespace internal {

MainAllocator::MainAllocator(Heap* heap, SpaceWithLinearArea* space,
                             CompactionSpaceKind compaction_space_kind,
                             SupportsExtendingLAB supports_extending_lab,
                             LinearAllocationArea& allocation_info)
    : heap_(heap),
      space_(space),
      compaction_space_kind_(compaction_space_kind),
      supports_extending_lab_(supports_extending_lab),
      allocation_info_(allocation_info) {}

MainAllocator::MainAllocator(Heap* heap, SpaceWithLinearArea* space,
                             CompactionSpaceKind compaction_space_kind,
                             SupportsExtendingLAB supports_extending_lab)
    : heap_(heap),
      space_(space),
      compaction_space_kind_(compaction_space_kind),
      supports_extending_lab_(supports_extending_lab),
      allocation_info_(owned_allocation_info_) {}

AllocationResult MainAllocator::AllocateRawForceAlignmentForTesting(
    int size_in_bytes, AllocationAlignment alignment, AllocationOrigin origin) {
  size_in_bytes = ALIGN_TO_ALLOCATION_ALIGNMENT(size_in_bytes);

  AllocationResult result =
      AllocateFastAligned(size_in_bytes, nullptr, alignment, origin);

  return V8_UNLIKELY(result.IsFailure())
             ? AllocateRawSlowAligned(size_in_bytes, alignment, origin)
             : result;
}

void MainAllocator::AddAllocationObserver(AllocationObserver* observer) {
  if (!allocation_counter().IsStepInProgress()) {
    AdvanceAllocationObservers();
    allocation_counter().AddAllocationObserver(observer);
    UpdateInlineAllocationLimit();
  } else {
    allocation_counter().AddAllocationObserver(observer);
  }
}

void MainAllocator::RemoveAllocationObserver(AllocationObserver* observer) {
  if (!allocation_counter().IsStepInProgress()) {
    AdvanceAllocationObservers();
    allocation_counter().RemoveAllocationObserver(observer);
    UpdateInlineAllocationLimit();
  } else {
    allocation_counter().RemoveAllocationObserver(observer);
  }
}

void MainAllocator::PauseAllocationObservers() { AdvanceAllocationObservers(); }

void MainAllocator::ResumeAllocationObservers() {
  MarkLabStartInitialized();
  UpdateInlineAllocationLimit();
}

void MainAllocator::AdvanceAllocationObservers() {
  if (allocation_info().top() &&
      allocation_info().start() != allocation_info().top()) {
    if (heap()->IsAllocationObserverActive()) {
      allocation_counter().AdvanceAllocationObservers(
          allocation_info().top() - allocation_info().start());
    }
    MarkLabStartInitialized();
  }
}

void MainAllocator::MarkLabStartInitialized() {
  allocation_info().ResetStart();
  if (identity() == NEW_SPACE) {
    MoveOriginalTopForward();

#if DEBUG
    Verify();
#endif
  }
}

// Perform an allocation step when the step is reached. size_in_bytes is the
// actual size needed for the object (required for InvokeAllocationObservers).
// aligned_size_in_bytes is the size of the object including the filler right
// before it to reach the right alignment (required to DCHECK the start of the
// object). allocation_size is the size of the actual allocation which needs to
// be used for the accounting. It can be different from aligned_size_in_bytes in
// PagedSpace::AllocateRawAligned, where we have to overallocate in order to be
// able to align the allocation afterwards.
void MainAllocator::InvokeAllocationObservers(Address soon_object,
                                              size_t size_in_bytes,
                                              size_t aligned_size_in_bytes,
                                              size_t allocation_size) {
  DCHECK_LE(size_in_bytes, aligned_size_in_bytes);
  DCHECK_LE(aligned_size_in_bytes, allocation_size);
  DCHECK(size_in_bytes == aligned_size_in_bytes ||
         aligned_size_in_bytes == allocation_size);

  if (!SupportsAllocationObserver() || !heap()->IsAllocationObserverActive())
    return;

  if (allocation_size >= allocation_counter().NextBytes()) {
    // Only the first object in a LAB should reach the next step.
    DCHECK_EQ(soon_object, allocation_info().start() + aligned_size_in_bytes -
                               size_in_bytes);

    // Right now the LAB only contains that one object.
    DCHECK_EQ(allocation_info().top() + allocation_size - aligned_size_in_bytes,
              allocation_info().limit());

    // Ensure that there is a valid object
    heap_->CreateFillerObjectAt(soon_object, static_cast<int>(size_in_bytes));

#if DEBUG
    // Ensure that allocation_info_ isn't modified during one of the
    // AllocationObserver::Step methods.
    LinearAllocationArea saved_allocation_info = allocation_info();
#endif

    // Run AllocationObserver::Step through the AllocationCounter.
    allocation_counter().InvokeAllocationObservers(soon_object, size_in_bytes,
                                                   allocation_size);

    // Ensure that start/top/limit didn't change.
    DCHECK_EQ(saved_allocation_info.start(), allocation_info().start());
    DCHECK_EQ(saved_allocation_info.top(), allocation_info().top());
    DCHECK_EQ(saved_allocation_info.limit(), allocation_info().limit());
  }

  DCHECK_LT(allocation_info().limit() - allocation_info().start(),
            allocation_counter().NextBytes());
}

AllocationResult MainAllocator::AllocateRawSlow(int size_in_bytes,
                                                AllocationAlignment alignment,
                                                AllocationOrigin origin) {
  AllocationResult result =
      USE_ALLOCATION_ALIGNMENT_BOOL && alignment != kTaggedAligned
          ? AllocateRawSlowAligned(size_in_bytes, alignment, origin)
          : AllocateRawSlowUnaligned(size_in_bytes, origin);
  return result;
}

AllocationResult MainAllocator::AllocateRawSlowUnaligned(
    int size_in_bytes, AllocationOrigin origin) {
  DCHECK(!v8_flags.enable_third_party_heap);
  int max_aligned_size;
  if (!EnsureAllocation(size_in_bytes, kTaggedAligned, origin,
                        &max_aligned_size)) {
    return AllocationResult::Failure();
  }

  DCHECK_EQ(max_aligned_size, size_in_bytes);
  DCHECK_LE(allocation_info().start(), allocation_info().top());

  AllocationResult result = AllocateFastUnaligned(size_in_bytes, origin);
  DCHECK(!result.IsFailure());

  InvokeAllocationObservers(result.ToAddress(), size_in_bytes, size_in_bytes,
                            size_in_bytes);

  return result;
}

AllocationResult MainAllocator::AllocateRawSlowAligned(
    int size_in_bytes, AllocationAlignment alignment, AllocationOrigin origin) {
  DCHECK(!v8_flags.enable_third_party_heap);
  int max_aligned_size;
  if (!EnsureAllocation(size_in_bytes, alignment, origin, &max_aligned_size)) {
    return AllocationResult::Failure();
  }

  DCHECK_GE(max_aligned_size, size_in_bytes);
  DCHECK_LE(allocation_info().start(), allocation_info().top());

  int aligned_size_in_bytes;

  AllocationResult result = AllocateFastAligned(
      size_in_bytes, &aligned_size_in_bytes, alignment, origin);
  DCHECK_GE(max_aligned_size, aligned_size_in_bytes);
  DCHECK(!result.IsFailure());

  InvokeAllocationObservers(result.ToAddress(), size_in_bytes,
                            aligned_size_in_bytes, max_aligned_size);

  return result;
}

void MainAllocator::MakeLinearAllocationAreaIterable() {
  Address current_top = top();
  Address current_limit = original_limit_relaxed();
  DCHECK_GE(current_limit, limit());
  if (current_top != kNullAddress && current_top != current_limit) {
    heap_->CreateFillerObjectAt(current_top,
                                static_cast<int>(current_limit - current_top));
  }
}

void MainAllocator::MarkLinearAllocationAreaBlack() {
  DCHECK(heap()->incremental_marking()->black_allocation());
  Address current_top = top();
  Address current_limit = limit();
  if (current_top != kNullAddress && current_top != current_limit) {
    Page::FromAllocationAreaAddress(current_top)
        ->CreateBlackArea(current_top, current_limit);
  }
}

void MainAllocator::UnmarkLinearAllocationArea() {
  Address current_top = top();
  Address current_limit = limit();
  if (current_top != kNullAddress && current_top != current_limit) {
    Page::FromAllocationAreaAddress(current_top)
        ->DestroyBlackArea(current_top, current_limit);
  }
}

void MainAllocator::MoveOriginalTopForward() {
  DCHECK(!is_compaction_space());
  base::SharedMutexGuard<base::kExclusive> guard(
      linear_area_original_data_.linear_area_lock());
  DCHECK_GE(top(), linear_area_original_data_.get_original_top_acquire());
  DCHECK_LE(top(), linear_area_original_data_.get_original_limit_relaxed());
  linear_area_original_data_.set_original_top_release(top());
}

void MainAllocator::ResetLab(Address start, Address end, Address extended_end) {
  DCHECK_LE(start, end);
  DCHECK_LE(end, extended_end);

  allocation_info().Reset(start, end);

  base::Optional<base::SharedMutexGuard<base::kExclusive>> guard;
  if (!is_compaction_space())
    guard.emplace(linear_area_original_data_.linear_area_lock());
  linear_area_original_data().set_original_limit_relaxed(extended_end);
  linear_area_original_data().set_original_top_release(start);
}

bool MainAllocator::IsPendingAllocation(Address object_address) {
  DCHECK(!is_compaction_space());
  base::SharedMutexGuard<base::kShared> guard(
      linear_area_original_data_.linear_area_lock());
  Address top = original_top_acquire();
  Address limit = original_limit_relaxed();
  DCHECK_LE(top, limit);
  return top && top <= object_address && object_address < limit;
}

void MainAllocator::MaybeFreeUnusedLab(LinearAllocationArea lab) {
  DCHECK(!is_compaction_space());

  if (allocation_info().MergeIfAdjacent(lab)) {
    base::SharedMutexGuard<base::kExclusive> guard(
        linear_area_original_data_.linear_area_lock());
    linear_area_original_data().set_original_top_release(
        allocation_info().top());
  }

#if DEBUG
  Verify();
#endif
}

bool MainAllocator::EnsureAllocation(int size_in_bytes,
                                     AllocationAlignment alignment,
                                     AllocationOrigin origin,
                                     int* out_max_aligned_size) {
  return space_->EnsureAllocation(size_in_bytes, alignment, origin,
                                  out_max_aligned_size);
}

void MainAllocator::UpdateInlineAllocationLimit() {
  return space_->UpdateInlineAllocationLimit();
}

void MainAllocator::FreeLinearAllocationArea() {
  space_->FreeLinearAllocationArea();
}

void MainAllocator::ExtendLAB(Address limit) {
  DCHECK(supports_extending_lab());
  DCHECK_LE(limit, original_limit_relaxed());
  allocation_info().SetLimit(limit);
}

Address MainAllocator::ComputeLimit(Address start, Address end,
                                    size_t min_size) const {
  DCHECK_GE(end - start, min_size);

  // During GCs we always use the full LAB.
  if (heap()->IsInGC()) return end;

  if (!heap()->IsInlineAllocationEnabled()) {
    // LABs are disabled, so we fit the requested area exactly.
    return start + min_size;
  }

  // When LABs are enabled, pick the largest possible LAB size by default.
  size_t step_size = end - start;

  if (SupportsAllocationObserver() && heap()->IsAllocationObserverActive()) {
    // Ensure there are no unaccounted allocations.
    DCHECK_EQ(allocation_info().start(), allocation_info().top());

    size_t step = allocation_counter().NextBytes();
    DCHECK_NE(step, 0);
    // Generated code may allocate inline from the linear allocation area. To
    // make sure we can observe these allocations, we use a lower limit.
    size_t rounded_step = static_cast<size_t>(
        RoundDown(static_cast<int>(step - 1), ObjectAlignment()));
    step_size = std::min(step_size, rounded_step);
  }

  if (v8_flags.stress_marking) {
    step_size = std::min(step_size, static_cast<size_t>(64));
  }

  DCHECK_LE(start + step_size, end);
  return start + std::max(step_size, min_size);
}

#if DEBUG
void MainAllocator::Verify() const {
  // Ensure validity of LAB: start <= top <= limit
  DCHECK_LE(allocation_info().start(), allocation_info().top());
  DCHECK_LE(allocation_info().top(), allocation_info().limit());

  // Ensure that original_top_ always >= LAB start. The delta between start_
  // and top_ is still to be processed by allocation observers.
  DCHECK_GE(linear_area_original_data().get_original_top_acquire(),
            allocation_info().start());

  // Ensure that limit() is <= original_limit_.
  DCHECK_LE(allocation_info().limit(),
            linear_area_original_data().get_original_limit_relaxed());
}
#endif  // DEBUG

int MainAllocator::ObjectAlignment() const {
  if (identity() == CODE_SPACE) {
    return kCodeAlignment;
  } else if (V8_COMPRESS_POINTERS_8GB_BOOL) {
    return kObjectAlignment8GbHeap;
  } else {
    return kTaggedSize;
  }
}

AllocationSpace MainAllocator::identity() const { return space_->identity(); }

}  // namespace internal
}  // namespace v8

Zerion Mini Shell 1.0