Coverage Report

Created: 2025-06-16 07:00

/src/libjxl/lib/jxl/memory_manager_internal.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#ifndef LIB_JXL_MEMORY_MANAGER_INTERNAL_H_
7
#define LIB_JXL_MEMORY_MANAGER_INTERNAL_H_
8
9
// Memory allocator with support for alignment + misalignment.
10
11
#include <jxl/memory_manager.h>
12
13
#include <cstddef>
14
#include <memory>
15
#include <utility>
16
17
#include "lib/jxl/base/compiler_specific.h"
18
#include "lib/jxl/base/status.h"
19
20
namespace jxl {
21
22
namespace memory_manager_internal {
23
24
// To avoid RFOs, match L2 fill size (pairs of lines); 2 x cache line size.
25
static constexpr size_t kAlignment = 2 * 64;
26
static_assert((kAlignment & (kAlignment - 1)) == 0,
27
              "kAlignment must be a power of 2");
28
29
// Minimum multiple for which cache set conflicts and/or loads blocked by
30
// preceding stores can occur.
31
static constexpr size_t kNumAlignmentGroups = 16;
32
static constexpr size_t kAlias = kNumAlignmentGroups * kAlignment;
33
static_assert((kNumAlignmentGroups & (kNumAlignmentGroups - 1)) == 0,
34
              "kNumAlignmentGroups must be a power of 2");
35
36
}  // namespace memory_manager_internal
37
38
// Initializes the memory manager instance with the passed one. The
39
// MemoryManager passed in |memory_manager| may be NULL or contain NULL
40
// functions which will be initialized with the default ones. If either alloc
41
// or free are NULL, then both must be NULL, otherwise this function returns an
42
// error.
43
Status MemoryManagerInit(JxlMemoryManager* self,
44
                         const JxlMemoryManager* memory_manager);
45
46
void* MemoryManagerAlloc(const JxlMemoryManager* memory_manager, size_t size);
47
void MemoryManagerFree(const JxlMemoryManager* memory_manager, void* address);
48
49
// Helper class to be used as a deleter in a unique_ptr<T> call.
50
class MemoryManagerDeleteHelper {
51
 public:
52
  explicit MemoryManagerDeleteHelper(const JxlMemoryManager* memory_manager)
53
1.35k
      : memory_manager_(memory_manager) {}
54
55
  // Delete and free the passed pointer using the memory_manager.
56
  template <typename T>
57
674
  void operator()(T* address) const {
58
674
    if (!address) {
59
0
      return;
60
0
    }
61
674
    address->~T();
62
674
    return memory_manager_->free(memory_manager_->opaque, address);
63
674
  }
void jxl::MemoryManagerDeleteHelper::operator()<jxl::JxlEncoderQueuedFrame>(jxl::JxlEncoderQueuedFrame*) const
Line
Count
Source
57
186
  void operator()(T* address) const {
58
186
    if (!address) {
59
0
      return;
60
0
    }
61
186
    address->~T();
62
186
    return memory_manager_->free(memory_manager_->opaque, address);
63
186
  }
void jxl::MemoryManagerDeleteHelper::operator()<jxl::JxlEncoderQueuedBox>(jxl::JxlEncoderQueuedBox*) const
Line
Count
Source
57
41
  void operator()(T* address) const {
58
41
    if (!address) {
59
0
      return;
60
0
    }
61
41
    address->~T();
62
41
    return memory_manager_->free(memory_manager_->opaque, address);
63
41
  }
void jxl::MemoryManagerDeleteHelper::operator()<JxlEncoderFrameSettings>(JxlEncoderFrameSettings*) const
Line
Count
Source
57
217
  void operator()(T* address) const {
58
217
    if (!address) {
59
0
      return;
60
0
    }
61
217
    address->~T();
62
217
    return memory_manager_->free(memory_manager_->opaque, address);
63
217
  }
void jxl::MemoryManagerDeleteHelper::operator()<jxl::ThreadPool>(jxl::ThreadPool*) const
Line
Count
Source
57
230
  void operator()(T* address) const {
58
230
    if (!address) {
59
0
      return;
60
0
    }
61
230
    address->~T();
62
230
    return memory_manager_->free(memory_manager_->opaque, address);
63
230
  }
64
65
 private:
66
  const JxlMemoryManager* memory_manager_;
67
};
68
69
template <typename T>
70
using MemoryManagerUniquePtr = std::unique_ptr<T, MemoryManagerDeleteHelper>;
71
72
// Creates a new object T allocating it with the memory allocator into a
73
// unique_ptr; not to be used outside JXL_MEMORY_MANAGER_MAKE_UNIQUE_OR_RETURN.
74
template <typename T, typename... Args>
75
JXL_INLINE MemoryManagerUniquePtr<T> MemoryManagerMakeUniquePrivate(
76
674
    const JxlMemoryManager* memory_manager, Args&&... args) {
77
674
  T* mem =
78
674
      static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T)));
