Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/gfx/IterableArena.h
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef MOZILLA_GFX_ITERABLEARENA_H_
8
#define MOZILLA_GFX_ITERABLEARENA_H_
9
10
#include "mozilla/Move.h"
11
#include "mozilla/Assertions.h"
12
#include "mozilla/gfx/Logging.h"
13
14
#include <string.h>
15
#include <vector>
16
#include <stdint.h>
17
#include <stdio.h>
18
19
namespace mozilla {
20
namespace gfx {
21
22
/// A simple pool allocator for plain data structures.
23
///
24
/// Beware that the pool will not attempt to run the destructors. It is the
25
/// responsibility of the user of this class to either use objects with no
26
/// destructor or to manually call the allocated objects destructors.
27
/// If the pool is growable, its allocated objects must be safely moveable in
28
/// in memory (through memcpy).
29
class IterableArena {
30
protected:
31
  struct Header
32
  {
33
    size_t mBlocSize;
34
  };
35
public:
36
  enum ArenaType {
37
    FIXED_SIZE,
38
    GROWABLE
39
  };
40
41
  IterableArena(ArenaType aType, size_t aStorageSize)
42
  : mSize(aStorageSize)
43
  , mCursor(0)
44
  , mIsGrowable(aType == GROWABLE)
45
0
  {
46
0
    if (mSize == 0) {
47
0
      mSize = 128;
48
0
    }
49
0
50
0
    mStorage = (uint8_t*)malloc(mSize);
51
0
    if (mStorage == nullptr) {
52
0
      gfxCriticalError() << "Not enough Memory allocate a memory pool of size " << aStorageSize;
53
0
      MOZ_CRASH("GFX: Out of memory IterableArena");
54
0
    }
55
0
  }
56
57
  ~IterableArena()
58
0
  {
59
0
    free(mStorage);
60
0
  }
61
62
  /// Constructs a new item in the pool and returns a positive offset in case of
63
  /// success.
64
  ///
65
  /// The offset never changes even if the storage is reallocated, so users
66
  /// of this class should prefer storing offsets rather than direct pointers
67
  /// to the allocated objects.
68
  /// Alloc can cause the storage to be reallocated if the pool was initialized
69
  /// with IterableArena::GROWABLE.
70
  /// If for any reason the pool fails to allocate enough space for the new item
71
  /// Alloc returns a negative offset and the object's constructor is not called.
72
  template<typename T, typename... Args>
73
  ptrdiff_t
74
  Alloc(Args&&... aArgs)
75
0
  {
76
0
    void* storage = nullptr;
77
0
    auto offset = AllocRaw(sizeof(T), &storage);
78
0
    if (offset < 0) {
79
0
      return offset;
80
0
    }
81
0
    new (storage) T(std::forward<Args>(aArgs)...);
82
0
    return offset;
83
0
  }
Unexecuted instantiation: long mozilla::gfx::IterableArena::Alloc<test_arena::A, int>(int&&)
Unexecuted instantiation: long mozilla::gfx::IterableArena::Alloc<test_arena::B, char const (&) [14]>(char const (&) [14])
Unexecuted instantiation: long mozilla::gfx::IterableArena::Alloc<test_arena::B, char const (&) [17]>(char const (&) [17])
Unexecuted instantiation: long mozilla::gfx::IterableArena::Alloc<test_arena::B, char const (&) [27]>(char const (&) [27])
Unexecuted instantiation: long mozilla::gfx::IterableArena::Alloc<test_arena::BigStruct, int>(int&&)
84
85
  ptrdiff_t AllocRaw(size_t aSize, void** aOutPtr = nullptr)
86
0
  {
87
0
    const size_t blocSize = AlignedSize(sizeof(Header) + aSize);
88
0
89
0
    if (AlignedSize(mCursor + blocSize) > mSize) {
90
0
      if (!mIsGrowable) {
91
0
        return -1;
92
0
      }
93
0
94
0
      size_t newSize = mSize * 2;
95
0
      while (AlignedSize(mCursor + blocSize) > newSize) {
96
0
        newSize *= 2;
97
0
      }
98
0
99
0
      uint8_t* newStorage = (uint8_t*)realloc(mStorage, newSize);
100
0
      if (!newStorage) {
101
0
         gfxCriticalError() << "Not enough Memory to grow the memory pool, size: " << newSize;
102
0
        return -1;
103
0
      }
104
0
105
0
      mStorage = newStorage;
106
0
      mSize = newSize;
107
0
    }
108
0
    ptrdiff_t offset = mCursor;
109
0
    GetHeader(offset)->mBlocSize = blocSize;
110
0
    mCursor += blocSize;
111
0
    if (aOutPtr) {
112
0
        *aOutPtr = GetStorage(offset);
113
0
    }
114
0
    return offset;
115
0
  }
116
117
  /// Get access to an allocated item at a given offset (only use offsets returned
118
  /// by Alloc or AllocRaw).
119
  ///
120
  /// If the pool is growable, the returned pointer is only valid temporarily. The
121
  /// underlying storage can be reallocated in Alloc or AllocRaw, so do not keep
122
  /// these pointers around and store the offset instead.
123
  void* GetStorage(ptrdiff_t offset = 0)
124
0
  {
125
0
    MOZ_ASSERT(offset >= 0);
126
0
    MOZ_ASSERT(offset < mCursor);
127
0
    return offset >= 0 ? mStorage + offset + sizeof(Header) : nullptr;
128
0
  }
129
130
  /// Clears the storage without running any destructor and without deallocating it.
131
  void Clear()
132
0
  {
133
0
    mCursor = 0;
134
0
  }
135
136
  /// Iterate over the elements allocated in this pool.
137
  ///
138
  /// Takes a lambda or function object accepting a void* as parameter.
139
  template<typename Func>
140
  void ForEach(Func cb)
141
0
  {
142
0
    Iterator it;
143
0
    while (void* ptr = it.Next(this)) {
144
0
      cb(ptr);
145
0
    }
146
0
  }
Unexecuted instantiation: Unified_cpp_gfx_2d1.cpp:void mozilla::gfx::IterableArena::ForEach<mozilla::gfx::CommandBuffer::~CommandBuffer()::$_0>(mozilla::gfx::CommandBuffer::~CommandBuffer()::$_0)
Unexecuted instantiation: Unified_cpp_gfx_tests_gtest0.cpp:void mozilla::gfx::IterableArena::ForEach<test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_0>(test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_0)
Unexecuted instantiation: Unified_cpp_gfx_tests_gtest0.cpp:void mozilla::gfx::IterableArena::ForEach<test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_1>(test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_1)
Unexecuted instantiation: Unified_cpp_gfx_tests_gtest0.cpp:void mozilla::gfx::IterableArena::ForEach<test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_2>(test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_2)
Unexecuted instantiation: Unified_cpp_gfx_tests_gtest0.cpp:void mozilla::gfx::IterableArena::ForEach<test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_3>(test_arena::TestArenaAlloc(mozilla::gfx::IterableArena::ArenaType)::$_3)
147
148
  /// A simple iterator over an arena.
149
  class Iterator {
150
  public:
151
    Iterator()
152
    : mCursor(0)
153
0
    {}
154
155
    void* Next(IterableArena* aArena)
156
0
    {
157
0
      if (mCursor >= aArena->mCursor) {
158
0
        return nullptr;
159
0
      }
160
0
      void* result = aArena->GetStorage(mCursor);
161
0
      const size_t blocSize = aArena->GetHeader(mCursor)->mBlocSize;
162
0
      MOZ_ASSERT(blocSize != 0);
163
0
      mCursor += blocSize;
164
0
      return result;
165
0
    }
166
167
  private:
168
    ptrdiff_t mCursor;
169
  };
170
171
protected:
172
  Header* GetHeader(ptrdiff_t offset)
173
0
  {
174
0
    return (Header*) (mStorage + offset);
175
0
  }
176
177
  size_t AlignedSize(size_t aSize) const
178
0
  {
179
0
    const size_t alignment = sizeof(uintptr_t);
180
0
    return aSize + (alignment - (aSize % alignment)) % alignment;
181
0
  }
182
183
  uint8_t* mStorage;
184
  uint32_t mSize;
185
  ptrdiff_t mCursor;
186
  bool mIsGrowable;
187
188
  friend class Iterator;
189
};
190
191
} // namespace
192
} // namespace
193
194
#endif