3#if defined(SKSE_SUPPORT_XBYAK) 
   14        [[nodiscard]] 
constexpr std::size_t 
roundup(std::size_t a_number, std::size_t a_multiple) 
noexcept 
   16            if (a_multiple == 0) {
 
   20            const auto remainder = a_number % a_multiple;
 
   21            return remainder == 0 ?
 
   23                       a_number + a_multiple - remainder;
 
   26        [[nodiscard]] 
constexpr std::size_t 
rounddown(std::size_t a_number, std::size_t a_multiple) 
noexcept 
   28            if (a_multiple == 0) {
 
   32            const auto remainder = a_number % a_multiple;
 
   33            return remainder == 0 ?
 
   42        using deleter_type = std::function<void(
void* a_mem, std::size_t a_size)>;
 
   59            if (
this != std::addressof(a_rhs)) {
 
   60                move_from(std::move(a_rhs));
 
   65        void create(std::size_t a_size) { 
return create(a_size, 
nullptr); }
 
   67        void create(std::size_t a_size, 
void* a_module)
 
   75                a_module = text.
pointer<std::byte>() + text.size();
 
   78            auto mem = do_create(a_size, 
reinterpret_cast<std::uintptr_t
>(a_module));
 
   84                [](
void* a_mem, std::size_t) {
 
   93            auto trampoline = 
static_cast<std::byte*
>(a_trampoline);
 
   95                constexpr auto INT3 = 
static_cast<int>(0xCC);
 
   96                std::memset(trampoline, INT3, a_size);
 
  101            _deleter = std::move(a_deleter);
 
  111            auto result = do_allocate(a_size);
 
  116#ifdef SKSE_SUPPORT_XBYAK 
  117        [[nodiscard]] 
void* 
allocate(Xbyak::CodeGenerator& a_code);
 
  123            return static_cast<T*
>(
allocate(
sizeof(T)));
 
  126        [[nodiscard]] 
constexpr std::size_t 
empty() const noexcept { 
return _capacity == 0; }
 
  127        [[nodiscard]] 
constexpr std::size_t 
capacity() const noexcept { 
return _capacity; }
 
  128        [[nodiscard]] 
constexpr std::size_t 
allocated_size() const noexcept { 
return _size; }
 
  129        [[nodiscard]] 
constexpr std::size_t 
free_size() const noexcept { 
return _capacity - _size; }
 
  131        template <std::
size_t N>
 
  132        std::uintptr_t 
write_branch(std::uintptr_t a_src, std::uintptr_t a_dst)
 
  134            std::uint8_t data = 0;
 
  135            if constexpr (N == 5) {
 
  139            } 
else if constexpr (N == 6) {
 
  144                static_assert(
false && N, 
"invalid branch size");
 
  147            return write_branch<N>(a_src, a_dst, data);
 
  150        template <std::
size_t N, 
class F>
 
  153            return write_branch<N>(a_src, stl::unrestricted_cast<std::uintptr_t>(a_dst));
 
  156        template <std::
size_t N>
 
  157        std::uintptr_t 
write_call(std::uintptr_t a_src, std::uintptr_t a_dst)
 
  159            std::uint8_t data = 0;
 
  160            if constexpr (N == 5) {
 
  164            } 
else if constexpr (N == 6) {
 
  169                static_assert(
false && N, 
"invalid call size");
 
  172            return write_branch<N>(a_src, a_dst, data);
 
  175        template <std::
size_t N, 
class F>
 
  178            return write_call<N>(a_src, stl::unrestricted_cast<std::uintptr_t>(a_dst));
 
  182        [[nodiscard]] 
void* do_create(std::size_t a_size, std::uintptr_t a_address);
 
  184        [[nodiscard]] 
void* do_allocate(std::size_t a_size)
 
  190            auto mem = _data + _size;
 
  196        void write_5branch(std::uintptr_t a_src, std::uintptr_t a_dst, std::uint8_t a_opcode)
 
  205            static_assert(offsetof(SrcAssembly, opcode) == 0x0);
 
  206            static_assert(offsetof(SrcAssembly, disp) == 0x1);
 
  207            static_assert(
sizeof(SrcAssembly) == 0x5);
 
  211            struct TrampolineAssembly
 
  219            static_assert(offsetof(TrampolineAssembly, jmp) == 0x0);
 
  220            static_assert(offsetof(TrampolineAssembly, modrm) == 0x1);
 
  221            static_assert(offsetof(TrampolineAssembly, disp) == 0x2);
 
  222            static_assert(offsetof(TrampolineAssembly, addr) == 0x6);
 
  223            static_assert(
sizeof(TrampolineAssembly) == 0xE);
 
  226            TrampolineAssembly* mem = 
nullptr;
 
  227            if (
const auto it = _5branches.find(a_dst); it != _5branches.end()) {
 
  228                mem = 
reinterpret_cast<TrampolineAssembly*
>(it->second);
 
  230                mem = allocate<TrampolineAssembly>();
 
  231                _5branches.emplace(a_dst, 
reinterpret_cast<std::byte*
>(mem));
 
  235                reinterpret_cast<const std::byte*
>(mem) -
 
  236                reinterpret_cast<const std::byte*
>(a_src + 
sizeof(SrcAssembly));
 
  237            if (!in_range(disp)) {  
 
  241            SrcAssembly assembly;
 
  242            assembly.opcode = a_opcode;
 
  243            assembly.disp = 
static_cast<std::int32_t
>(disp);
 
  246            mem->jmp = 
static_cast<std::uint8_t
>(0xFF);
 
  247            mem->modrm = 
static_cast<std::uint8_t
>(0x25);
 
  248            mem->disp = 
static_cast<std::int32_t
>(0);
 
  249            mem->addr = 
static_cast<std::uint64_t
>(a_dst);
 
  252        void write_6branch(std::uintptr_t a_src, std::uintptr_t a_dst, std::uint8_t a_modrm)
 
  262            static_assert(offsetof(Assembly, opcode) == 0x0);
 
  263            static_assert(offsetof(Assembly, modrm) == 0x1);
 
  264            static_assert(offsetof(Assembly, disp) == 0x2);
 
  265            static_assert(
sizeof(Assembly) == 0x6);
 
  268            std::uintptr_t* mem = 
nullptr;
 
  269            if (
const auto it = _6branches.find(a_dst); it != _6branches.end()) {
 
  270                mem = 
reinterpret_cast<std::uintptr_t*
>(it->second);
 
  272                mem = allocate<std::uintptr_t>();
 
  273                _6branches.emplace(a_dst, 
reinterpret_cast<std::byte*
>(mem));
 
  277                reinterpret_cast<const std::byte*
>(mem) -
 
  278                reinterpret_cast<const std::byte*
>(a_src + 
sizeof(Assembly));
 
  279            if (!in_range(disp)) {  
 
  284            assembly.opcode = 
static_cast<std::uint8_t
>(0xFF);
 
  285            assembly.modrm = a_modrm;
 
  286            assembly.disp = 
static_cast<std::int32_t
>(disp);
 
  292        template <std::
size_t N>
 
  293        [[nodiscard]] std::uintptr_t 
write_branch(std::uintptr_t a_src, std::uintptr_t a_dst, std::uint8_t a_data)
 
  295            const auto disp = 
reinterpret_cast<std::int32_t*
>(a_src + N - 4);
 
  296            const auto nextOp = a_src + N;
 
  297            const auto func = nextOp + *disp;
 
  299            if constexpr (N == 5) {
 
  300                write_5branch(a_src, a_dst, a_data);
 
  301            } 
else if constexpr (N == 6) {
 
  302                write_6branch(a_src, a_dst, a_data);
 
  304                static_assert(
false && N, 
"invalid branch size");
 
  312            _5branches = std::move(a_rhs._5branches);
 
  313            _6branches = std::move(a_rhs._6branches);
 
  314            _name = std::move(a_rhs._name);
 
  316            _deleter = std::move(a_rhs._deleter);
 
  319            a_rhs._data = 
nullptr;
 
  321            _capacity = a_rhs._capacity;
 
  328        void log_stats() 
const;
 
  330        [[nodiscard]] 
bool in_range(std::ptrdiff_t a_disp)
 const 
  332            constexpr auto min = std::numeric_limits<std::int32_t>::min();
 
  333            constexpr auto max = std::numeric_limits<std::int32_t>::max();
 
  335            return min <= a_disp && a_disp <= max;
 
  340            if (_data && _deleter) {
 
  341                _deleter(_data, _capacity);
 
  351        std::map<std::uintptr_t, std::byte*> _5branches;
 
  352        std::map<std::uintptr_t, std::byte*> _6branches;
 
  353        std::string                          _name{ 
"Default Trampoline"sv };
 
  355        std::byte*                           _data{ 
nullptr };
 
  356        std::size_t                          _capacity{ 0 };
 
  357        std::size_t                          _size{ 0 };
 
static Module & get()
Definition: Relocation.h:421
 
Segment segment(Segment::Name a_segment) const noexcept
Definition: Relocation.h:431
 
@ textx
Definition: Relocation.h:381
 
void * pointer() const noexcept
Definition: Relocation.h:404
 
Definition: Trampoline.h:40
 
Trampoline & operator=(Trampoline &&a_rhs)
Definition: Trampoline.h:57
 
std::uintptr_t write_call(std::uintptr_t a_src, std::uintptr_t a_dst)
Definition: Trampoline.h:157
 
constexpr std::size_t allocated_size() const noexcept
Definition: Trampoline.h:128
 
T * allocate()
Definition: Trampoline.h:121
 
std::function< void(void *a_mem, std::size_t a_size)> deleter_type
Definition: Trampoline.h:42
 
void * allocate(std::size_t a_size)
Definition: Trampoline.h:109
 
~Trampoline()
Definition: Trampoline.h:53
 
std::uintptr_t write_branch(std::uintptr_t a_src, std::uintptr_t a_dst)
Definition: Trampoline.h:132
 
Trampoline(std::string_view a_name)
Definition: Trampoline.h:49
 
Trampoline & operator=(const Trampoline &)=delete
 
Trampoline(const Trampoline &)=delete
 
std::uintptr_t write_branch(std::uintptr_t a_src, F a_dst)
Definition: Trampoline.h:151
 
void create(std::size_t a_size)
Definition: Trampoline.h:65
 
Trampoline(Trampoline &&a_rhs)
Definition: Trampoline.h:47
 
void set_trampoline(void *a_trampoline, std::size_t a_size)
Definition: Trampoline.h:89
 
constexpr std::size_t capacity() const noexcept
Definition: Trampoline.h:127
 
std::uintptr_t write_call(std::uintptr_t a_src, F a_dst)
Definition: Trampoline.h:176
 
constexpr std::size_t empty() const noexcept
Definition: Trampoline.h:126
 
constexpr std::size_t free_size() const noexcept
Definition: Trampoline.h:129
 
void create(std::size_t a_size, void *a_module)
Definition: Trampoline.h:67
 
void set_trampoline(void *a_trampoline, std::size_t a_size, deleter_type a_deleter)
Definition: Trampoline.h:91
 
void safe_write(std::uintptr_t a_dst, const void *a_src, std::size_t a_count)
Definition: Relocation.h:218
 
constexpr auto MEM_RELEASE
Definition: WinAPI.h:10
 
bool VirtualFree(void *a_address, std::size_t a_size, std::uint32_t a_freeType) noexcept
 
constexpr std::size_t rounddown(std::size_t a_number, std::size_t a_multiple) noexcept
Definition: Trampoline.h:26
 
constexpr std::size_t roundup(std::size_t a_number, std::size_t a_multiple) noexcept
Definition: Trampoline.h:14
 
void report_and_fail(std::string_view a_msg, std::source_location a_loc=std::source_location::current())
Definition: PCH.h:580