summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt34
-rw-r--r--src/common/bit_cast.h22
-rw-r--r--src/common/bit_set.h99
-rw-r--r--src/common/concepts.h4
-rw-r--r--src/common/div_ceil.h26
-rw-r--r--src/common/fiber.cpp194
-rw-r--r--src/common/fiber.h29
-rw-r--r--src/common/file_util.cpp31
-rw-r--r--src/common/file_util.h2
-rw-r--r--src/common/hex_util.h10
-rw-r--r--src/common/logging/backend.cpp17
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/math_util.h8
-rw-r--r--src/common/memory_hook.cpp11
-rw-r--r--src/common/memory_hook.h47
-rw-r--r--src/common/misc.cpp15
-rw-r--r--src/common/multi_level_queue.h345
-rw-r--r--src/common/page_table.cpp12
-rw-r--r--src/common/page_table.h100
-rw-r--r--src/common/scope_exit.h2
-rw-r--r--src/common/spin_lock.h8
-rw-r--r--src/common/stream.cpp47
-rw-r--r--src/common/stream.h56
-rw-r--r--src/common/string_util.cpp5
-rw-r--r--src/common/swap.h4
-rw-r--r--src/common/telemetry.h4
-rw-r--r--src/common/thread_worker.cpp58
-rw-r--r--src/common/thread_worker.h30
-rw-r--r--src/common/timer.cpp12
-rw-r--r--src/common/vector_math.h75
-rw-r--r--src/common/virtual_buffer.cpp4
-rw-r--r--src/common/virtual_buffer.h38
-rw-r--r--src/common/wall_clock.cpp8
-rw-r--r--src/common/wall_clock.h8
-rw-r--r--src/common/x64/native_clock.cpp8
-rw-r--r--src/common/x64/native_clock.h7
-rw-r--r--src/common/x64/xbyak_abi.h20
37 files changed, 700 insertions, 701 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 5d54516eb..2c2bd2ee8 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -102,7 +102,9 @@ add_library(common STATIC
102 atomic_ops.h 102 atomic_ops.h
103 detached_tasks.cpp 103 detached_tasks.cpp
104 detached_tasks.h 104 detached_tasks.h
105 bit_cast.h
105 bit_field.h 106 bit_field.h
107 bit_set.h
106 bit_util.h 108 bit_util.h
107 cityhash.cpp 109 cityhash.cpp
108 cityhash.h 110 cityhash.h
@@ -111,6 +113,7 @@ add_library(common STATIC
111 common_paths.h 113 common_paths.h
112 common_types.h 114 common_types.h
113 concepts.h 115 concepts.h
116 div_ceil.h
114 dynamic_library.cpp 117 dynamic_library.cpp
115 dynamic_library.h 118 dynamic_library.h
116 fiber.cpp 119 fiber.cpp
@@ -132,13 +135,10 @@ add_library(common STATIC
132 math_util.h 135 math_util.h
133 memory_detect.cpp 136 memory_detect.cpp
134 memory_detect.h 137 memory_detect.h
135 memory_hook.cpp
136 memory_hook.h
137 microprofile.cpp 138 microprofile.cpp
138 microprofile.h 139 microprofile.h
139 microprofileui.h 140 microprofileui.h
140 misc.cpp 141 misc.cpp
141 multi_level_queue.h
142 page_table.cpp 142 page_table.cpp
143 page_table.h 143 page_table.h
144 param_package.cpp 144 param_package.cpp
@@ -150,6 +150,8 @@ add_library(common STATIC
150 scope_exit.h 150 scope_exit.h
151 spin_lock.cpp 151 spin_lock.cpp
152 spin_lock.h 152 spin_lock.h
153 stream.cpp
154 stream.h
153 string_util.cpp 155 string_util.cpp
154 string_util.h 156 string_util.h
155 swap.h 157 swap.h
@@ -158,6 +160,8 @@ add_library(common STATIC
158 thread.cpp 160 thread.cpp
159 thread.h 161 thread.h
160 thread_queue_list.h 162 thread_queue_list.h
163 thread_worker.cpp
164 thread_worker.h
161 threadsafe_queue.h 165 threadsafe_queue.h
162 time_zone.cpp 166 time_zone.cpp
163 time_zone.h 167 time_zone.h
@@ -188,8 +192,28 @@ if(ARCHITECTURE_x86_64)
188 ) 192 )
189endif() 193endif()
190 194
195if (MSVC)
196 target_compile_definitions(common PRIVATE
197 # The standard library doesn't provide any replacement for codecvt yet
198 # so we can disable this deprecation warning for the time being.
199 _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING
200 )
201 target_compile_options(common PRIVATE
202 /W4
203 /WX
204 )
205else()
206 target_compile_options(common PRIVATE
207 -Werror
208 )
209endif()
210
191create_target_directory_groups(common) 211create_target_directory_groups(common)
192find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
193 212
194target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile) 213target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile)
195target_link_libraries(common PRIVATE lz4::lz4 zstd::zstd xbyak) 214target_link_libraries(common PRIVATE lz4::lz4 xbyak)
215if (MSVC)
216 target_link_libraries(common PRIVATE zstd::zstd)
217else()
218 target_link_libraries(common PRIVATE zstd)
219endif()
diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h
new file mode 100644
index 000000000..a32a063d1
--- /dev/null
+++ b/src/common/bit_cast.h
@@ -0,0 +1,22 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstring>
8#include <type_traits>
9
10namespace Common {
11
12template <typename To, typename From>
13[[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> &&
14 std::is_trivially_copyable_v<To>,
15 To>
16BitCast(const From& src) noexcept {
17 To dst;
18 std::memcpy(&dst, &src, sizeof(To));
19 return dst;
20}
21
22} // namespace Common
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
new file mode 100644
index 000000000..9235ad412
--- /dev/null
+++ b/src/common/bit_set.h
@@ -0,0 +1,99 @@
1/*
2 * Copyright (c) 2018-2020 Atmosphère-NX
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#pragma once
18
19#include <array>
20#include <bit>
21
22#include "common/alignment.h"
23#include "common/bit_util.h"
24#include "common/common_types.h"
25
26namespace Common {
27
28namespace impl {
29
30template <typename Storage, size_t N>
31class BitSet {
32
33public:
34 constexpr BitSet() = default;
35
36 constexpr void SetBit(size_t i) {
37 this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord);
38 }
39
40 constexpr void ClearBit(size_t i) {
41 this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord);
42 }
43
44 constexpr size_t CountLeadingZero() const {
45 for (size_t i = 0; i < NumWords; i++) {
46 if (this->words[i]) {
47 return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]);
48 }
49 }
50 return FlagsPerWord * NumWords;
51 }
52
53 constexpr size_t GetNextSet(size_t n) const {
54 for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) {
55 Storage word = this->words[i];
56 if (!IsAligned(n + 1, FlagsPerWord)) {
57 word &= GetBitMask(n % FlagsPerWord) - 1;
58 }
59 if (word) {
60 return FlagsPerWord * i + CountLeadingZeroImpl(word);
61 }
62 }
63 return FlagsPerWord * NumWords;
64 }
65
66private:
67 static_assert(std::is_unsigned_v<Storage>);
68 static_assert(sizeof(Storage) <= sizeof(u64));
69
70 static constexpr size_t FlagsPerWord = BitSize<Storage>();
71 static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord;
72
73 static constexpr auto CountLeadingZeroImpl(Storage word) {
74 return std::countl_zero(static_cast<unsigned long long>(word)) -
75 (BitSize<unsigned long long>() - FlagsPerWord);
76 }
77
78 static constexpr Storage GetBitMask(size_t bit) {
79 return Storage(1) << (FlagsPerWord - 1 - bit);
80 }
81
82 std::array<Storage, NumWords> words{};
83};
84
85} // namespace impl
86
87template <size_t N>
88using BitSet8 = impl::BitSet<u8, N>;
89
90template <size_t N>
91using BitSet16 = impl::BitSet<u16, N>;
92
93template <size_t N>
94using BitSet32 = impl::BitSet<u32, N>;
95
96template <size_t N>
97using BitSet64 = impl::BitSet<u64, N>;
98
99} // namespace Common
diff --git a/src/common/concepts.h b/src/common/concepts.h
index 5bef3ad67..aa08065a7 100644
--- a/src/common/concepts.h
+++ b/src/common/concepts.h
@@ -31,4 +31,8 @@ concept DerivedFrom = requires {
31 std::is_convertible_v<const volatile Derived*, const volatile Base*>; 31 std::is_convertible_v<const volatile Derived*, const volatile Base*>;
32}; 32};
33 33
34// TODO: Replace with std::convertible_to when libc++ implements it.
35template <typename From, typename To>
36concept ConvertibleTo = std::is_convertible_v<From, To>;
37
34} // namespace Common 38} // namespace Common
diff --git a/src/common/div_ceil.h b/src/common/div_ceil.h
new file mode 100644
index 000000000..95e1489a9
--- /dev/null
+++ b/src/common/div_ceil.h
@@ -0,0 +1,26 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <type_traits>
9
10namespace Common {
11
12/// Ceiled integer division.
13template <typename N, typename D>
14requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeil(N number,
15 D divisor) {
16 return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
17}
18
19/// Ceiled integer division with logarithmic divisor in base 2
20template <typename N, typename D>
21requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr N DivCeilLog2(
22 N value, D alignment_log2) {
23 return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
24}
25
26} // namespace Common
diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp
index 1c1d09ccb..3c1eefcb7 100644
--- a/src/common/fiber.cpp
+++ b/src/common/fiber.cpp
@@ -4,129 +4,51 @@
4 4
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/fiber.h" 6#include "common/fiber.h"
7#if defined(_WIN32) || defined(WIN32) 7#include "common/spin_lock.h"
8#include <windows.h> 8#include "common/virtual_buffer.h"
9#else 9
10#include <boost/context/detail/fcontext.hpp> 10#include <boost/context/detail/fcontext.hpp>
11#endif
12 11
13namespace Common { 12namespace Common {
14 13
15constexpr std::size_t default_stack_size = 256 * 1024; // 256kb 14constexpr std::size_t default_stack_size = 256 * 1024;
16
17#if defined(_WIN32) || defined(WIN32)
18 15
19struct Fiber::FiberImpl { 16struct Fiber::FiberImpl {
20 LPVOID handle = nullptr; 17 FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
21 LPVOID rewind_handle = nullptr; 18
19 VirtualBuffer<u8> stack;
20 VirtualBuffer<u8> rewind_stack;
21
22 SpinLock guard{};
23 std::function<void(void*)> entry_point;
24 std::function<void(void*)> rewind_point;
25 void* rewind_parameter{};
26 void* start_parameter{};
27 std::shared_ptr<Fiber> previous_fiber;
28 bool is_thread_fiber{};
29 bool released{};
30
31 u8* stack_limit{};
32 u8* rewind_stack_limit{};
33 boost::context::detail::fcontext_t context{};
34 boost::context::detail::fcontext_t rewind_context{};
22}; 35};
23 36
24void Fiber::Start() { 37void Fiber::SetStartParameter(void* new_parameter) {
25 ASSERT(previous_fiber != nullptr); 38 impl->start_parameter = new_parameter;
26 previous_fiber->guard.unlock();
27 previous_fiber.reset();
28 entry_point(start_parameter);
29 UNREACHABLE();
30}
31
32void Fiber::OnRewind() {
33 ASSERT(impl->handle != nullptr);
34 DeleteFiber(impl->handle);
35 impl->handle = impl->rewind_handle;
36 impl->rewind_handle = nullptr;
37 rewind_point(rewind_parameter);
38 UNREACHABLE();
39}
40
41void Fiber::FiberStartFunc(void* fiber_parameter) {
42 auto fiber = static_cast<Fiber*>(fiber_parameter);
43 fiber->Start();
44}
45
46void Fiber::RewindStartFunc(void* fiber_parameter) {
47 auto fiber = static_cast<Fiber*>(fiber_parameter);
48 fiber->OnRewind();
49}
50
51Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
52 : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} {
53 impl = std::make_unique<FiberImpl>();
54 impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
55}
56
57Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
58
59Fiber::~Fiber() {
60 if (released) {
61 return;
62 }
63 // Make sure the Fiber is not being used
64 const bool locked = guard.try_lock();
65 ASSERT_MSG(locked, "Destroying a fiber that's still running");
66 if (locked) {
67 guard.unlock();
68 }
69 DeleteFiber(impl->handle);
70}
71
72void Fiber::Exit() {
73 ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber");
74 if (!is_thread_fiber) {
75 return;
76 }
77 ConvertFiberToThread();
78 guard.unlock();
79 released = true;
80}
81
82void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
83 rewind_point = std::move(rewind_func);
84 rewind_parameter = start_parameter;
85}
86
87void Fiber::Rewind() {
88 ASSERT(rewind_point);
89 ASSERT(impl->rewind_handle == nullptr);
90 impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
91 SwitchToFiber(impl->rewind_handle);
92}
93
94void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) {
95 ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
96 ASSERT_MSG(to != nullptr, "Next fiber is null!");
97 to->guard.lock();
98 to->previous_fiber = from;
99 SwitchToFiber(to->impl->handle);
100 ASSERT(from->previous_fiber != nullptr);
101 from->previous_fiber->guard.unlock();
102 from->previous_fiber.reset();
103} 39}
104 40
105std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 41void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param) {
106 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; 42 impl->rewind_point = std::move(rewind_func);
107 fiber->guard.lock(); 43 impl->rewind_parameter = rewind_param;
108 fiber->impl->handle = ConvertThreadToFiber(nullptr);
109 fiber->is_thread_fiber = true;
110 return fiber;
111} 44}
112 45
113#else
114
115struct Fiber::FiberImpl {
116 alignas(64) std::array<u8, default_stack_size> stack;
117 alignas(64) std::array<u8, default_stack_size> rewind_stack;
118 u8* stack_limit;
119 u8* rewind_stack_limit;
120 boost::context::detail::fcontext_t context;
121 boost::context::detail::fcontext_t rewind_context;
122};
123
124void Fiber::Start(boost::context::detail::transfer_t& transfer) { 46void Fiber::Start(boost::context::detail::transfer_t& transfer) {
125 ASSERT(previous_fiber != nullptr); 47 ASSERT(impl->previous_fiber != nullptr);
126 previous_fiber->impl->context = transfer.fctx; 48 impl->previous_fiber->impl->context = transfer.fctx;
127 previous_fiber->guard.unlock(); 49 impl->previous_fiber->impl->guard.unlock();
128 previous_fiber.reset(); 50 impl->previous_fiber.reset();
129 entry_point(start_parameter); 51 impl->entry_point(impl->start_parameter);
130 UNREACHABLE(); 52 UNREACHABLE();
131} 53}
132 54
@@ -137,23 +59,24 @@ void Fiber::OnRewind([[maybe_unused]] boost::context::detail::transfer_t& transf
137 u8* tmp = impl->stack_limit; 59 u8* tmp = impl->stack_limit;
138 impl->stack_limit = impl->rewind_stack_limit; 60 impl->stack_limit = impl->rewind_stack_limit;
139 impl->rewind_stack_limit = tmp; 61 impl->rewind_stack_limit = tmp;
140 rewind_point(rewind_parameter); 62 impl->rewind_point(impl->rewind_parameter);
141 UNREACHABLE(); 63 UNREACHABLE();
142} 64}
143 65
144void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) { 66void Fiber::FiberStartFunc(boost::context::detail::transfer_t transfer) {
145 auto fiber = static_cast<Fiber*>(transfer.data); 67 auto* fiber = static_cast<Fiber*>(transfer.data);
146 fiber->Start(transfer); 68 fiber->Start(transfer);
147} 69}
148 70
149void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) { 71void Fiber::RewindStartFunc(boost::context::detail::transfer_t transfer) {
150 auto fiber = static_cast<Fiber*>(transfer.data); 72 auto* fiber = static_cast<Fiber*>(transfer.data);
151 fiber->OnRewind(transfer); 73 fiber->OnRewind(transfer);
152} 74}
153 75
154Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter) 76Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
155 : entry_point{std::move(entry_point_func)}, start_parameter{start_parameter} { 77 : impl{std::make_unique<FiberImpl>()} {
156 impl = std::make_unique<FiberImpl>(); 78 impl->entry_point = std::move(entry_point_func);
79 impl->start_parameter = start_parameter;
157 impl->stack_limit = impl->stack.data(); 80 impl->stack_limit = impl->stack.data();
158 impl->rewind_stack_limit = impl->rewind_stack.data(); 81 impl->rewind_stack_limit = impl->rewind_stack.data();
159 u8* stack_base = impl->stack_limit + default_stack_size; 82 u8* stack_base = impl->stack_limit + default_stack_size;
@@ -161,37 +84,31 @@ Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_paramete
161 boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc); 84 boost::context::detail::make_fcontext(stack_base, impl->stack.size(), FiberStartFunc);
162} 85}
163 86
164void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter) {
165 rewind_point = std::move(rewind_func);
166 rewind_parameter = start_parameter;
167}
168
169Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {} 87Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
170 88
171Fiber::~Fiber() { 89Fiber::~Fiber() {
172 if (released) { 90 if (impl->released) {
173 return; 91 return;
174 } 92 }
175 // Make sure the Fiber is not being used 93 // Make sure the Fiber is not being used
176 const bool locked = guard.try_lock(); 94 const bool locked = impl->guard.try_lock();
177 ASSERT_MSG(locked, "Destroying a fiber that's still running"); 95 ASSERT_MSG(locked, "Destroying a fiber that's still running");
178 if (locked) { 96 if (locked) {
179 guard.unlock(); 97 impl->guard.unlock();
180 } 98 }
181} 99}
182 100
183void Fiber::Exit() { 101void Fiber::Exit() {
184 102 ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
185 ASSERT_MSG(is_thread_fiber, "Exitting non main thread fiber"); 103 if (!impl->is_thread_fiber) {
186 if (!is_thread_fiber) {
187 return; 104 return;
188 } 105 }
189 guard.unlock(); 106 impl->guard.unlock();
190 released = true; 107 impl->released = true;
191} 108}
192 109
193void Fiber::Rewind() { 110void Fiber::Rewind() {
194 ASSERT(rewind_point); 111 ASSERT(impl->rewind_point);
195 ASSERT(impl->rewind_context == nullptr); 112 ASSERT(impl->rewind_context == nullptr);
196 u8* stack_base = impl->rewind_stack_limit + default_stack_size; 113 u8* stack_base = impl->rewind_stack_limit + default_stack_size;
197 impl->rewind_context = 114 impl->rewind_context =
@@ -199,24 +116,23 @@ void Fiber::Rewind() {
199 boost::context::detail::jump_fcontext(impl->rewind_context, this); 116 boost::context::detail::jump_fcontext(impl->rewind_context, this);
200} 117}
201 118
202void Fiber::YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to) { 119void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
203 ASSERT_MSG(from != nullptr, "Yielding fiber is null!"); 120 ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
204 ASSERT_MSG(to != nullptr, "Next fiber is null!"); 121 ASSERT_MSG(to != nullptr, "Next fiber is null!");
205 to->guard.lock(); 122 to->impl->guard.lock();
206 to->previous_fiber = from; 123 to->impl->previous_fiber = from;
207 auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get()); 124 auto transfer = boost::context::detail::jump_fcontext(to->impl->context, to.get());
208 ASSERT(from->previous_fiber != nullptr); 125 ASSERT(from->impl->previous_fiber != nullptr);
209 from->previous_fiber->impl->context = transfer.fctx; 126 from->impl->previous_fiber->impl->context = transfer.fctx;
210 from->previous_fiber->guard.unlock(); 127 from->impl->previous_fiber->impl->guard.unlock();
211 from->previous_fiber.reset(); 128 from->impl->previous_fiber.reset();
212} 129}
213 130
214std::shared_ptr<Fiber> Fiber::ThreadToFiber() { 131std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
215 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()}; 132 std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
216 fiber->guard.lock(); 133 fiber->impl->guard.lock();
217 fiber->is_thread_fiber = true; 134 fiber->impl->is_thread_fiber = true;
218 return fiber; 135 return fiber;
219} 136}
220 137
221#endif
222} // namespace Common 138} // namespace Common
diff --git a/src/common/fiber.h b/src/common/fiber.h
index 89dde5e36..f7f587f8c 100644
--- a/src/common/fiber.h
+++ b/src/common/fiber.h
@@ -7,14 +7,9 @@
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9 9
10#include "common/common_types.h"
11#include "common/spin_lock.h"
12
13#if !defined(_WIN32) && !defined(WIN32)
14namespace boost::context::detail { 10namespace boost::context::detail {
15struct transfer_t; 11struct transfer_t;
16} 12}
17#endif
18 13
19namespace Common { 14namespace Common {
20 15
@@ -46,10 +41,10 @@ public:
46 41
47 /// Yields control from Fiber 'from' to Fiber 'to' 42 /// Yields control from Fiber 'from' to Fiber 'to'
48 /// Fiber 'from' must be the currently running fiber. 43 /// Fiber 'from' must be the currently running fiber.
49 static void YieldTo(std::shared_ptr<Fiber>& from, std::shared_ptr<Fiber>& to); 44 static void YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to);
50 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber(); 45 [[nodiscard]] static std::shared_ptr<Fiber> ThreadToFiber();
51 46
52 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* start_parameter); 47 void SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewind_param);
53 48
54 void Rewind(); 49 void Rewind();
55 50
@@ -57,36 +52,18 @@ public:
57 void Exit(); 52 void Exit();
58 53
59 /// Changes the start parameter of the fiber. Has no effect if the fiber already started 54 /// Changes the start parameter of the fiber. Has no effect if the fiber already started
60 void SetStartParameter(void* new_parameter) { 55 void SetStartParameter(void* new_parameter);
61 start_parameter = new_parameter;
62 }
63 56
64private: 57private:
65 Fiber(); 58 Fiber();
66 59
67#if defined(_WIN32) || defined(WIN32)
68 void OnRewind();
69 void Start();
70 static void FiberStartFunc(void* fiber_parameter);
71 static void RewindStartFunc(void* fiber_parameter);
72#else
73 void OnRewind(boost::context::detail::transfer_t& transfer); 60 void OnRewind(boost::context::detail::transfer_t& transfer);
74 void Start(boost::context::detail::transfer_t& transfer); 61 void Start(boost::context::detail::transfer_t& transfer);
75 static void FiberStartFunc(boost::context::detail::transfer_t transfer); 62 static void FiberStartFunc(boost::context::detail::transfer_t transfer);
76 static void RewindStartFunc(boost::context::detail::transfer_t transfer); 63 static void RewindStartFunc(boost::context::detail::transfer_t transfer);
77#endif
78 64
79 struct FiberImpl; 65 struct FiberImpl;
80
81 SpinLock guard{};
82 std::function<void(void*)> entry_point;
83 std::function<void(void*)> rewind_point;
84 void* rewind_parameter{};
85 void* start_parameter{};
86 std::shared_ptr<Fiber> previous_fiber;
87 std::unique_ptr<FiberImpl> impl; 66 std::unique_ptr<FiberImpl> impl;
88 bool is_thread_fiber{};
89 bool released{};
90}; 67};
91 68
92} // namespace Common 69} // namespace Common
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 16c3713e0..18fbfa25b 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -472,13 +472,14 @@ u64 ScanDirectoryTree(const std::string& directory, FSTEntry& parent_entry,
472} 472}
473 473
474bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) { 474bool DeleteDirRecursively(const std::string& directory, unsigned int recursion) {
475 const auto callback = [recursion](u64* num_entries_out, const std::string& directory, 475 const auto callback = [recursion](u64*, const std::string& directory,
476 const std::string& virtual_name) -> bool { 476 const std::string& virtual_name) {
477 std::string new_path = directory + DIR_SEP_CHR + virtual_name; 477 const std::string new_path = directory + DIR_SEP_CHR + virtual_name;
478 478
479 if (IsDirectory(new_path)) { 479 if (IsDirectory(new_path)) {
480 if (recursion == 0) 480 if (recursion == 0) {
481 return false; 481 return false;
482 }
482 return DeleteDirRecursively(new_path, recursion - 1); 483 return DeleteDirRecursively(new_path, recursion - 1);
483 } 484 }
484 return Delete(new_path); 485 return Delete(new_path);
@@ -492,7 +493,8 @@ bool DeleteDirRecursively(const std::string& directory, unsigned int recursion)
492 return true; 493 return true;
493} 494}
494 495
495void CopyDir(const std::string& source_path, const std::string& dest_path) { 496void CopyDir([[maybe_unused]] const std::string& source_path,
497 [[maybe_unused]] const std::string& dest_path) {
496#ifndef _WIN32 498#ifndef _WIN32
497 if (source_path == dest_path) { 499 if (source_path == dest_path) {
498 return; 500 return;
@@ -553,7 +555,7 @@ std::optional<std::string> GetCurrentDir() {
553 std::string strDir = dir; 555 std::string strDir = dir;
554#endif 556#endif
555 free(dir); 557 free(dir);
556 return std::move(strDir); 558 return strDir;
557} 559}
558 560
559bool SetCurrentDir(const std::string& directory) { 561bool SetCurrentDir(const std::string& directory) {
@@ -772,21 +774,23 @@ std::size_t ReadFileToString(bool text_file, const std::string& filename, std::s
772 774
773void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name, 775void SplitFilename83(const std::string& filename, std::array<char, 9>& short_name,
774 std::array<char, 4>& extension) { 776 std::array<char, 4>& extension) {
775 const std::string forbidden_characters = ".\"/\\[]:;=, "; 777 static constexpr std::string_view forbidden_characters = ".\"/\\[]:;=, ";
776 778
777 // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces. 779 // On a FAT32 partition, 8.3 names are stored as a 11 bytes array, filled with spaces.
778 short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}}; 780 short_name = {{' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '\0'}};
779 extension = {{' ', ' ', ' ', '\0'}}; 781 extension = {{' ', ' ', ' ', '\0'}};
780 782
781 std::string::size_type point = filename.rfind('.'); 783 auto point = filename.rfind('.');
782 if (point == filename.size() - 1) 784 if (point == filename.size() - 1) {
783 point = filename.rfind('.', point); 785 point = filename.rfind('.', point);
786 }
784 787
785 // Get short name. 788 // Get short name.
786 int j = 0; 789 int j = 0;
787 for (char letter : filename.substr(0, point)) { 790 for (char letter : filename.substr(0, point)) {
788 if (forbidden_characters.find(letter, 0) != std::string::npos) 791 if (forbidden_characters.find(letter, 0) != std::string::npos) {
789 continue; 792 continue;
793 }
790 if (j == 8) { 794 if (j == 8) {
791 // TODO(Link Mauve): also do that for filenames containing a space. 795 // TODO(Link Mauve): also do that for filenames containing a space.
792 // TODO(Link Mauve): handle multiple files having the same short name. 796 // TODO(Link Mauve): handle multiple files having the same short name.
@@ -794,14 +798,15 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
794 short_name[7] = '1'; 798 short_name[7] = '1';
795 break; 799 break;
796 } 800 }
797 short_name[j++] = toupper(letter); 801 short_name[j++] = static_cast<char>(std::toupper(letter));
798 } 802 }
799 803
800 // Get extension. 804 // Get extension.
801 if (point != std::string::npos) { 805 if (point != std::string::npos) {
802 j = 0; 806 j = 0;
803 for (char letter : filename.substr(point + 1, 3)) 807 for (char letter : filename.substr(point + 1, 3)) {
804 extension[j++] = toupper(letter); 808 extension[j++] = static_cast<char>(std::toupper(letter));
809 }
805 } 810 }
806} 811}
807 812
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 8b587320f..840cde2a6 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -232,7 +232,7 @@ public:
232 232
233 void Swap(IOFile& other) noexcept; 233 void Swap(IOFile& other) noexcept;
234 234
235 [[nodiscard]] bool Open(const std::string& filename, const char openmode[], int flags = 0); 235 bool Open(const std::string& filename, const char openmode[], int flags = 0);
236 bool Close(); 236 bool Close();
237 237
238 template <typename T> 238 template <typename T>
diff --git a/src/common/hex_util.h b/src/common/hex_util.h
index 120f1a5e6..a8d414fb8 100644
--- a/src/common/hex_util.h
+++ b/src/common/hex_util.h
@@ -16,14 +16,14 @@ namespace Common {
16 16
17[[nodiscard]] constexpr u8 ToHexNibble(char c) { 17[[nodiscard]] constexpr u8 ToHexNibble(char c) {
18 if (c >= 65 && c <= 70) { 18 if (c >= 65 && c <= 70) {
19 return c - 55; 19 return static_cast<u8>(c - 55);
20 } 20 }
21 21
22 if (c >= 97 && c <= 102) { 22 if (c >= 97 && c <= 102) {
23 return c - 87; 23 return static_cast<u8>(c - 87);
24 } 24 }
25 25
26 return c - 48; 26 return static_cast<u8>(c - 48);
27} 27}
28 28
29[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); 29[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
@@ -33,11 +33,11 @@ template <std::size_t Size, bool le = false>
33 std::array<u8, Size> out{}; 33 std::array<u8, Size> out{};
34 if constexpr (le) { 34 if constexpr (le) {
35 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { 35 for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
36 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 36 out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
37 } 37 }
38 } else { 38 } else {
39 for (std::size_t i = 0; i < 2 * Size; i += 2) { 39 for (std::size_t i = 0; i < 2 * Size; i += 2) {
40 out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); 40 out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
41 } 41 }
42 } 42 }
43 return out; 43 return out;
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 62cfde397..631f64d05 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -23,6 +23,7 @@
23#include "common/logging/text_formatter.h" 23#include "common/logging/text_formatter.h"
24#include "common/string_util.h" 24#include "common/string_util.h"
25#include "common/threadsafe_queue.h" 25#include "common/threadsafe_queue.h"
26#include "core/settings.h"
26 27
27namespace Log { 28namespace Log {
28 29
@@ -152,10 +153,19 @@ FileBackend::FileBackend(const std::string& filename)
152void FileBackend::Write(const Entry& entry) { 153void FileBackend::Write(const Entry& entry) {
153 // prevent logs from going over the maximum size (in case its spamming and the user doesn't 154 // prevent logs from going over the maximum size (in case its spamming and the user doesn't
154 // know) 155 // know)
155 constexpr std::size_t MAX_BYTES_WRITTEN = 50 * 1024L * 1024L; 156 constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024;
156 if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) { 157 constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024;
158
159 if (!file.IsOpen()) {
160 return;
161 }
162
163 if (Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN_EXTENDED) {
164 return;
165 } else if (!Settings::values.extended_logging && bytes_written > MAX_BYTES_WRITTEN) {
157 return; 166 return;
158 } 167 }
168
159 bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n')); 169 bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));
160 if (entry.log_level >= Level::Error) { 170 if (entry.log_level >= Level::Error) {
161 file.Flush(); 171 file.Flush();
@@ -222,6 +232,7 @@ void DebuggerBackend::Write(const Entry& entry) {
222 SUB(Service, NPNS) \ 232 SUB(Service, NPNS) \
223 SUB(Service, NS) \ 233 SUB(Service, NS) \
224 SUB(Service, NVDRV) \ 234 SUB(Service, NVDRV) \
235 SUB(Service, OLSC) \
225 SUB(Service, PCIE) \ 236 SUB(Service, PCIE) \
226 SUB(Service, PCTL) \ 237 SUB(Service, PCTL) \
227 SUB(Service, PCV) \ 238 SUB(Service, PCV) \
@@ -274,7 +285,6 @@ const char* GetLogClassName(Class log_class) {
274 case Class::Count: 285 case Class::Count:
275 break; 286 break;
276 } 287 }
277 UNREACHABLE();
278 return "Invalid"; 288 return "Invalid";
279} 289}
280 290
@@ -293,7 +303,6 @@ const char* GetLevelName(Level log_level) {
293 break; 303 break;
294 } 304 }
295#undef LVL 305#undef LVL
296 UNREACHABLE();
297 return "Invalid"; 306 return "Invalid";
298} 307}
299 308
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 13a4f1e30..835894918 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -95,6 +95,7 @@ enum class Class : ClassType {
95 Service_NPNS, ///< The NPNS service 95 Service_NPNS, ///< The NPNS service
96 Service_NS, ///< The NS services 96 Service_NS, ///< The NS services
97 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 97 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
98 Service_OLSC, ///< The OLSC service
98 Service_PCIE, ///< The PCIe service 99 Service_PCIE, ///< The PCIe service
99 Service_PCTL, ///< The PCTL (Parental control) service 100 Service_PCTL, ///< The PCTL (Parental control) service
100 Service_PCV, ///< The PCV service 101 Service_PCV, ///< The PCV service
diff --git a/src/common/math_util.h b/src/common/math_util.h
index b35ad8507..4c38d8040 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -20,14 +20,14 @@ struct Rectangle {
20 20
21 constexpr Rectangle() = default; 21 constexpr Rectangle() = default;
22 22
23 constexpr Rectangle(T left, T top, T right, T bottom) 23 constexpr Rectangle(T left_, T top_, T right_, T bottom_)
24 : left(left), top(top), right(right), bottom(bottom) {} 24 : left(left_), top(top_), right(right_), bottom(bottom_) {}
25 25
26 [[nodiscard]] T GetWidth() const { 26 [[nodiscard]] T GetWidth() const {
27 if constexpr (std::is_floating_point_v<T>) { 27 if constexpr (std::is_floating_point_v<T>) {
28 return std::abs(right - left); 28 return std::abs(right - left);
29 } else { 29 } else {
30 return std::abs(static_cast<std::make_signed_t<T>>(right - left)); 30 return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(right - left)));
31 } 31 }
32 } 32 }
33 33
@@ -35,7 +35,7 @@ struct Rectangle {
35 if constexpr (std::is_floating_point_v<T>) { 35 if constexpr (std::is_floating_point_v<T>) {
36 return std::abs(bottom - top); 36 return std::abs(bottom - top);
37 } else { 37 } else {
38 return std::abs(static_cast<std::make_signed_t<T>>(bottom - top)); 38 return static_cast<T>(std::abs(static_cast<std::make_signed_t<T>>(bottom - top)));
39 } 39 }
40 } 40 }
41 41
diff --git a/src/common/memory_hook.cpp b/src/common/memory_hook.cpp
deleted file mode 100644
index 3986986d6..000000000
--- a/src/common/memory_hook.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
1// Copyright 2018 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/memory_hook.h"
6
7namespace Common {
8
9MemoryHook::~MemoryHook() = default;
10
11} // namespace Common
diff --git a/src/common/memory_hook.h b/src/common/memory_hook.h
deleted file mode 100644
index adaa4c2c5..000000000
--- a/src/common/memory_hook.h
+++ /dev/null
@@ -1,47 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8#include <optional>
9
10#include "common/common_types.h"
11
12namespace Common {
13
14/**
15 * Memory hooks have two purposes:
16 * 1. To allow reads and writes to a region of memory to be intercepted. This is used to implement
17 * texture forwarding and memory breakpoints for debugging.
18 * 2. To allow for the implementation of MMIO devices.
19 *
20 * A hook may be mapped to multiple regions of memory.
21 *
22 * If a std::nullopt or false is returned from a function, the read/write request is passed through
23 * to the underlying memory region.
24 */
25class MemoryHook {
26public:
27 virtual ~MemoryHook();
28
29 virtual std::optional<bool> IsValidAddress(VAddr addr) = 0;
30
31 virtual std::optional<u8> Read8(VAddr addr) = 0;
32 virtual std::optional<u16> Read16(VAddr addr) = 0;
33 virtual std::optional<u32> Read32(VAddr addr) = 0;
34 virtual std::optional<u64> Read64(VAddr addr) = 0;
35
36 virtual bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) = 0;
37
38 virtual bool Write8(VAddr addr, u8 data) = 0;
39 virtual bool Write16(VAddr addr, u16 data) = 0;
40 virtual bool Write32(VAddr addr, u32 data) = 0;
41 virtual bool Write64(VAddr addr, u64 data) = 0;
42
43 virtual bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) = 0;
44};
45
46using MemoryHookPointer = std::shared_ptr<MemoryHook>;
47} // namespace Common
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 68cb86cd1..1d5393597 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -16,16 +16,23 @@
16// Call directly after the command or use the error num. 16// Call directly after the command or use the error num.
17// This function might change the error code. 17// This function might change the error code.
18std::string GetLastErrorMsg() { 18std::string GetLastErrorMsg() {
19 static const std::size_t buff_size = 255; 19 static constexpr std::size_t buff_size = 255;
20 char err_str[buff_size]; 20 char err_str[buff_size];
21 21
22#ifdef _WIN32 22#ifdef _WIN32
23 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(), 23 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
24 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr); 24 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err_str, buff_size, nullptr);
25 return std::string(err_str, buff_size);
26#elif defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
27 // Thread safe (GNU-specific)
28 const char* str = strerror_r(errno, err_str, buff_size);
29 return std::string(str);
25#else 30#else
26 // Thread safe (XSI-compliant) 31 // Thread safe (XSI-compliant)
27 strerror_r(errno, err_str, buff_size); 32 const int success = strerror_r(errno, err_str, buff_size);
33 if (success != 0) {
34 return {};
35 }
36 return std::string(err_str);
28#endif 37#endif
29
30 return std::string(err_str, buff_size);
31} 38}
diff --git a/src/common/multi_level_queue.h b/src/common/multi_level_queue.h
deleted file mode 100644
index 4b305bf40..000000000
--- a/src/common/multi_level_queue.h
+++ /dev/null
@@ -1,345 +0,0 @@
1// Copyright 2019 TuxSH
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <iterator>
9#include <list>
10#include <utility>
11
12#include "common/bit_util.h"
13#include "common/common_types.h"
14
15namespace Common {
16
17/**
18 * A MultiLevelQueue is a type of priority queue which has the following characteristics:
19 * - iteratable through each of its elements.
20 * - back can be obtained.
21 * - O(1) add, lookup (both front and back)
22 * - discrete priorities and a max of 64 priorities (limited domain)
23 * This type of priority queue is normaly used for managing threads within an scheduler
24 */
25template <typename T, std::size_t Depth>
26class MultiLevelQueue {
27public:
28 using value_type = T;
29 using reference = value_type&;
30 using const_reference = const value_type&;
31 using pointer = value_type*;
32 using const_pointer = const value_type*;
33
34 using difference_type = typename std::pointer_traits<pointer>::difference_type;
35 using size_type = std::size_t;
36
37 template <bool is_constant>
38 class iterator_impl {
39 public:
40 using iterator_category = std::bidirectional_iterator_tag;
41 using value_type = T;
42 using pointer = std::conditional_t<is_constant, T*, const T*>;
43 using reference = std::conditional_t<is_constant, const T&, T&>;
44 using difference_type = typename std::pointer_traits<pointer>::difference_type;
45
46 friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) {
47 if (lhs.IsEnd() && rhs.IsEnd())
48 return true;
49 return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it);
50 }
51
52 friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) {
53 return !operator==(lhs, rhs);
54 }
55
56 reference operator*() const {
57 return *it;
58 }
59
60 pointer operator->() const {
61 return it.operator->();
62 }
63
64 iterator_impl& operator++() {
65 if (IsEnd()) {
66 return *this;
67 }
68
69 ++it;
70
71 if (it == GetEndItForPrio()) {
72 u64 prios = mlq.used_priorities;
73 prios &= ~((1ULL << (current_priority + 1)) - 1);
74 if (prios == 0) {
75 current_priority = static_cast<u32>(mlq.depth());
76 } else {
77 current_priority = CountTrailingZeroes64(prios);
78 it = GetBeginItForPrio();
79 }
80 }
81 return *this;
82 }
83
84 iterator_impl& operator--() {
85 if (IsEnd()) {
86 if (mlq.used_priorities != 0) {
87 current_priority = 63 - CountLeadingZeroes64(mlq.used_priorities);
88 it = GetEndItForPrio();
89 --it;
90 }
91 } else if (it == GetBeginItForPrio()) {
92 u64 prios = mlq.used_priorities;
93 prios &= (1ULL << current_priority) - 1;
94 if (prios != 0) {
95 current_priority = CountTrailingZeroes64(prios);
96 it = GetEndItForPrio();
97 --it;
98 }
99 } else {
100 --it;
101 }
102 return *this;
103 }
104
105 iterator_impl operator++(int) {
106 const iterator_impl v{*this};
107 ++(*this);
108 return v;
109 }
110
111 iterator_impl operator--(int) {
112 const iterator_impl v{*this};
113 --(*this);
114 return v;
115 }
116
117 // allow implicit const->non-const
118 iterator_impl(const iterator_impl<false>& other)
119 : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
120
121 iterator_impl(const iterator_impl<true>& other)
122 : mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
123
124 iterator_impl& operator=(const iterator_impl<false>& other) {
125 mlq = other.mlq;
126 it = other.it;
127 current_priority = other.current_priority;
128 return *this;
129 }
130
131 friend class iterator_impl<true>;
132 iterator_impl() = default;
133
134 private:
135 friend class MultiLevelQueue;
136 using container_ref =
137 std::conditional_t<is_constant, const MultiLevelQueue&, MultiLevelQueue&>;
138 using list_iterator = std::conditional_t<is_constant, typename std::list<T>::const_iterator,
139 typename std::list<T>::iterator>;
140
141 explicit iterator_impl(container_ref mlq, list_iterator it, u32 current_priority)
142 : mlq(mlq), it(it), current_priority(current_priority) {}
143 explicit iterator_impl(container_ref mlq, u32 current_priority)
144 : mlq(mlq), it(), current_priority(current_priority) {}
145
146 bool IsEnd() const {
147 return current_priority == mlq.depth();
148 }
149
150 list_iterator GetBeginItForPrio() const {
151 return mlq.levels[current_priority].begin();
152 }
153
154 list_iterator GetEndItForPrio() const {
155 return mlq.levels[current_priority].end();
156 }
157
158 container_ref mlq;
159 list_iterator it;
160 u32 current_priority;
161 };
162
163 using iterator = iterator_impl<false>;
164 using const_iterator = iterator_impl<true>;
165
166 void add(const T& element, u32 priority, bool send_back = true) {
167 if (send_back)
168 levels[priority].push_back(element);
169 else
170 levels[priority].push_front(element);
171 used_priorities |= 1ULL << priority;
172 }
173
174 void remove(const T& element, u32 priority) {
175 auto it = ListIterateTo(levels[priority], element);
176 if (it == levels[priority].end())
177 return;
178 levels[priority].erase(it);
179 if (levels[priority].empty()) {
180 used_priorities &= ~(1ULL << priority);
181 }
182 }
183
184 void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) {
185 remove(element, old_priority);
186 add(element, new_priority, !adjust_front);
187 }
188 void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) {
189 adjust(*it, old_priority, new_priority, adjust_front);
190 }
191
192 void transfer_to_front(const T& element, u32 priority, MultiLevelQueue& other) {
193 ListSplice(other.levels[priority], other.levels[priority].begin(), levels[priority],
194 ListIterateTo(levels[priority], element));
195
196 other.used_priorities |= 1ULL << priority;
197
198 if (levels[priority].empty()) {
199 used_priorities &= ~(1ULL << priority);
200 }
201 }
202
203 void transfer_to_front(const_iterator it, u32 priority, MultiLevelQueue& other) {
204 transfer_to_front(*it, priority, other);
205 }
206
207 void transfer_to_back(const T& element, u32 priority, MultiLevelQueue& other) {
208 ListSplice(other.levels[priority], other.levels[priority].end(), levels[priority],
209 ListIterateTo(levels[priority], element));
210
211 other.used_priorities |= 1ULL << priority;
212
213 if (levels[priority].empty()) {
214 used_priorities &= ~(1ULL << priority);
215 }
216 }
217
218 void transfer_to_back(const_iterator it, u32 priority, MultiLevelQueue& other) {
219 transfer_to_back(*it, priority, other);
220 }
221
222 void yield(u32 priority, std::size_t n = 1) {
223 ListShiftForward(levels[priority], n);
224 }
225
226 [[nodiscard]] std::size_t depth() const {
227 return Depth;
228 }
229
230 [[nodiscard]] std::size_t size(u32 priority) const {
231 return levels[priority].size();
232 }
233
234 [[nodiscard]] std::size_t size() const {
235 u64 priorities = used_priorities;
236 std::size_t size = 0;
237 while (priorities != 0) {
238 const u64 current_priority = CountTrailingZeroes64(priorities);
239 size += levels[current_priority].size();
240 priorities &= ~(1ULL << current_priority);
241 }
242 return size;
243 }
244
245 [[nodiscard]] bool empty() const {
246 return used_priorities == 0;
247 }
248
249 [[nodiscard]] bool empty(u32 priority) const {
250 return (used_priorities & (1ULL << priority)) == 0;
251 }
252
253 [[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
254 const u64 priorities =
255 max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
256 return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
257 }
258
259 [[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
260 const u64 priorities = min_priority >= Depth - 1
261 ? used_priorities
262 : (used_priorities & ((1ULL << (min_priority + 1)) - 1));
263 return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
264 }
265
266 [[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
267 const u32 priority = highest_priority_set(max_prio);
268 return priority == Depth ? cend()
269 : const_iterator{*this, levels[priority].cbegin(), priority};
270 }
271 [[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
272 return cbegin(max_prio);
273 }
274 [[nodiscard]] iterator begin(u32 max_prio = 0) {
275 const u32 priority = highest_priority_set(max_prio);
276 return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
277 }
278
279 [[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
280 return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
281 }
282 [[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
283 return cend(min_prio);
284 }
285 [[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
286 return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
287 }
288
289 [[nodiscard]] T& front(u32 max_priority = 0) {
290 const u32 priority = highest_priority_set(max_priority);
291 return levels[priority == Depth ? 0 : priority].front();
292 }
293 [[nodiscard]] const T& front(u32 max_priority = 0) const {
294 const u32 priority = highest_priority_set(max_priority);
295 return levels[priority == Depth ? 0 : priority].front();
296 }
297
298 [[nodiscard]] T& back(u32 min_priority = Depth - 1) {
299 const u32 priority = lowest_priority_set(min_priority); // intended
300 return levels[priority == Depth ? 63 : priority].back();
301 }
302 [[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
303 const u32 priority = lowest_priority_set(min_priority); // intended
304 return levels[priority == Depth ? 63 : priority].back();
305 }
306
307 void clear() {
308 used_priorities = 0;
309 for (std::size_t i = 0; i < Depth; i++) {
310 levels[i].clear();
311 }
312 }
313
314private:
315 using const_list_iterator = typename std::list<T>::const_iterator;
316
317 static void ListShiftForward(std::list<T>& list, const std::size_t shift = 1) {
318 if (shift >= list.size()) {
319 return;
320 }
321
322 const auto begin_range = list.begin();
323 const auto end_range = std::next(begin_range, shift);
324 list.splice(list.end(), list, begin_range, end_range);
325 }
326
327 static void ListSplice(std::list<T>& in_list, const_list_iterator position,
328 std::list<T>& out_list, const_list_iterator element) {
329 in_list.splice(position, out_list, element);
330 }
331
332 [[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
333 const T& element) {
334 auto it = list.cbegin();
335 while (it != list.cend() && *it != element) {
336 ++it;
337 }
338 return it;
339 }
340
341 std::array<std::list<T>, Depth> levels;
342 u64 used_priorities = 0;
343};
344
345} // namespace Common
diff --git a/src/common/page_table.cpp b/src/common/page_table.cpp
index e5d3090d5..8fd8620fd 100644
--- a/src/common/page_table.cpp
+++ b/src/common/page_table.cpp
@@ -8,18 +8,12 @@ namespace Common {
8 8
9PageTable::PageTable() = default; 9PageTable::PageTable() = default;
10 10
11PageTable::~PageTable() = default; 11PageTable::~PageTable() noexcept = default;
12 12
13void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, 13void PageTable::Resize(size_t address_space_width_in_bits, size_t page_size_in_bits) {
14 bool has_attribute) { 14 const size_t num_page_table_entries{1ULL << (address_space_width_in_bits - page_size_in_bits)};
15 const std::size_t num_page_table_entries{1ULL
16 << (address_space_width_in_bits - page_size_in_bits)};
17 pointers.resize(num_page_table_entries); 15 pointers.resize(num_page_table_entries);
18 backing_addr.resize(num_page_table_entries); 16 backing_addr.resize(num_page_table_entries);
19
20 if (has_attribute) {
21 attributes.resize(num_page_table_entries);
22 }
23} 17}
24 18
25} // namespace Common 19} // namespace Common
diff --git a/src/common/page_table.h b/src/common/page_table.h
index cf5eed780..61c5552e0 100644
--- a/src/common/page_table.h
+++ b/src/common/page_table.h
@@ -4,12 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <atomic>
8 8#include <tuple>
9#include <boost/icl/interval_map.hpp>
10 9
11#include "common/common_types.h" 10#include "common/common_types.h"
12#include "common/memory_hook.h"
13#include "common/virtual_buffer.h" 11#include "common/virtual_buffer.h"
14 12
15namespace Common { 13namespace Common {
@@ -22,27 +20,6 @@ enum class PageType : u8 {
22 /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and 20 /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
23 /// invalidation 21 /// invalidation
24 RasterizerCachedMemory, 22 RasterizerCachedMemory,
25 /// Page is mapped to a I/O region. Writing and reading to this page is handled by functions.
26 Special,
27 /// Page is allocated for use.
28 Allocated,
29};
30
31struct SpecialRegion {
32 enum class Type {
33 DebugHook,
34 IODevice,
35 } type;
36
37 MemoryHookPointer handler;
38
39 [[nodiscard]] bool operator<(const SpecialRegion& other) const {
40 return std::tie(type, handler) < std::tie(other.type, other.handler);
41 }
42
43 [[nodiscard]] bool operator==(const SpecialRegion& other) const {
44 return std::tie(type, handler) == std::tie(other.type, other.handler);
45 }
46}; 23};
47 24
48/** 25/**
@@ -50,27 +27,84 @@ struct SpecialRegion {
50 * mimics the way a real CPU page table works. 27 * mimics the way a real CPU page table works.
51 */ 28 */
52struct PageTable { 29struct PageTable {
30 /// Number of bits reserved for attribute tagging.
31 /// This can be at most the guaranteed alignment of the pointers in the page table.
32 static constexpr int ATTRIBUTE_BITS = 2;
33
34 /**
35 * Pair of host pointer and page type attribute.
36 * This uses the lower bits of a given pointer to store the attribute tag.
37 * Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method
38 * call. In other words, they are guaranteed to be synchronized at all times.
39 */
40 class PageInfo {
41 public:
42 /// Returns the page pointer
43 [[nodiscard]] u8* Pointer() const noexcept {
44 return ExtractPointer(raw.load(std::memory_order_relaxed));
45 }
46
47 /// Returns the page type attribute
48 [[nodiscard]] PageType Type() const noexcept {
49 return ExtractType(raw.load(std::memory_order_relaxed));
50 }
51
52 /// Returns the page pointer and attribute pair, extracted from the same atomic read
53 [[nodiscard]] std::pair<u8*, PageType> PointerType() const noexcept {
54 const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed);
55 return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)};
56 }
57
58 /// Returns the raw representation of the page information.
59 /// Use ExtractPointer and ExtractType to unpack the value.
60 [[nodiscard]] uintptr_t Raw() const noexcept {
61 return raw.load(std::memory_order_relaxed);
62 }
63
64 /// Write a page pointer and type pair atomically
65 void Store(u8* pointer, PageType type) noexcept {
66 raw.store(reinterpret_cast<uintptr_t>(pointer) | static_cast<uintptr_t>(type));
67 }
68
69 /// Unpack a pointer from a page info raw representation
70 [[nodiscard]] static u8* ExtractPointer(uintptr_t raw) noexcept {
71 return reinterpret_cast<u8*>(raw & (~uintptr_t{0} << ATTRIBUTE_BITS));
72 }
73
74 /// Unpack a page type from a page info raw representation
75 [[nodiscard]] static PageType ExtractType(uintptr_t raw) noexcept {
76 return static_cast<PageType>(raw & ((uintptr_t{1} << ATTRIBUTE_BITS) - 1));
77 }
78
79 private:
80 std::atomic<uintptr_t> raw;
81 };
82
53 PageTable(); 83 PageTable();
54 ~PageTable(); 84 ~PageTable() noexcept;
85
86 PageTable(const PageTable&) = delete;
87 PageTable& operator=(const PageTable&) = delete;
88
89 PageTable(PageTable&&) noexcept = default;
90 PageTable& operator=(PageTable&&) noexcept = default;
55 91
56 /** 92 /**
57 * Resizes the page table to be able to accomodate enough pages within 93 * Resizes the page table to be able to accommodate enough pages within
58 * a given address space. 94 * a given address space.
59 * 95 *
60 * @param address_space_width_in_bits The address size width in bits. 96 * @param address_space_width_in_bits The address size width in bits.
97 * @param page_size_in_bits The page size in bits.
61 */ 98 */
62 void Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits, 99 void Resize(size_t address_space_width_in_bits, size_t page_size_in_bits);
63 bool has_attribute);
64 100
65 /** 101 /**
66 * Vector of memory pointers backing each page. An entry can only be non-null if the 102 * Vector of memory pointers backing each page. An entry can only be non-null if the
67 * corresponding entry in the `attributes` vector is of type `Memory`. 103 * corresponding attribute element is of type `Memory`.
68 */ 104 */
69 VirtualBuffer<u8*> pointers; 105 VirtualBuffer<PageInfo> pointers;
70 106
71 VirtualBuffer<u64> backing_addr; 107 VirtualBuffer<u64> backing_addr;
72
73 VirtualBuffer<PageType> attributes;
74}; 108};
75 109
76} // namespace Common 110} // namespace Common
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
index 68ef5f197..fa46cb394 100644
--- a/src/common/scope_exit.h
+++ b/src/common/scope_exit.h
@@ -10,7 +10,7 @@
10namespace detail { 10namespace detail {
11template <typename Func> 11template <typename Func>
12struct ScopeExitHelper { 12struct ScopeExitHelper {
13 explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {} 13 explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
14 ~ScopeExitHelper() { 14 ~ScopeExitHelper() {
15 if (active) { 15 if (active) {
16 func(); 16 func();
diff --git a/src/common/spin_lock.h b/src/common/spin_lock.h
index 4f946a258..06ac2f5bb 100644
--- a/src/common/spin_lock.h
+++ b/src/common/spin_lock.h
@@ -15,6 +15,14 @@ namespace Common {
15 */ 15 */
16class SpinLock { 16class SpinLock {
17public: 17public:
18 SpinLock() = default;
19
20 SpinLock(const SpinLock&) = delete;
21 SpinLock& operator=(const SpinLock&) = delete;
22
23 SpinLock(SpinLock&&) = delete;
24 SpinLock& operator=(SpinLock&&) = delete;
25
18 void lock(); 26 void lock();
19 void unlock(); 27 void unlock();
20 [[nodiscard]] bool try_lock(); 28 [[nodiscard]] bool try_lock();
diff --git a/src/common/stream.cpp b/src/common/stream.cpp
new file mode 100644
index 000000000..bf0496c26
--- /dev/null
+++ b/src/common/stream.cpp
@@ -0,0 +1,47 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <stdexcept>
6#include "common/common_types.h"
7#include "common/stream.h"
8
9namespace Common {
10
11Stream::Stream() = default;
12Stream::~Stream() = default;
13
14void Stream::Seek(s32 offset, SeekOrigin origin) {
15 if (origin == SeekOrigin::SetOrigin) {
16 if (offset < 0) {
17 position = 0;
18 } else if (position >= buffer.size()) {
19 position = buffer.size();
20 } else {
21 position = offset;
22 }
23 } else if (origin == SeekOrigin::FromCurrentPos) {
24 Seek(static_cast<s32>(position) + offset, SeekOrigin::SetOrigin);
25 } else if (origin == SeekOrigin::FromEnd) {
26 Seek(static_cast<s32>(buffer.size()) - offset, SeekOrigin::SetOrigin);
27 }
28}
29
30u8 Stream::ReadByte() {
31 if (position < buffer.size()) {
32 return buffer[position++];
33 } else {
34 throw std::out_of_range("Attempting to read a byte not within the buffer range");
35 }
36}
37
38void Stream::WriteByte(u8 byte) {
39 if (position == buffer.size()) {
40 buffer.push_back(byte);
41 position++;
42 } else {
43 buffer.insert(buffer.begin() + position, byte);
44 }
45}
46
47} // namespace Common
diff --git a/src/common/stream.h b/src/common/stream.h
new file mode 100644
index 000000000..0e40692de
--- /dev/null
+++ b/src/common/stream.h
@@ -0,0 +1,56 @@
1// Copyright 2020 yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <vector>
8#include "common/common_types.h"
9
10namespace Common {
11
12enum class SeekOrigin {
13 SetOrigin,
14 FromCurrentPos,
15 FromEnd,
16};
17
18class Stream {
19public:
20 /// Stream creates a bitstream and provides common functionality on the stream.
21 explicit Stream();
22 ~Stream();
23
24 Stream(const Stream&) = delete;
25 Stream& operator=(const Stream&) = delete;
26
27 Stream(Stream&&) = default;
28 Stream& operator=(Stream&&) = default;
29
30 /// Reposition bitstream "cursor" to the specified offset from origin
31 void Seek(s32 offset, SeekOrigin origin);
32
33 /// Reads next byte in the stream buffer and increments position
34 u8 ReadByte();
35
36 /// Writes byte at current position
37 void WriteByte(u8 byte);
38
39 [[nodiscard]] std::size_t GetPosition() const {
40 return position;
41 }
42
43 [[nodiscard]] std::vector<u8>& GetBuffer() {
44 return buffer;
45 }
46
47 [[nodiscard]] const std::vector<u8>& GetBuffer() const {
48 return buffer;
49 }
50
51private:
52 std::vector<u8> buffer;
53 std::size_t position{0};
54};
55
56} // namespace Common
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 84883a1d3..4cba2aaa4 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -8,6 +8,7 @@
8#include <cstdlib> 8#include <cstdlib>
9#include <locale> 9#include <locale>
10#include <sstream> 10#include <sstream>
11
11#include "common/common_paths.h" 12#include "common/common_paths.h"
12#include "common/logging/log.h" 13#include "common/logging/log.h"
13#include "common/string_util.h" 14#include "common/string_util.h"
@@ -21,14 +22,14 @@ namespace Common {
21/// Make a string lowercase 22/// Make a string lowercase
22std::string ToLower(std::string str) { 23std::string ToLower(std::string str) {
23 std::transform(str.begin(), str.end(), str.begin(), 24 std::transform(str.begin(), str.end(), str.begin(),
24 [](unsigned char c) { return std::tolower(c); }); 25 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
25 return str; 26 return str;
26} 27}
27 28
28/// Make a string uppercase 29/// Make a string uppercase
29std::string ToUpper(std::string str) { 30std::string ToUpper(std::string str) {
30 std::transform(str.begin(), str.end(), str.begin(), 31 std::transform(str.begin(), str.end(), str.begin(),
31 [](unsigned char c) { return std::toupper(c); }); 32 [](unsigned char c) { return static_cast<char>(std::toupper(c)); });
32 return str; 33 return str;
33} 34}
34 35
diff --git a/src/common/swap.h b/src/common/swap.h
index 7665942a2..a80e191dc 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -394,7 +394,7 @@ public:
394 template <typename S, typename T2, typename F2> 394 template <typename S, typename T2, typename F2>
395 friend S operator%(const S& p, const swapped_t v); 395 friend S operator%(const S& p, const swapped_t v);
396 396
397 // Arithmetics + assignements 397 // Arithmetics + assignments
398 template <typename S, typename T2, typename F2> 398 template <typename S, typename T2, typename F2>
399 friend S operator+=(const S& p, const swapped_t v); 399 friend S operator+=(const S& p, const swapped_t v);
400 400
@@ -451,7 +451,7 @@ S operator%(const S& i, const swap_struct_t<T, F> v) {
451 return i % v.swap(); 451 return i % v.swap();
452} 452}
453 453
454// Arithmetics + assignements 454// Arithmetics + assignments
455template <typename S, typename T, typename F> 455template <typename S, typename T, typename F>
456S& operator+=(S& i, const swap_struct_t<T, F> v) { 456S& operator+=(S& i, const swap_struct_t<T, F> v) {
457 i += v.swap(); 457 i += v.swap();
diff --git a/src/common/telemetry.h b/src/common/telemetry.h
index a50c5d1de..49186e848 100644
--- a/src/common/telemetry.h
+++ b/src/common/telemetry.h
@@ -52,8 +52,8 @@ public:
52template <typename T> 52template <typename T>
53class Field : public FieldInterface { 53class Field : public FieldInterface {
54public: 54public:
55 Field(FieldType type, std::string name, T value) 55 Field(FieldType type_, std::string name_, T value_)
56 : name(std::move(name)), type(type), value(std::move(value)) {} 56 : name(std::move(name_)), type(type_), value(std::move(value_)) {}
57 57
58 Field(const Field&) = default; 58 Field(const Field&) = default;
59 Field& operator=(const Field&) = default; 59 Field& operator=(const Field&) = default;
diff --git a/src/common/thread_worker.cpp b/src/common/thread_worker.cpp
new file mode 100644
index 000000000..8f9bf447a
--- /dev/null
+++ b/src/common/thread_worker.cpp
@@ -0,0 +1,58 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/thread.h"
6#include "common/thread_worker.h"
7
8namespace Common {
9
10ThreadWorker::ThreadWorker(std::size_t num_workers, const std::string& name) {
11 for (std::size_t i = 0; i < num_workers; ++i)
12 threads.emplace_back([this, thread_name{std::string{name}}] {
13 Common::SetCurrentThreadName(thread_name.c_str());
14
15 // Wait for first request
16 {
17 std::unique_lock lock{queue_mutex};
18 condition.wait(lock, [this] { return stop || !requests.empty(); });
19 }
20
21 while (true) {
22 std::function<void()> task;
23
24 {
25 std::unique_lock lock{queue_mutex};
26 condition.wait(lock, [this] { return stop || !requests.empty(); });
27 if (stop || requests.empty()) {
28 return;
29 }
30 task = std::move(requests.front());
31 requests.pop();
32 }
33
34 task();
35 }
36 });
37}
38
39ThreadWorker::~ThreadWorker() {
40 {
41 std::unique_lock lock{queue_mutex};
42 stop = true;
43 }
44 condition.notify_all();
45 for (std::thread& thread : threads) {
46 thread.join();
47 }
48}
49
50void ThreadWorker::QueueWork(std::function<void()>&& work) {
51 {
52 std::unique_lock lock{queue_mutex};
53 requests.emplace(work);
54 }
55 condition.notify_one();
56}
57
58} // namespace Common
diff --git a/src/common/thread_worker.h b/src/common/thread_worker.h
new file mode 100644
index 000000000..f1859971f
--- /dev/null
+++ b/src/common/thread_worker.h
@@ -0,0 +1,30 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <atomic>
8#include <functional>
9#include <mutex>
10#include <string>
11#include <vector>
12#include <queue>
13
14namespace Common {
15
16class ThreadWorker final {
17public:
18 explicit ThreadWorker(std::size_t num_workers, const std::string& name);
19 ~ThreadWorker();
20 void QueueWork(std::function<void()>&& work);
21
22private:
23 std::vector<std::thread> threads;
24 std::queue<std::function<void()>> requests;
25 std::mutex queue_mutex;
26 std::condition_variable condition;
27 std::atomic_bool stop{};
28};
29
30} // namespace Common
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index 2dc15e434..d17dc2a50 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -142,20 +142,18 @@ std::string Timer::GetTimeFormatted() {
142// ---------------- 142// ----------------
143double Timer::GetDoubleTime() { 143double Timer::GetDoubleTime() {
144 // Get continuous timestamp 144 // Get continuous timestamp
145 u64 TmpSeconds = static_cast<u64>(Common::Timer::GetTimeSinceJan1970().count()); 145 auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count());
146 double ms = static_cast<u64>(GetTimeMs().count()) % 1000; 146 const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000);
147 147
148 // Remove a few years. We only really want enough seconds to make 148 // Remove a few years. We only really want enough seconds to make
149 // sure that we are detecting actual actions, perhaps 60 seconds is 149 // sure that we are detecting actual actions, perhaps 60 seconds is
150 // enough really, but I leave a year of seconds anyway, in case the 150 // enough really, but I leave a year of seconds anyway, in case the
151 // user's clock is incorrect or something like that. 151 // user's clock is incorrect or something like that.
152 TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); 152 tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60);
153 153
154 // Make a smaller integer that fits in the double 154 // Make a smaller integer that fits in the double
155 u32 Seconds = static_cast<u32>(TmpSeconds); 155 const auto seconds = static_cast<u32>(tmp_seconds);
156 double TmpTime = Seconds + ms; 156 return seconds + ms;
157
158 return TmpTime;
159} 157}
160 158
161} // Namespace Common 159} // Namespace Common
diff --git a/src/common/vector_math.h b/src/common/vector_math.h
index 2a0fcf541..22dba3c2d 100644
--- a/src/common/vector_math.h
+++ b/src/common/vector_math.h
@@ -87,7 +87,13 @@ public:
87 87
88 template <typename V> 88 template <typename V>
89 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { 89 [[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
90 return {x * f, y * f}; 90 using TV = decltype(T{} * V{});
91 using C = std::common_type_t<T, V>;
92
93 return {
94 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
95 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
96 };
91 } 97 }
92 98
93 template <typename V> 99 template <typename V>
@@ -98,7 +104,13 @@ public:
98 104
99 template <typename V> 105 template <typename V>
100 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { 106 [[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
101 return {x / f, y / f}; 107 using TV = decltype(T{} / V{});
108 using C = std::common_type_t<T, V>;
109
110 return {
111 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
112 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
113 };
102 } 114 }
103 115
104 template <typename V> 116 template <typename V>
@@ -168,7 +180,10 @@ public:
168 180
169template <typename T, typename V> 181template <typename T, typename V>
170[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { 182[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
171 return Vec2<T>(f * vec.x, f * vec.y); 183 using C = std::common_type_t<T, V>;
184
185 return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
186 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
172} 187}
173 188
174using Vec2f = Vec2<float>; 189using Vec2f = Vec2<float>;
@@ -237,7 +252,14 @@ public:
237 252
238 template <typename V> 253 template <typename V>
239 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { 254 [[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
240 return {x * f, y * f, z * f}; 255 using TV = decltype(T{} * V{});
256 using C = std::common_type_t<T, V>;
257
258 return {
259 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
260 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
261 static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
262 };
241 } 263 }
242 264
243 template <typename V> 265 template <typename V>
@@ -247,7 +269,14 @@ public:
247 } 269 }
248 template <typename V> 270 template <typename V>
249 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { 271 [[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
250 return {x / f, y / f, z / f}; 272 using TV = decltype(T{} / V{});
273 using C = std::common_type_t<T, V>;
274
275 return {
276 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
277 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
278 static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
279 };
251 } 280 }
252 281
253 template <typename V> 282 template <typename V>
@@ -367,7 +396,11 @@ public:
367 396
368template <typename T, typename V> 397template <typename T, typename V>
369[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { 398[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
370 return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); 399 using C = std::common_type_t<T, V>;
400
401 return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
402 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
403 static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
371} 404}
372 405
373template <> 406template <>
@@ -446,7 +479,15 @@ public:
446 479
447 template <typename V> 480 template <typename V>
448 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { 481 [[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
449 return {x * f, y * f, z * f, w * f}; 482 using TV = decltype(T{} * V{});
483 using C = std::common_type_t<T, V>;
484
485 return {
486 static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
487 static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
488 static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
489 static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
490 };
450 } 491 }
451 492
452 template <typename V> 493 template <typename V>
@@ -457,7 +498,15 @@ public:
457 498
458 template <typename V> 499 template <typename V>
459 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { 500 [[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
460 return {x / f, y / f, z / f, w / f}; 501 using TV = decltype(T{} / V{});
502 using C = std::common_type_t<T, V>;
503
504 return {
505 static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
506 static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
507 static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
508 static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
509 };
461 } 510 }
462 511
463 template <typename V> 512 template <typename V>
@@ -582,7 +631,15 @@ public:
582 631
583template <typename T, typename V> 632template <typename T, typename V>
584[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { 633[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
585 return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; 634 using TV = decltype(V{} * T{});
635 using C = std::common_type_t<T, V>;
636
637 return {
638 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
639 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
640 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
641 static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
642 };
586} 643}
587 644
588using Vec4f = Vec4<float>; 645using Vec4f = Vec4<float>;
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp
index b009cb500..e3ca29258 100644
--- a/src/common/virtual_buffer.cpp
+++ b/src/common/virtual_buffer.cpp
@@ -13,7 +13,7 @@
13 13
14namespace Common { 14namespace Common {
15 15
16void* AllocateMemoryPages(std::size_t size) { 16void* AllocateMemoryPages(std::size_t size) noexcept {
17#ifdef _WIN32 17#ifdef _WIN32
18 void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)}; 18 void* base{VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE)};
19#else 19#else
@@ -29,7 +29,7 @@ void* AllocateMemoryPages(std::size_t size) {
29 return base; 29 return base;
30} 30}
31 31
32void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) { 32void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
33 if (!base) { 33 if (!base) {
34 return; 34 return;
35 } 35 }
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h
index 125cb42f0..fb1a6f81f 100644
--- a/src/common/virtual_buffer.h
+++ b/src/common/virtual_buffer.h
@@ -4,29 +4,55 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h" 7#include <type_traits>
8#include <utility>
8 9
9namespace Common { 10namespace Common {
10 11
11void* AllocateMemoryPages(std::size_t size); 12void* AllocateMemoryPages(std::size_t size) noexcept;
12void FreeMemoryPages(void* base, std::size_t size); 13void FreeMemoryPages(void* base, std::size_t size) noexcept;
13 14
14template <typename T> 15template <typename T>
15class VirtualBuffer final : NonCopyable { 16class VirtualBuffer final {
16public: 17public:
18 // TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible
19 // using std::atomic_ref once libc++ has support for it
20 // static_assert(
21 // std::is_trivially_constructible_v<T>,
22 // "T must be trivially constructible, as non-trivial constructors will not be executed "
23 // "with the current allocator");
24
17 constexpr VirtualBuffer() = default; 25 constexpr VirtualBuffer() = default;
18 explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} { 26 explicit VirtualBuffer(std::size_t count) : alloc_size{count * sizeof(T)} {
19 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); 27 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
20 } 28 }
21 29
22 ~VirtualBuffer() { 30 ~VirtualBuffer() noexcept {
23 FreeMemoryPages(base_ptr, alloc_size); 31 FreeMemoryPages(base_ptr, alloc_size);
24 } 32 }
25 33
34 VirtualBuffer(const VirtualBuffer&) = delete;
35 VirtualBuffer& operator=(const VirtualBuffer&) = delete;
36
37 VirtualBuffer(VirtualBuffer&& other) noexcept
38 : alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr),
39 nullptr} {}
40
41 VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
42 alloc_size = std::exchange(other.alloc_size, 0);
43 base_ptr = std::exchange(other.base_ptr, nullptr);
44 return *this;
45 }
46
26 void resize(std::size_t count) { 47 void resize(std::size_t count) {
48 const auto new_size = count * sizeof(T);
49 if (new_size == alloc_size) {
50 return;
51 }
52
27 FreeMemoryPages(base_ptr, alloc_size); 53 FreeMemoryPages(base_ptr, alloc_size);
28 54
29 alloc_size = count * sizeof(T); 55 alloc_size = new_size;
30 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); 56 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
31 } 57 }
32 58
diff --git a/src/common/wall_clock.cpp b/src/common/wall_clock.cpp
index 3afbdb898..a8c143f85 100644
--- a/src/common/wall_clock.cpp
+++ b/src/common/wall_clock.cpp
@@ -15,10 +15,10 @@ namespace Common {
15using base_timer = std::chrono::steady_clock; 15using base_timer = std::chrono::steady_clock;
16using base_time_point = std::chrono::time_point<base_timer>; 16using base_time_point = std::chrono::time_point<base_timer>;
17 17
18class StandardWallClock : public WallClock { 18class StandardWallClock final : public WallClock {
19public: 19public:
20 StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency) 20 explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_)
21 : WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) { 21 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {
22 start_time = base_timer::now(); 22 start_time = base_timer::now();
23 } 23 }
24 24
@@ -53,7 +53,7 @@ public:
53 return Common::Divide128On32(temporary, 1000000000).first; 53 return Common::Divide128On32(temporary, 1000000000).first;
54 } 54 }
55 55
56 void Pause(bool is_paused) override { 56 void Pause([[maybe_unused]] bool is_paused) override {
57 // Do nothing in this clock type. 57 // Do nothing in this clock type.
58 } 58 }
59 59
diff --git a/src/common/wall_clock.h b/src/common/wall_clock.h
index 5db30083d..cef3e9499 100644
--- a/src/common/wall_clock.h
+++ b/src/common/wall_clock.h
@@ -13,6 +13,8 @@ namespace Common {
13 13
14class WallClock { 14class WallClock {
15public: 15public:
16 virtual ~WallClock() = default;
17
16 /// Returns current wall time in nanoseconds 18 /// Returns current wall time in nanoseconds
17 [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0; 19 [[nodiscard]] virtual std::chrono::nanoseconds GetTimeNS() = 0;
18 20
@@ -36,9 +38,9 @@ public:
36 } 38 }
37 39
38protected: 40protected:
39 WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native) 41 explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_)
40 : emulated_cpu_frequency{emulated_cpu_frequency}, 42 : emulated_cpu_frequency{emulated_cpu_frequency_},
41 emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {} 43 emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {}
42 44
43 u64 emulated_cpu_frequency; 45 u64 emulated_cpu_frequency;
44 u64 emulated_clock_frequency; 46 u64 emulated_clock_frequency;
diff --git a/src/common/x64/native_clock.cpp b/src/common/x64/native_clock.cpp
index 424b39b1f..eb8a7782f 100644
--- a/src/common/x64/native_clock.cpp
+++ b/src/common/x64/native_clock.cpp
@@ -43,10 +43,10 @@ u64 EstimateRDTSCFrequency() {
43} 43}
44 44
45namespace X64 { 45namespace X64 {
46NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, 46NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
47 u64 rtsc_frequency) 47 u64 rtsc_frequency_)
48 : WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{ 48 : WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
49 rtsc_frequency} { 49 rtsc_frequency_} {
50 _mm_mfence(); 50 _mm_mfence();
51 last_measure = __rdtsc(); 51 last_measure = __rdtsc();
52 accumulated_ticks = 0U; 52 accumulated_ticks = 0U;
diff --git a/src/common/x64/native_clock.h b/src/common/x64/native_clock.h
index 891a3bbfd..6d1e32ac8 100644
--- a/src/common/x64/native_clock.h
+++ b/src/common/x64/native_clock.h
@@ -12,9 +12,10 @@
12namespace Common { 12namespace Common {
13 13
14namespace X64 { 14namespace X64 {
15class NativeClock : public WallClock { 15class NativeClock final : public WallClock {
16public: 16public:
17 NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency); 17 explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
18 u64 rtsc_frequency_);
18 19
19 std::chrono::nanoseconds GetTimeNS() override; 20 std::chrono::nanoseconds GetTimeNS() override;
20 21
@@ -34,7 +35,7 @@ private:
34 /// value used to reduce the native clocks accuracy as some apss rely on 35 /// value used to reduce the native clocks accuracy as some apss rely on
35 /// undefined behavior where the level of accuracy in the clock shouldn't 36 /// undefined behavior where the level of accuracy in the clock shouldn't
36 /// be higher. 37 /// be higher.
37 static constexpr u64 inaccuracy_mask = ~(0x400 - 1); 38 static constexpr u64 inaccuracy_mask = ~(UINT64_C(0x400) - 1);
38 39
39 SpinLock rtsc_serialize{}; 40 SpinLock rtsc_serialize{};
40 u64 last_measure{}; 41 u64 last_measure{};
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
index 26e4bfda5..c2c9b6134 100644
--- a/src/common/x64/xbyak_abi.h
+++ b/src/common/x64/xbyak_abi.h
@@ -11,25 +11,25 @@
11 11
12namespace Common::X64 { 12namespace Common::X64 {
13 13
14constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) { 14constexpr size_t RegToIndex(const Xbyak::Reg& reg) {
15 using Kind = Xbyak::Reg::Kind; 15 using Kind = Xbyak::Reg::Kind;
16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0, 16 ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
17 "RegSet only support GPRs and XMM registers."); 17 "RegSet only support GPRs and XMM registers.");
18 ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15."); 18 ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
19 return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16); 19 return static_cast<size_t>(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16);
20} 20}
21 21
22constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) { 22constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) {
23 ASSERT(reg_index < 16); 23 ASSERT(reg_index < 16);
24 return Xbyak::Reg64(static_cast<int>(reg_index)); 24 return Xbyak::Reg64(static_cast<int>(reg_index));
25} 25}
26 26
27constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) { 27constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) {
28 ASSERT(reg_index >= 16 && reg_index < 32); 28 ASSERT(reg_index >= 16 && reg_index < 32);
29 return Xbyak::Xmm(static_cast<int>(reg_index - 16)); 29 return Xbyak::Xmm(static_cast<int>(reg_index - 16));
30} 30}
31 31
32constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) { 32constexpr Xbyak::Reg IndexToReg(size_t reg_index) {
33 if (reg_index < 16) { 33 if (reg_index < 16) {
34 return IndexToReg64(reg_index); 34 return IndexToReg64(reg_index);
35 } else { 35 } else {
@@ -182,7 +182,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b
182 size_t rsp_alignment, size_t needed_frame_size = 0) { 182 size_t rsp_alignment, size_t needed_frame_size = 0) {
183 auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); 183 auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size);
184 184
185 for (std::size_t i = 0; i < regs.size(); ++i) { 185 for (size_t i = 0; i < regs.size(); ++i) {
186 if (regs[i] && ABI_ALL_GPRS[i]) { 186 if (regs[i] && ABI_ALL_GPRS[i]) {
187 code.push(IndexToReg64(i)); 187 code.push(IndexToReg64(i));
188 } 188 }
@@ -192,7 +192,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b
192 code.sub(code.rsp, frame_info.subtraction); 192 code.sub(code.rsp, frame_info.subtraction);
193 } 193 }
194 194
195 for (std::size_t i = 0; i < regs.size(); ++i) { 195 for (size_t i = 0; i < regs.size(); ++i) {
196 if (regs[i] && ABI_ALL_XMMS[i]) { 196 if (regs[i] && ABI_ALL_XMMS[i]) {
197 code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i)); 197 code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i));
198 frame_info.xmm_offset += 0x10; 198 frame_info.xmm_offset += 0x10;
@@ -206,7 +206,7 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits
206 size_t rsp_alignment, size_t needed_frame_size = 0) { 206 size_t rsp_alignment, size_t needed_frame_size = 0) {
207 auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size); 207 auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size);
208 208
209 for (std::size_t i = 0; i < regs.size(); ++i) { 209 for (size_t i = 0; i < regs.size(); ++i) {
210 if (regs[i] && ABI_ALL_XMMS[i]) { 210 if (regs[i] && ABI_ALL_XMMS[i]) {
211 code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]); 211 code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]);
212 frame_info.xmm_offset += 0x10; 212 frame_info.xmm_offset += 0x10;
@@ -218,8 +218,8 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits
218 } 218 }
219 219
220 // GPRs need to be popped in reverse order 220 // GPRs need to be popped in reverse order
221 for (std::size_t j = 0; j < regs.size(); ++j) { 221 for (size_t j = 0; j < regs.size(); ++j) {
222 const std::size_t i = regs.size() - j - 1; 222 const size_t i = regs.size() - j - 1;
223 if (regs[i] && ABI_ALL_GPRS[i]) { 223 if (regs[i] && ABI_ALL_GPRS[i]) {
224 code.pop(IndexToReg64(i)); 224 code.pop(IndexToReg64(i));
225 } 225 }