Foreign function callbacks now receive a ModuleAndName parameter too.
This commit breaks the ARM64 version, I will fix it next. Lots going on here. DynafuncMaker got updated to store strings to back the ModuleAndName objects that get hardcoded in the assembly glue function. ModuleAndName is not a typedef to a tuple anymore, because I discovered that tuples suck. They get always pushed on the stack when passed as parameter, instead the new implementation gets passed into 2 registers being it a standard layout type. dhandy::bt::string got updated so it can be used as a literal value for non-type template parameters, which allowed for a really easy to use `wren::MN<>` helper. Code now fully requires c++20.
This commit is contained in:
parent
b2c694c954
commit
eadd25b827
16 changed files with 247 additions and 53 deletions
|
@ -23,8 +23,15 @@
|
|||
.global g_dynafunc_end
|
||||
|
||||
g_dynafunc:
|
||||
movq $0xdeadbeefdeadbeef, %rdi
|
||||
movq $0xbadc0ffee0ddf00d, %rdx
|
||||
jmp *%rdx
|
||||
//VM pointer, parameter 1
|
||||
movabsq $0xdeadbeefdeadbeef, %rdi
|
||||
//ModuleAndName string part, parameter 2
|
||||
movabsq $0x1badb0021badb002, %rsi
|
||||
//ModuleAndName data part, parameter 3
|
||||
movabsq $0xfee1deadfee1dead, %rdx
|
||||
|
||||
//jump address
|
||||
movabsq $0xbadc0ffee0ddf00d, %rax
|
||||
jmp *%rax
|
||||
ret
|
||||
g_dynafunc_end:
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "dynafunc_maker.hpp"
|
||||
#include "pvt_config.h"
|
||||
#include "wrenpp/detail/strings_in_vector.hpp"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <unistd.h> //for sysconf()
|
||||
|
@ -31,6 +32,8 @@
|
|||
#include <sys/mman.h> //for mprotect()
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
namespace wren {
|
||||
namespace {
|
||||
|
@ -44,8 +47,15 @@ namespace wren {
|
|||
|
||||
constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
|
||||
constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_PTR_SIZE;
|
||||
//For inspiration: https://www.liquisearch.com/deadbeef/magic_debug_values
|
||||
//0xdeadbeefdeadbeef
|
||||
constexpr unsigned char g_dynafunc_ptr1[] = {0xef, 0xbe, 0xad, 0xde, 0xef, 0xbe, 0xad, 0xde};
|
||||
//0xbadc0ffee0ddf00d
|
||||
constexpr unsigned char g_dynafunc_ptr2[] = {0x0d, 0xf0, 0xdd, 0xe0, 0xfe, 0x0f, 0xdc, 0xba};
|
||||
//0x1badb0021badb002
|
||||
constexpr unsigned char g_dynafunc_ptr3[] = {0x02, 0xb0, 0xad, 0x1b, 0x02, 0xb0, 0xad, 0x1b};
|
||||
//0xfee1deadfee1dead
|
||||
constexpr unsigned char g_dynafunc_ptr4[] = {0xad, 0xde, 0xe1, 0xfe, 0xad, 0xde, 0xe1, 0xfe};
|
||||
|
||||
static_assert(sizeof(g_dynafunc_ptr1) / sizeof(g_dynafunc_ptr1[0]) >= g_dynafunc_ptr1_size);
|
||||
static_assert(sizeof(g_dynafunc_ptr2) / sizeof(g_dynafunc_ptr2[0]) >= g_dynafunc_ptr2_size);
|
||||
|
@ -64,11 +74,52 @@ namespace wren {
|
|||
std::copy(ptr, ptr + sizeof(T), subseq);
|
||||
}
|
||||
|
||||
void make_dynafunc_asm(unsigned char* out, VM* ptr1, foreign_method_t ptr2) {
|
||||
void make_dynafunc_asm(
|
||||
unsigned char* out,
|
||||
VM* ptr1,
|
||||
foreign_method_t ptr2,
|
||||
RawAccessModuleAndName mn
|
||||
) {
|
||||
static_assert(std::is_standard_layout<ModuleAndName>::value,
|
||||
"Must be a standard layout to be compliant with the assembly functions");
|
||||
static_assert(sizeof(void*) * 2 == sizeof(ModuleAndName),
|
||||
"Must fit into 2 registers to be compliant with the assembly functions");
|
||||
|
||||
std::copy(g_dynafunc, g_dynafunc_end, out);
|
||||
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr1, ptr1);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr2, ptr2);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr3, mn.raw.string);
|
||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr4, mn.raw.data);
|
||||
}
|
||||
|
||||
ModuleAndName store_module_name (
|
||||
std::list<std::vector<char>>& dst,
|
||||
std::string_view mod_name,
|
||||
std::string_view cls_name
|
||||
) {
|
||||
typedef std::vector<char> CharVec;
|
||||
CharVec new_entry = strings_to_vector(mod_name, cls_name);
|
||||
|
||||
const auto it_found = std::lower_bound(
|
||||
dst.cbegin(),
|
||||
dst.cend(),
|
||||
new_entry,
|
||||
[](const CharVec& a, const CharVec& b) {
|
||||
return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
|
||||
}
|
||||
);
|
||||
|
||||
const CharVec* source_mem;
|
||||
if (dst.cend() != it_found) {
|
||||
assert(std::equal(it_found->cbegin(), it_found->cend(), new_entry.cbegin(), new_entry.cend()));
|
||||
source_mem = &*it_found;
|
||||
}
|
||||
else {
|
||||
source_mem = &*dst.insert(it_found, std::move(new_entry));
|
||||
}
|
||||
|
||||
return {source_mem->data(), 0, mod_name.size(), cls_name.size()};
|
||||
}
|
||||
} //unnamed namespace
|
||||
|
||||
|
@ -87,9 +138,11 @@ namespace wren {
|
|||
clear();
|
||||
}
|
||||
|
||||
void* DynafuncMaker::make (VM* vm, foreign_method_t cb) {
|
||||
void* DynafuncMaker::make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name) {
|
||||
unsigned char* const mem = allocate_chunk();
|
||||
make_dynafunc_asm(mem, vm, cb);
|
||||
const auto mn = store_module_name(m_string_params, mod_name, cls_name);
|
||||
make_dynafunc_asm(mem, vm, cb, mn);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "wrenpp/detail/wren_types.hpp"
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <cstddef>
|
||||
|
||||
namespace wren {
|
||||
|
@ -27,7 +28,7 @@ namespace wren {
|
|||
DynafuncMaker();
|
||||
~DynafuncMaker() noexcept;
|
||||
|
||||
void* make (VM* vm, foreign_method_t cb);
|
||||
void* make (VM* vm, foreign_method_t cb, const char* mod_name, const char* cls_name);
|
||||
void clear() noexcept;
|
||||
|
||||
std::size_t total_memory() const;
|
||||
|
@ -35,6 +36,7 @@ namespace wren {
|
|||
private:
|
||||
unsigned char* allocate_chunk();
|
||||
|
||||
std::list<std::vector<char>> m_string_params;
|
||||
std::vector<void*> m_pages;
|
||||
std::size_t m_page_size;
|
||||
std::size_t m_used_bytes;
|
||||
|
|
20
src/vm.cpp
20
src/vm.cpp
|
@ -89,7 +89,18 @@ namespace wren {
|
|||
if (func) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, func));
|
||||
//dfm->make creates a function that takes one WrenVM* parameter
|
||||
//which it disregards; then it calls func passing cb->owner to
|
||||
//it and a ModuleAndName object populated with the values given
|
||||
//here. This should rarely change, but please double check if
|
||||
//this is important to you as this comment might become
|
||||
//outdated.
|
||||
auto retval = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
|
||||
cb->owner,
|
||||
func,
|
||||
module,
|
||||
class_name
|
||||
));
|
||||
return retval;
|
||||
}
|
||||
else {
|
||||
|
@ -118,7 +129,12 @@ namespace wren {
|
|||
if (funcs.allocate) {
|
||||
DynafuncMaker* const dfm = cb->dynafunc;
|
||||
assert(dfm);
|
||||
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(cb->owner, funcs.allocate));
|
||||
retval.allocate = reinterpret_cast<WrenForeignMethodFn>(dfm->make(
|
||||
cb->owner,
|
||||
funcs.allocate,
|
||||
module,
|
||||
class_name
|
||||
));
|
||||
}
|
||||
else {
|
||||
retval.allocate = nullptr;
|
||||
|
|
|
@ -72,15 +72,15 @@ namespace wren {
|
|||
return std::vector<char>{arr.first, arr.first + arr.second};
|
||||
}
|
||||
|
||||
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot) {
|
||||
vm.variable_or_throw(std::get<0>(mod_and_name), std::get<1>(mod_and_name), slot);
|
||||
void variable(VM& vm, ModuleAndName mod_and_name, int slot) {
|
||||
vm.variable_or_throw(mod_and_name.module_name_char(), mod_and_name.class_name_char(), slot);
|
||||
}
|
||||
|
||||
void variable (VM& vm, const Handle& handle, int slot) {
|
||||
vm.set_slot_handle(handle, slot);
|
||||
}
|
||||
|
||||
void variable_ensure_slot(VM& vm, const ModuleAndName& mod_and_name, int slot) {
|
||||
void variable_ensure_slot(VM& vm, ModuleAndName mod_and_name, int slot) {
|
||||
vm.ensure_slots(1);
|
||||
variable(vm, mod_and_name, slot);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue