1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2016 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "src/core/SkArenaAlloc.h"
9cb93a386Sopenharmony_ci#include <algorithm>
10cb93a386Sopenharmony_ci#include <new>
11cb93a386Sopenharmony_ci
12cb93a386Sopenharmony_cistatic char* end_chain(char*) { return nullptr; }
13cb93a386Sopenharmony_ci
14cb93a386Sopenharmony_ciSkArenaAlloc::SkArenaAlloc(char* block, size_t size, size_t firstHeapAllocation)
15cb93a386Sopenharmony_ci    : fDtorCursor {block}
16cb93a386Sopenharmony_ci    , fCursor     {block}
17cb93a386Sopenharmony_ci    , fEnd        {block + SkToU32(size)}
18cb93a386Sopenharmony_ci    , fFibonacciProgression{SkToU32(size), SkToU32(firstHeapAllocation)}
19cb93a386Sopenharmony_ci{
20cb93a386Sopenharmony_ci    if (size < sizeof(Footer)) {
21cb93a386Sopenharmony_ci        fEnd = fCursor = fDtorCursor = nullptr;
22cb93a386Sopenharmony_ci    }
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_ci    if (fCursor != nullptr) {
25cb93a386Sopenharmony_ci        this->installFooter(end_chain, 0);
26cb93a386Sopenharmony_ci    }
27cb93a386Sopenharmony_ci}
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ciSkArenaAlloc::~SkArenaAlloc() {
30cb93a386Sopenharmony_ci    RunDtorsOnBlock(fDtorCursor);
31cb93a386Sopenharmony_ci}
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_civoid SkArenaAlloc::installFooter(FooterAction* action, uint32_t padding) {
34cb93a386Sopenharmony_ci    assert(SkTFitsIn<uint8_t>(padding));
35cb93a386Sopenharmony_ci    this->installRaw(action);
36cb93a386Sopenharmony_ci    this->installRaw((uint8_t)padding);
37cb93a386Sopenharmony_ci    fDtorCursor = fCursor;
38cb93a386Sopenharmony_ci}
39cb93a386Sopenharmony_ci
40cb93a386Sopenharmony_cichar* SkArenaAlloc::SkipPod(char* footerEnd) {
41cb93a386Sopenharmony_ci    char* objEnd = footerEnd - (sizeof(Footer) + sizeof(int32_t));
42cb93a386Sopenharmony_ci    int32_t skip;
43cb93a386Sopenharmony_ci    memmove(&skip, objEnd, sizeof(int32_t));
44cb93a386Sopenharmony_ci    return objEnd - skip;
45cb93a386Sopenharmony_ci}
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_civoid SkArenaAlloc::RunDtorsOnBlock(char* footerEnd) {
48cb93a386Sopenharmony_ci    while (footerEnd != nullptr) {
49cb93a386Sopenharmony_ci        FooterAction* action;
50cb93a386Sopenharmony_ci        uint8_t       padding;
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_ci        memcpy(&action,  footerEnd - sizeof( Footer), sizeof( action));
53cb93a386Sopenharmony_ci        memcpy(&padding, footerEnd - sizeof(padding), sizeof(padding));
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci        footerEnd = action(footerEnd) - (ptrdiff_t)padding;
56cb93a386Sopenharmony_ci    }
57cb93a386Sopenharmony_ci}
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_cichar* SkArenaAlloc::NextBlock(char* footerEnd) {
60cb93a386Sopenharmony_ci    char* objEnd = footerEnd - (sizeof(char*) + sizeof(Footer));
61cb93a386Sopenharmony_ci    char* next;
62cb93a386Sopenharmony_ci    memmove(&next, objEnd, sizeof(char*));
63cb93a386Sopenharmony_ci    RunDtorsOnBlock(next);
64cb93a386Sopenharmony_ci    delete [] objEnd;
65cb93a386Sopenharmony_ci    return nullptr;
66cb93a386Sopenharmony_ci}
67cb93a386Sopenharmony_ci
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_civoid SkArenaAlloc::ensureSpace(uint32_t size, uint32_t alignment) {
70cb93a386Sopenharmony_ci    constexpr uint32_t headerSize = sizeof(Footer) + sizeof(ptrdiff_t);
71cb93a386Sopenharmony_ci    constexpr uint32_t maxSize = std::numeric_limits<uint32_t>::max();
72cb93a386Sopenharmony_ci    constexpr uint32_t overhead = headerSize + sizeof(Footer);
73cb93a386Sopenharmony_ci    AssertRelease(size <= maxSize - overhead);
74cb93a386Sopenharmony_ci    uint32_t objSizeAndOverhead = size + overhead;
75cb93a386Sopenharmony_ci
76cb93a386Sopenharmony_ci    const uint32_t alignmentOverhead = alignment - 1;
77cb93a386Sopenharmony_ci    AssertRelease(objSizeAndOverhead <= maxSize - alignmentOverhead);
78cb93a386Sopenharmony_ci    objSizeAndOverhead += alignmentOverhead;
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ci    uint32_t minAllocationSize = fFibonacciProgression.nextBlockSize();
81cb93a386Sopenharmony_ci    uint32_t allocationSize = std::max(objSizeAndOverhead, minAllocationSize);
82cb93a386Sopenharmony_ci
83cb93a386Sopenharmony_ci    // Round up to a nice size. If > 32K align to 4K boundary else up to max_align_t. The > 32K
84cb93a386Sopenharmony_ci    // heuristic is from the JEMalloc behavior.
85cb93a386Sopenharmony_ci    {
86cb93a386Sopenharmony_ci        uint32_t mask = allocationSize > (1 << 15) ? (1 << 12) - 1 : 16 - 1;
87cb93a386Sopenharmony_ci        AssertRelease(allocationSize <= maxSize - mask);
88cb93a386Sopenharmony_ci        allocationSize = (allocationSize + mask) & ~mask;
89cb93a386Sopenharmony_ci    }
90cb93a386Sopenharmony_ci
91cb93a386Sopenharmony_ci    char* newBlock = new char[allocationSize];
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    auto previousDtor = fDtorCursor;
94cb93a386Sopenharmony_ci    fCursor = newBlock;
95cb93a386Sopenharmony_ci    fDtorCursor = newBlock;
96cb93a386Sopenharmony_ci    fEnd = fCursor + allocationSize;
97cb93a386Sopenharmony_ci    this->installRaw(previousDtor);
98cb93a386Sopenharmony_ci    this->installFooter(NextBlock, 0);
99cb93a386Sopenharmony_ci}
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_cichar* SkArenaAlloc::allocObjectWithFooter(uint32_t sizeIncludingFooter, uint32_t alignment) {
102cb93a386Sopenharmony_ci    uintptr_t mask = alignment - 1;
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_cirestart:
105cb93a386Sopenharmony_ci    uint32_t skipOverhead = 0;
106cb93a386Sopenharmony_ci    const bool needsSkipFooter = fCursor != fDtorCursor;
107cb93a386Sopenharmony_ci    if (needsSkipFooter) {
108cb93a386Sopenharmony_ci        skipOverhead = sizeof(Footer) + sizeof(uint32_t);
109cb93a386Sopenharmony_ci    }
110cb93a386Sopenharmony_ci    const uint32_t totalSize = sizeIncludingFooter + skipOverhead;
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci    // Math on null fCursor/fEnd is undefined behavior, so explicitly check for first alloc.
113cb93a386Sopenharmony_ci    if (!fCursor) {
114cb93a386Sopenharmony_ci        this->ensureSpace(totalSize, alignment);
115cb93a386Sopenharmony_ci        goto restart;
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    assert(fEnd);
119cb93a386Sopenharmony_ci    // This test alone would be enough nullptr were defined to be 0, but it's not.
120cb93a386Sopenharmony_ci    char* objStart = (char*)((uintptr_t)(fCursor + skipOverhead + mask) & ~mask);
121cb93a386Sopenharmony_ci    if ((ptrdiff_t)totalSize > fEnd - objStart) {
122cb93a386Sopenharmony_ci        this->ensureSpace(totalSize, alignment);
123cb93a386Sopenharmony_ci        goto restart;
124cb93a386Sopenharmony_ci    }
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_ci    AssertRelease((ptrdiff_t)totalSize <= fEnd - objStart);
127cb93a386Sopenharmony_ci
128cb93a386Sopenharmony_ci    // Install a skip footer if needed, thus terminating a run of POD data. The calling code is
129cb93a386Sopenharmony_ci    // responsible for installing the footer after the object.
130cb93a386Sopenharmony_ci    if (needsSkipFooter) {
131cb93a386Sopenharmony_ci        this->installRaw(SkToU32(fCursor - fDtorCursor));
132cb93a386Sopenharmony_ci        this->installFooter(SkipPod, 0);
133cb93a386Sopenharmony_ci    }
134cb93a386Sopenharmony_ci
135cb93a386Sopenharmony_ci    return objStart;
136cb93a386Sopenharmony_ci}
137cb93a386Sopenharmony_ci
138cb93a386Sopenharmony_ciSkArenaAllocWithReset::SkArenaAllocWithReset(char* block,
139cb93a386Sopenharmony_ci                                             size_t size,
140cb93a386Sopenharmony_ci                                             size_t firstHeapAllocation)
141cb93a386Sopenharmony_ci        : SkArenaAlloc(block, size, firstHeapAllocation)
142cb93a386Sopenharmony_ci        , fFirstBlock{block}
143cb93a386Sopenharmony_ci        , fFirstSize{SkToU32(size)}
144cb93a386Sopenharmony_ci        , fFirstHeapAllocationSize{SkToU32(firstHeapAllocation)} {}
145cb93a386Sopenharmony_ci
146cb93a386Sopenharmony_civoid SkArenaAllocWithReset::reset() {
147cb93a386Sopenharmony_ci    this->~SkArenaAllocWithReset();
148cb93a386Sopenharmony_ci    new (this) SkArenaAllocWithReset{fFirstBlock, fFirstSize, fFirstHeapAllocationSize};
149cb93a386Sopenharmony_ci}
150cb93a386Sopenharmony_ci
151cb93a386Sopenharmony_ci// SkFibonacci47 is the first 47 Fibonacci numbers. Fib(47) is the largest value less than 2 ^ 32.
152cb93a386Sopenharmony_ci// Used by SkFibBlockSizes.
153cb93a386Sopenharmony_cistd::array<const uint32_t, 47> SkFibonacci47 {
154cb93a386Sopenharmony_ci                1,         1,          2,          3,          5,          8,
155cb93a386Sopenharmony_ci               13,        21,         34,         55,         89,        144,
156cb93a386Sopenharmony_ci              233,       377,        610,        987,       1597,       2584,
157cb93a386Sopenharmony_ci             4181,      6765,      10946,      17711,      28657,      46368,
158cb93a386Sopenharmony_ci            75025,    121393,     196418,     317811,     514229,     832040,
159cb93a386Sopenharmony_ci          1346269,   2178309,    3524578,    5702887,    9227465,   14930352,
160cb93a386Sopenharmony_ci         24157817,  39088169,   63245986,  102334155,  165580141,  267914296,
161cb93a386Sopenharmony_ci        433494437, 701408733, 1134903170, 1836311903, 2971215073,
162cb93a386Sopenharmony_ci};
163