Skip to content

Commit

Permalink
refactor: refactoring Closure
Browse files Browse the repository at this point in the history
  • Loading branch information
OEOTYAN committed Nov 9, 2024
1 parent c38f756 commit d844740
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 140 deletions.
22 changes: 22 additions & 0 deletions src/ll/api/memory/Closure.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "ll/api/memory/Closure.h"

#include <cstddef>
#include <cstdint>
#include <cstring>

#include "ll/api/base/StdInt.h"
#include "ll/api/memory/Memory.h"
#include "ll/core/LeviLamina.h"

namespace ll::memory {
extern "C" { // from trampoline
std::size_t generate_trampoline(void* jit_code_address, const void* call_target, int = 0);
void* _asm_get_this_pointer();
}
void* ClosureBase::getClosureData() { return _asm_get_this_pointer(); }

ClosureBase::ClosureBase(void const* impl) {
storage.alloc(sizeof(PackedSelf));
generate_trampoline(new (storage.writable()) PackedSelf{.self = this}, impl);
}
} // namespace ll::memory
92 changes: 33 additions & 59 deletions src/ll/api/memory/Closure.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,45 @@
#include "ll/api/memory/Memory.h"

namespace ll::memory {
namespace detail {
static constexpr size_t closureMagicNumber = 0x58ffffbffdffffafull;
class ClosureBase {
public:
static constexpr size_t jitSize = 48;
struct PackedSelf {
char jitfn[jitSize];
ClosureBase* self;
};
DualMapping storage{};
LLNDAPI static void* getClosureData();
LLNDAPI ClosureBase(void const* impl);

LLAPI size_t getVolatileOffset(void*);
LLAPI void initNativeClosure(void* self, void* impl, size_t offset);
LLAPI void releaseNativeClosure(void* self);
} // namespace detail
ClosureBase(ClosureBase&&) = delete;
ClosureBase(ClosureBase const&) = delete;
ClosureBase& operator=(ClosureBase&&) = delete;
ClosureBase& operator=(ClosureBase const&) = delete;
};

// The principle of NativeClosure
//--------------------------------------------------------------
// | First we need an impl function as the actual |
// | implementation, and put a volatile variable at the |
// | beginning of the function, so that the compiler will |
// | theoretically push the value of this variable at the |
// | beginning. We set it to a value that should not appear |
// | in The number in the assembly, and then find the offset |
// | of this number from the beginning of the function |
// | pointer in the constructor of each closure, then |
// | allocate a small piece of memory, copy the Prologue of |
// | the function itself, but replace the value of that |
// | variable with what we want Incoming data. |
//--------------------------------------------------------------
// |from compiler| <copy to mem> >write by hand<
//--------------------------------------------------------------
// |..... pargs .....| <..... pargs .....>
// |mov rax , [mgic]| <mov rax>, [data]<
// addr |0x58 (magic head)| ---> >push rax <
// |mov qword ptr | >mov rax , [addr]<
// | [rbp-8], rax | >jmp rax <
// | ... ... | addr |0x58 (pop rax)|
// |.... orifunc ....| | ... ... |
//--------------------------------------------------------------
template <class... Args>
class NativeClosure {
static_assert(sizeof...(Args) < 0, "NativeClosure only accepts function types as template arguments.");
};

template <class Ret, class... Args>
class NativeClosure<Ret(Args...)> {
class NativeClosure<Ret(Args...)> : private ClosureBase {
static inline Ret closureImpl(Args... args) {
volatile uintptr_t data = detail::closureMagicNumber;
auto stored = (PackedData*)data;
return stored->func(stored->data, std::forward<Args>(args)...);
auto& self = *static_cast<NativeClosure*>(reinterpret_cast<PackedSelf*>(getClosureData())->self);
return (self.func)(self.data, std::forward<Args>(args)...);
}
static inline size_t implOffset = detail::getVolatileOffset((void*)closureImpl);

public:
using origin_fn = Ret(uintptr_t, Args...);
using closure_fn = Ret(Args...);

struct PackedData {
origin_fn* func;
uintptr_t data;
} stored;

DualMapping closure{};
using origin = Ret(uintptr_t, Args...);
using closure = Ret(Args...);

NativeClosure(origin_fn* func, uintptr_t data) : stored({func, data}) {
detail::initNativeClosure(this, (void*)closureImpl, implOffset);
}
closure_fn* get() const { return reinterpret_cast<closure_fn*>(closure.executable()); }
uintptr_t data;
origin* func;

~NativeClosure() { detail::releaseNativeClosure(this); }
[[nodiscard]] NativeClosure(origin* func, uintptr_t data) : ClosureBase(closureImpl), func(func), data(data) {}

NativeClosure(NativeClosure&&) = delete;
NativeClosure(NativeClosure const&) = delete;
NativeClosure& operator=(NativeClosure&&) = delete;
NativeClosure& operator=(NativeClosure const&) = delete;
[[nodiscard]] closure* get() const { return reinterpret_cast<closure*>(storage.executable()); }
};
template <class Ret, class... Args>
NativeClosure(Ret (*)(uintptr_t, Args...), uintptr_t) -> NativeClosure<Ret(Args...)>;
Expand All @@ -83,18 +55,20 @@ class FunctionalClosure {
static_assert(sizeof...(Args) < 0, "FunctionalClosure only accepts function types as template arguments.");
};
template <class Ret, class... Args>
class FunctionalClosure<Ret(Args...)> : public NativeClosure<Ret(Args...)> {
static inline Ret closureImpl(uintptr_t data, Args... args) {
return ((FunctionalClosure*)data)->func(std::forward<Args>(args)...);
class FunctionalClosure<Ret(Args...)> : private ClosureBase {
static inline Ret closureImpl(Args... args) {
auto& self = *static_cast<FunctionalClosure*>(reinterpret_cast<PackedSelf*>(getClosureData())->self);
return (self.func)(std::forward<Args>(args)...);
}

public:
using closure = Ret(Args...);

std::function<closure> func;

FunctionalClosure(std::function<closure> func)
: NativeClosure<Ret(Args...)>(closureImpl, (uintptr_t)this),
func(std::move(func)) {}
[[nodiscard]] FunctionalClosure(std::function<closure> func) : ClosureBase(closureImpl), func(std::move(func)) {}

[[nodiscard]] closure* get() const { return reinterpret_cast<closure*>(storage.executable()); }
};
template <class Ret, class... Args>
FunctionalClosure(Ret (*)(Args...)) -> FunctionalClosure<Ret(Args...)>;
Expand Down
15 changes: 7 additions & 8 deletions src/ll/api/memory/Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ size_t getUsableSize(void* ptr) { return getDefaultAllocator().getUsableSize(ptr
}
void DualMapping::alloc(size_t size) {
free();
memSize = size;
pointer = pl::DualMappingMemoryResource::getInstance().allocate(size);
memSize = size;
auto& allocator = pl::DualMappingMemoryResource::getInstance();
rw = allocator.allocate(size);
rx = allocator.executable(rw, memSize);
}
void DualMapping::free() {
if (!pointer) return;
pl::DualMappingMemoryResource::getInstance().deallocate(std::exchange(pointer, nullptr), std::exchange(memSize, 0));
}
void* DualMapping::executable() const {
if (!pointer) return nullptr;
return pl::DualMappingMemoryResource::getInstance().executable(pointer, memSize);
if (!rw) return;
rx = nullptr;
pl::DualMappingMemoryResource::getInstance().deallocate(std::exchange(rw, nullptr), std::exchange(memSize, 0));
}
} // namespace ll::memory
9 changes: 4 additions & 5 deletions src/ll/api/memory/Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,6 @@ constexpr auto construct(void* ptr, ptrdiff_t off, Args&&... args) {
);
}

LLNDAPI void* unwrapFuncAddress(void* ptr) noexcept;

LLNDAPI ::Bedrock::Memory::IMemoryAllocator& getDefaultAllocator();

[[noreturn]] LLAPI void throwMemoryException(size_t);
Expand Down Expand Up @@ -151,7 +149,8 @@ template <template <class> class P, class T>
#endif

class DualMapping {
void* pointer{};
void* rw{};
void* rx{};
size_t memSize{};

public:
Expand All @@ -166,7 +165,7 @@ class DualMapping {

size_t size() const { return memSize; }

void* writable() const { return pointer; }
LLAPI void* executable() const;
void* writable() const { return rw; }
void* executable() const { return rx; }
};
} // namespace ll::memory
57 changes: 0 additions & 57 deletions src/ll/api/memory/x64/Closure.cpp

This file was deleted.

10 changes: 0 additions & 10 deletions src/ll/api/memory/x64/Memory.cpp

This file was deleted.

3 changes: 2 additions & 1 deletion xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_requires("demangler v17.0.7")
add_requires("levibuildscript 0.2.0")
add_requires("preloader v1.12.0")
add_requires("symbolprovider v1.2.0")
add_requires("trampoline 2024.11.7")

if is_windows then
add_requires("libhat 2024.9.22")
Expand Down Expand Up @@ -107,7 +108,7 @@ target("LeviLamina")
add_headerfiles("src/(ll/api/**.h)", "src/(mc/**.h)")
add_includedirs("src", "$(buildir)/config")
set_pcxxheader("src/ll/api/Global.h")
add_packages("demangler", "mimalloc", "ctre", "cpr", "preloader")
add_packages("demangler", "mimalloc", "ctre", "cpr", "trampoline", "preloader")
add_packages(
"entt",
"expected-lite",
Expand Down

0 comments on commit d844740

Please sign in to comment.