79
674
  if (!mem) {
80
    // Allocation error case.
81
0
    return MemoryManagerUniquePtr<T>(nullptr,
82
0
                                     MemoryManagerDeleteHelper(memory_manager));
83
0
  }
84
674
  return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...),
85
674
                                   MemoryManagerDeleteHelper(memory_manager));
86
674
}
std::__1::unique_ptr<JxlEncoderFrameSettings, jxl::MemoryManagerDeleteHelper> jxl::MemoryManagerMakeUniquePrivate<JxlEncoderFrameSettings>(JxlMemoryManagerStruct const*)
Line
Count
Source
76
217
    const JxlMemoryManager* memory_manager, Args&&... args) {
77
217
  T* mem =
78
217
      static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T)));
79
217
  if (!mem) {
80
    // Allocation error case.
81
0
    return MemoryManagerUniquePtr<T>(nullptr,
82
0
                                     MemoryManagerDeleteHelper(memory_manager));
83
0
  }
84
217
  return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...),
85
217
                                   MemoryManagerDeleteHelper(memory_manager));
86
217
}
std::__1::unique_ptr<jxl::ThreadPool, jxl::MemoryManagerDeleteHelper> jxl::MemoryManagerMakeUniquePrivate<jxl::ThreadPool, int (*&)(void*, void*, int (*)(void*, unsigned long), void (*)(void*, unsigned int, unsigned long), unsigned int, unsigned int), void*&>(JxlMemoryManagerStruct const*, int (*&)(void*, void*, int (*)(void*, unsigned long), void (*)(void*, unsigned int, unsigned long), unsigned int, unsigned int), void*&)
Line
Count
Source
76
230
    const JxlMemoryManager* memory_manager, Args&&... args) {
77
230
  T* mem =
78
230
      static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T)));
79
230
  if (!mem) {
80
    // Allocation error case.
81
0
    return MemoryManagerUniquePtr<T>(nullptr,
82
0
                                     MemoryManagerDeleteHelper(memory_manager));
83
0
  }
84
230
  return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...),
85
230
                                   MemoryManagerDeleteHelper(memory_manager));
86
230
}
std::__1::unique_ptr<jxl::JxlEncoderQueuedFrame, jxl::MemoryManagerDeleteHelper> jxl::MemoryManagerMakeUniquePrivate<jxl::JxlEncoderQueuedFrame, jxl::JxlEncoderQueuedFrame>(JxlMemoryManagerStruct const*, jxl::JxlEncoderQueuedFrame&&)
Line
Count
Source
76
186
    const JxlMemoryManager* memory_manager, Args&&... args) {
77
186
  T* mem =
78
186
      static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T)));
79
186
  if (!mem) {
80
    // Allocation error case.
81
0
    return MemoryManagerUniquePtr<T>(nullptr,
82
0
                                     MemoryManagerDeleteHelper(memory_manager));
83
0
  }
84
186
  return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...),
85
186
                                   MemoryManagerDeleteHelper(memory_manager));
