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 Page_h
27#define Page_h
28
29#include "BAssert.h"
30#include "Mutex.h"
31#include "VMAllocate.h"
32#include <mutex>
33
34namespace bmalloc {
35
36template<typename Traits>
37class Page {
38public:
39    typedef typename Traits::Chunk Chunk;
40    typedef typename Traits::Line Line;
41    static const size_t lineSize = Traits::lineSize;
42
43    static const unsigned char maxRefCount = std::numeric_limits<unsigned char>::max();
44    static_assert(vmPageSize / lineSize < maxRefCount, "maximum line count must fit in Page");
45
46    static Page* get(Line*);
47
48    void ref(std::lock_guard<StaticMutex>&);
49    bool deref(std::lock_guard<StaticMutex>&);
50    unsigned refCount(std::lock_guard<StaticMutex>&) { return m_refCount; }
51
52    size_t smallSizeClass() { return m_smallSizeClass; }
53    void setSmallSizeClass(size_t smallSizeClass) { m_smallSizeClass = smallSizeClass; }
54
55    Line* begin();
56    Line* end();
57
58private:
59    unsigned char m_refCount;
60    unsigned char m_smallSizeClass;
61};
62
63template<typename Traits>
64inline void Page<Traits>::ref(std::lock_guard<StaticMutex>&)
65{
66    BASSERT(m_refCount < maxRefCount);
67    ++m_refCount;
68}
69
70template<typename Traits>
71inline bool Page<Traits>::deref(std::lock_guard<StaticMutex>&)
72{
73    BASSERT(m_refCount);
74    --m_refCount;
75    return !m_refCount;
76}
77
78template<typename Traits>
79inline auto Page<Traits>::get(Line* line) -> Page*
80{
81    Chunk* chunk = Chunk::get(line);
82    size_t lineNumber = line - chunk->lines();
83    size_t pageNumber = lineNumber * lineSize / vmPageSize;
84    return &chunk->pages()[pageNumber];
85}
86
87template<typename Traits>
88inline auto Page<Traits>::begin() -> Line*
89{
90    Chunk* chunk = Chunk::get(this);
91    size_t pageNumber = this - chunk->pages();
92    size_t lineNumber = pageNumber * vmPageSize / lineSize;
93    return &chunk->lines()[lineNumber];
94}
95
96template<typename Traits>
97inline auto Page<Traits>::end() -> Line*
98{
99    return begin() + vmPageSize / lineSize;
100}
101
102} // namespace bmalloc
103
104#endif // Page_h
105