Coverage Report

Created: 2021-08-22 09:07

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