86
186
}
std::__1::unique_ptr<jxl::JxlEncoderQueuedBox, jxl::MemoryManagerDeleteHelper> jxl::MemoryManagerMakeUniquePrivate<jxl::JxlEncoderQueuedBox>(JxlMemoryManagerStruct const*)
Line
Count
Source
76
41
    const JxlMemoryManager* memory_manager, Args&&... args) {
77
41
  T* mem =
78
41
      static_cast<T*>(memory_manager->alloc(memory_manager->opaque, sizeof(T)));
79
41
  if (!mem) {
80
    // Allocation error case.
81
0
    return MemoryManagerUniquePtr<T>(nullptr,
82
0
                                     MemoryManagerDeleteHelper(memory_manager));
83
0
  }
84
41
  return MemoryManagerUniquePtr<T>(new (mem) T(std::forward<Args>(args)...),
85
41
                                   MemoryManagerDeleteHelper(memory_manager));
86
41
}
87
88
// NOLINTBEGIN(bugprone-macro-parentheses)
89
// NB: ARGS should be in parentheses on instantiation side; it contains
90
//     arguments for MemoryManagerMakeUniquePrivate, including `memory_manager`.
91
#define JXL_MEMORY_MANAGER_MAKE_UNIQUE_OR_RETURN(NAME, TYPE, ARGS, RETURN) \
92
674
  auto NAME = ::jxl::MemoryManagerMakeUniquePrivate<TYPE> ARGS;            \
93
674
  if (!NAME) {                                                             \
94
0
    return RETURN;                                                         \
95
0
  }
