Coverage Report

Created: 2026-09-14 07:37

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