0cae7b3b创建于 2025年7月30日历史提交
// Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
// This source file is part of the Cangjie project, licensed under Apache-2.0
// with Runtime Library Exception.
//
// See https://cangjie-lang.cn/pages/LICENSE for license information.


#include "ThreadCache.h"

#include "CentralCache.h"

namespace MapleRuntime {
void* ThreadCache::Allocate(size_t bytes)
{
    // ThreadCache can only allocate object space that is less than or equal to 256KB
    CHECK(bytes <= MAX_BYTES);
    // 1. Determine the size of the aligned small fixed-size memory block and the free list bucket it maps to
    size_t index = SizeManager::Index(bytes);
    size_t alignBytes = SizeManager::RoundUp(bytes);
    // 2. If the free list bucket is not empty, retrieve the first small fixed-size memory block.
    //    If the bucket is empty, batch-allocate from CentralCache.
    if (!freeLists[index].Empty()) {
        return freeLists[index].PopFront();
    } else {
        return FetchFromCentralCache(index, alignBytes);
    }
}

// Deallocate a small fixed-size memory block
void ThreadCache::Deallocate(void* ptr, size_t bytes)
{
    CHECK(ptr != nullptr);
    CHECK(bytes <= MAX_BYTES);
    // 1. Calculate the free list bucket it maps to
    size_t index = SizeManager::Index(bytes);
    // 2. Insert the small fixed-size memory block at the head of the free list bucket
    freeLists[index].PushFront(ptr);
    // 3. When the free list length is greater than or equal to the batch allocation size,
    //    return all small fixed-size memory blocks in the current free list to CentralCache
    if (freeLists[index].GetSize() >= freeLists[index].GetAdjustSize()) {
        ReturnToCentralCache(freeLists[index], bytes);
    }
}

// Fetch a "batch" of small fixed-size memory blocks from the central cache and return one block to the caller
void* ThreadCache::FetchFromCentralCache(size_t index, size_t alignBytes)
{
    // Slow-start feedback adjustment algorithm:
    // 1. Initially, do not request too many blocks from CentralCache at once, as too many may not be fully utilized.
    // 2. Gradually increase the batch size until the upper limit is reached.
    // 3. The smaller the alignBytes, the larger the batch size requested from CentralCache.
    // 4. The larger the alignBytes, the smaller the batch size requested from CentralCache.

    CHECK(alignBytes >= MIN_ALIGN_NUM);

    // 1. Calculate the number of small fixed-size memory blocks to request from CentralCache
    size_t batchNum = std::min(freeLists[index].GetAdjustSize(), SizeManager::LimitSize(alignBytes));
    if (freeLists[index].GetAdjustSize() == batchNum) {
        freeLists[index].GetAdjustSize() += 1;
    }
    // 2. Request a batch of small fixed-size memory blocks from CentralCache using output parameters
    void* begin = nullptr;
    void* end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(begin, end, batchNum, alignBytes);
    // 3. Return the first small fixed-size memory block to the caller
    //    and link the remaining blocks to the free list bucket
    CHECK(actualNum > 0);
    if (actualNum == 1) {
        CHECK(begin == end);
        return begin;
    } else {
        freeLists[index].PushAtFront(NextObj(begin), end, actualNum - 1);
        return begin;
    }
}

// Return a list of memory blocks to CentralCache
void ThreadCache::ReturnToCentralCache(FreeList& list, size_t bytes)
{
    CHECK(bytes > 0);

    void* start = nullptr;
    // 1. Strip the contiguous small fixed-size memory blocks from the list
    list.PopAtFront(start, list.GetSize());
    // 2. Release the stripped memory block list to CentralCache
    CentralCache::GetInstance()->ReleaseListToSpans(start, SizeManager::Index(bytes));
}
} // namespace MapleRuntime