96
// NOLINTEND(bugprone-macro-parentheses)
97
98
// Returns recommended distance in bytes between the start of two consecutive
99
// rows.
100
size_t BytesPerRow(size_t xsize, size_t sizeof_t);
101
102
class AlignedMemory {
103
 public:
104
  AlignedMemory()
105
9.55M
      : allocation_(nullptr), memory_manager_(nullptr), address_(nullptr) {}
106
107
  // Copy disallowed.
108
  AlignedMemory(const AlignedMemory& other) = delete;
109
  AlignedMemory& operator=(const AlignedMemory& other) = delete;
110
111
  // Custom move.
112
  AlignedMemory(AlignedMemory&& other) noexcept;
113
  AlignedMemory& operator=(AlignedMemory&& other) noexcept;
114
115
  ~AlignedMemory();
116
117
  static StatusOr<AlignedMemory> Create(JxlMemoryManager* memory_manager,
118
                                        size_t size, size_t pre_padding = 0);
119
120
2.00k
  explicit operator bool() const noexcept { return (address_ != nullptr); }
121
122
  template <typename T>
123
526M
  T* address() const {
124
526M
    return reinterpret_cast<T*>(address_);
125
526M
  }
void* jxl::AlignedMemory::address<void>() const
Line
Count
Source
123
6.06M
  T* address() const {
124
6.06M
    return reinterpret_cast<T*>(address_);
125
6.06M
  }
unsigned char* jxl::AlignedMemory::address<unsigned char>() const
Line
Count
Source
123
520M
  T* address() const {
124
520M
    return reinterpret_cast<T*>(address_);
125
520M
  }
enc_coeff_order.cc:jxl::ComputeCoeffOrder(jxl::SpeedTier, jxl::ACImage const&, jxl::AcStrategyImage const&, jxl::FrameDimensions const&, unsigned int&, unsigned int, unsigned int, unsigned int, unsigned int*)::PosAndCount* jxl::AlignedMemory::address<jxl::ComputeCoeffOrder(jxl::SpeedTier, jxl::ACImage const&, jxl::AcStrategyImage const&, jxl::FrameDimensions const&, unsigned int&, unsigned int, unsigned int, unsigned int, unsigned int*)::PosAndCount>() const
Line
Count
Source
123
2.37k
  T* address() const {
124
2.37k
    return reinterpret_cast<T*>(address_);
125
2.37k
  }
unsigned int* jxl::AlignedMemory::address<unsigned int>() const
Line
Count
Source
123
19.6k
  T* address() const {
124
19.6k
    return reinterpret_cast<T*>(address_);
125
19.6k
  }
float* jxl::AlignedMemory::address<float>() const
Line
Count
Source
123
34.0k
  T* address() const {
124
34.0k
    return reinterpret_cast<T*>(address_);
125
34.0k
  }
jxl::GroupDecCache* jxl::AlignedMemory::address<jxl::GroupDecCache>() const
Line
Count
Source
123
2.90k
  T* address() const {
124
2.90k
    return reinterpret_cast<T*>(address_);
125
2.90k
  }
int* jxl::AlignedMemory::address<int>() const
Line
Count
Source
123
4.07k
  T* address() const {
124
4.07k
    return reinterpret_cast<T*>(address_);
125
4.07k
  }
jxl::AliasTable::Entry* jxl::AlignedMemory::address<jxl::AliasTable::Entry>() const
Line
Count
Source
123
127k
  T* address() const {
124
127k
    return reinterpret_cast<T*>(address_);
125
127k
  }
short* jxl::AlignedMemory::address<short>() const
Line
Count
Source
123
3.48k
  T* address() const {
124
3.48k
    return reinterpret_cast<T*>(address_);
125
3.48k
  }
unsigned short* jxl::AlignedMemory::address<unsigned short>() const
Line
Count
Source
123
83.4k
  T* address() const {
124
83.4k
    return reinterpret_cast<T*>(address_);
125
83.4k
  }
126
84.3k
  JxlMemoryManager* memory_manager() const { return memory_manager_; }
127
128
  // TODO(eustas): we can offer "actually accessible" size; it is 0-2KiB bigger
129
  //               than requested size, due to generous alignment;
130
  //               might be useful for resizeable containers (e.g. PaddedBytes)
131
132
 private:
133
  AlignedMemory(JxlMemoryManager* memory_manager, void* allocation,
134
                size_t pre_padding);
135
136
  void* allocation_;
137
  JxlMemoryManager* memory_manager_;
138
  void* address_;
139
};
140
141
template <typename T>
142
class AlignedArray {
143
 public:
144
558
  AlignedArray() : size_(0) {}
145
146
  static StatusOr<AlignedArray> Create(JxlMemoryManager* memory_manager,
147
558
                                       size_t size) {
148
558
    size_t storage_size = size * sizeof(T);
149
558
    JXL_ASSIGN_OR_RETURN(AlignedMemory storage,
150
558
                         AlignedMemory::Create(memory_manager, storage_size));
151
558
    T* items = storage.address<T>();
152
1.11k
    for (size_t i = 0; i < size; ++i) {
153
558
      new (items + i) T();
154
558
    }
155
558
    return AlignedArray<T>(std::move(storage), size);
156
558
  }
157
158
  // Copy disallowed.
159
  AlignedArray(const AlignedArray& other) = delete;
160
  AlignedArray& operator=(const AlignedArray& other) = delete;
161
162
  // Custom move.
163
1.11k
  AlignedArray(AlignedArray&& other) noexcept {
164
1.11k
    size_ = other.size_;
165
1.11k
    storage_ = std::move(other.storage_);
166
1.11k
    other.size_ = 0;
167
1.11k
  }
168
169
558
  AlignedArray& operator=(AlignedArray&& other) noexcept {
170
558
    if (this == &other) return *this;
171
558
    size_ = other.size_;
172
558
    storage_ = std::move(other.storage_);
173
558
    other.size_ = 0;
174
558
    return *this;
175
558
  }
176
177
2.23k
  ~AlignedArray() {
178
2.23k
    if (!size_) return;
179
558
    T* items = storage_.address<T>();
180
1.11k
    for (size_t i = 0; i < size_; ++i) {
181
558
      items[i].~T();
182
558
    }
183
558
  }
184
185
1.78k
  T& operator[](const size_t i) {
186
1.78k
    JXL_DASSERT(i < size_);
187
1.78k
    return *(storage_.address<T>() + i);
188
1.78k
  }
189
  const T& operator[](const size_t i) const {
190
    JXL_DASSERT(i < size_);
191
    return *(storage_.address<T>() + i);
192
  }
193
194
 private:
195
  explicit AlignedArray(AlignedMemory&& storage, size_t size)
196
558
      : size_(size), storage_(std::move(storage)) {}
197
  size_t size_;
198
  AlignedMemory storage_;
199
};
200
201
}  // namespace jxl
202
203
#endif  // LIB_JXL_MEMORY_MANAGER_INTERNAL_H_