// Copyright 2020 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/codegen/aligned-slot-allocator.h" #include "src/base/bits.h" #include "src/base/logging.h" namespace v8 { namespace internal { int AlignedSlotAllocator::NextSlot(int n) const { DCHECK(n == 1 || n == 2 || n == 4); if (n <= 1 && IsValid(next1_)) return next1_; if (n <= 2 && IsValid(next2_)) return next2_; DCHECK(IsValid(next4_)); return next4_; } int AlignedSlotAllocator::Allocate(int n) { DCHECK(n == 1 || n == 2 || n == 4); // Check invariants. DCHECK_EQ(0, next4_ & 3); DCHECK_IMPLIES(IsValid(next2_), (next2_ & 1) == 0); // The sentinel value kInvalidSlot is used to indicate no slot. // next1_ is the index of the 1 slot fragment, or kInvalidSlot. // next2_ is the 2-aligned index of the 2 slot fragment, or kInvalidSlot. // next4_ is the 4-aligned index of the next 4 slot group. It is always valid. // In order to ensure we only have a single 1- or 2-slot fragment, we greedily // use any fragment that satisfies the request. int result = kInvalidSlot; switch (n) { case 1: { if (IsValid(next1_)) { result = next1_; next1_ = kInvalidSlot; } else if (IsValid(next2_)) { result = next2_; next1_ = result + 1; next2_ = kInvalidSlot; } else { result = next4_; next1_ = result + 1; next2_ = result + 2; next4_ += 4; } break; } case 2: { if (IsValid(next2_)) { result = next2_; next2_ = kInvalidSlot; } else { result = next4_; next2_ = result + 2; next4_ += 4; } break; } case 4: { result = next4_; next4_ += 4; break; } default: UNREACHABLE(); } DCHECK(IsValid(result)); size_ = std::max(size_, result + n); return result; } int AlignedSlotAllocator::AllocateUnaligned(int n) { DCHECK_GE(n, 0); // Check invariants. DCHECK_EQ(0, next4_ & 3); DCHECK_IMPLIES(IsValid(next2_), (next2_ & 1) == 0); // Reserve |n| slots at |size_|, invalidate fragments below the new |size_|, // and add any new fragments beyond the new |size_|. int result = size_; size_ += n; switch (size_ & 3) { case 0: { next1_ = next2_ = kInvalidSlot; next4_ = size_; break; } case 1: { next1_ = size_; next2_ = size_ + 1; next4_ = size_ + 3; break; } case 2: { next1_ = kInvalidSlot; next2_ = size_; next4_ = size_ + 2; break; } case 3: { next1_ = size_; next2_ = kInvalidSlot; next4_ = size_ + 1; break; } } return result; } int AlignedSlotAllocator::Align(int n) { DCHECK(base::bits::IsPowerOfTwo(n)); DCHECK_LE(n, 4); int mask = n - 1; int misalignment = size_ & mask; int padding = (n - misalignment) & mask; AllocateUnaligned(padding); return padding; } } // namespace internal } // namespace v8