1/*
2 * Copyright (C) 2014 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#ifndef LargeChunk_h
27#define LargeChunk_h
28
29#include "BeginTag.h"
30#include "EndTag.h"
31#include "ObjectType.h"
32#include "Sizes.h"
33#include "VMAllocate.h"
34
35namespace bmalloc {
36
37class LargeChunk {
38public:
39    static LargeChunk* create();
40    static LargeChunk* get(void*);
41
42    static BeginTag* beginTag(void*);
43    static EndTag* endTag(void*, size_t);
44
45    char* begin() { return m_memory; }
46    char* end() { return reinterpret_cast<char*>(this) + largeChunkSize; }
47
48private:
49     // Round up to ensure 2 dummy boundary tags -- for the left and right sentinels.
50     static const size_t boundaryTagCount = max(2 * largeMin / sizeof(BoundaryTag), largeChunkSize / largeMin);
51
52    // Our metadata layout includes a left and right edge sentinel.
53    // Metadata takes up enough space to leave at least the first two
54    // boundary tag slots unused.
55    //
56    //      So, boundary tag space looks like this:
57    //
58    //          [OOXXXXX...]
59    //
60    //      And BoundaryTag::get subtracts one, producing:
61    //
62    //          [OXXXXX...O].
63    //
64    // We use the X's for boundary tags and the O's for edge sentinels.
65
66    BoundaryTag m_boundaryTags[boundaryTagCount];
67
68    // Align to vmPageSize to avoid sharing physical pages with metadata.
69    // Otherwise, we'll confuse the scavenger into trying to scavenge metadata.
70    alignas(vmPageSize) char m_memory[];
71};
72
73inline LargeChunk* LargeChunk::create()
74{
75    size_t vmSize = bmalloc::vmSize(largeChunkSize);
76    std::pair<void*, Range> result = vmAllocate(vmSize, superChunkSize, largeChunkOffset);
77    return new (result.first) LargeChunk;
78}
79
80inline LargeChunk* LargeChunk::get(void* object)
81{
82    BASSERT(!isSmallOrMedium(object));
83    return static_cast<LargeChunk*>(mask(object, largeChunkMask));
84}
85
86inline BeginTag* LargeChunk::beginTag(void* object)
87{
88    LargeChunk* chunk = get(object);
89    size_t boundaryTagNumber = (static_cast<char*>(object) - reinterpret_cast<char*>(chunk)) / largeMin - 1; // - 1 to offset from the right sentinel.
90    return static_cast<BeginTag*>(&chunk->m_boundaryTags[boundaryTagNumber]);
91}
92
93inline EndTag* LargeChunk::endTag(void* object, size_t size)
94{
95    BASSERT(!isSmallOrMedium(object));
96
97    LargeChunk* chunk = get(object);
98    char* end = static_cast<char*>(object) + size;
99
100    // We subtract largeMin before computing the end pointer's boundary tag. An
101    // object's size need not be an even multiple of largeMin. Subtracting
102    // largeMin rounds down to the last boundary tag prior to our neighbor.
103
104    size_t boundaryTagNumber = (end - largeMin - reinterpret_cast<char*>(chunk)) / largeMin - 1; // - 1 to offset from the right sentinel.
105    return static_cast<EndTag*>(&chunk->m_boundaryTags[boundaryTagNumber]);
106}
107
108}; // namespace bmalloc
109
110#endif // LargeChunk
111