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
|
@ -69,7 +69,7 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void today (wren::VM& vm) {
|
static void today (wren::VM& vm, wren::ModuleAndName) {
|
||||||
vm.set_slot_string(0, today_unique_str().get());
|
vm.set_slot_string(0, today_unique_str().get());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ System.print("You have %(cale.appointment_count()) appointment(s)")
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
typedef wren::ModuleAndName MN;
|
using wren::MN;
|
||||||
|
|
||||||
MyConf conf;
|
MyConf conf;
|
||||||
wren::VM vm(&conf, nullptr);
|
wren::VM vm(&conf, nullptr);
|
||||||
|
@ -127,7 +127,7 @@ int main() {
|
||||||
|
|
||||||
vm.interpret("main", g_test_script);
|
vm.interpret("main", g_test_script);
|
||||||
|
|
||||||
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN{"main", "cale"}));
|
Calendar* const cale = std::get<0>(wren::variables<Calendar>(vm, MN<"main", "cale">));
|
||||||
cale->print_appointments();
|
cale->print_appointments();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -37,13 +37,13 @@ namespace {
|
||||||
std::uniform_int_distribution<int> distrib;
|
std::uniform_int_distribution<int> distrib;
|
||||||
};
|
};
|
||||||
|
|
||||||
void user_input(wren::VM& vm) {
|
void user_input(wren::VM& vm, wren::ModuleAndName) {
|
||||||
std::string retval;
|
std::string retval;
|
||||||
std::cin >> retval;
|
std::cin >> retval;
|
||||||
set(vm, 0, retval);
|
set(vm, 0, retval);
|
||||||
}
|
}
|
||||||
|
|
||||||
void random_num(wren::VM& vm) {
|
void random_num(wren::VM& vm, wren::ModuleAndName) {
|
||||||
auto* const cust_data = vm.user_data<CustomData>();
|
auto* const cust_data = vm.user_data<CustomData>();
|
||||||
set(vm, 0, cust_data->distrib(cust_data->generator));
|
set(vm, 0, cust_data->distrib(cust_data->generator));
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ int main() {
|
||||||
.add_callback(true, "main", "Game", "random()", &random_num);
|
.add_callback(true, "main", "Game", "random()", &random_num);
|
||||||
|
|
||||||
interpret(vm, "main", load_file("main.wren"));
|
interpret(vm, "main", load_file("main.wren"));
|
||||||
wren::call<void>(vm, {"main", "the_game"}, "play_game");
|
wren::call<void>(vm, wren::MN<"main", "the_game">, "play_game");
|
||||||
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -56,7 +56,7 @@ const char* raw_fetch_env (const char* name) noexcept {
|
||||||
return val_ptr;
|
return val_ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void user_get_env (wren::VM& vm) {
|
void user_get_env (wren::VM& vm, wren::ModuleAndName) {
|
||||||
set(vm, 0, raw_fetch_env(wren::get<const char*>(vm, 1)));
|
set(vm, 0, raw_fetch_env(wren::get<const char*>(vm, 1)));
|
||||||
}
|
}
|
||||||
} //unnamed namespace
|
} //unnamed namespace
|
||||||
|
@ -70,7 +70,7 @@ int main() {
|
||||||
|
|
||||||
vm.interpret("main", g_script);
|
vm.interpret("main", g_script);
|
||||||
|
|
||||||
wren::call<void>(vm, {"main", "the_user"}, "greet");
|
wren::call<void>(vm, wren::MN<"main", "the_user">, "greet");
|
||||||
|
|
||||||
std::cout << "Quitting in 1 sec" << std::endl;
|
std::cout << "Quitting in 1 sec" << std::endl;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||||
|
|
|
@ -130,7 +130,7 @@ namespace wren {
|
||||||
detail::static_assert_all_packs_are_unique<Args...>();
|
detail::static_assert_all_packs_are_unique<Args...>();
|
||||||
|
|
||||||
foreign_class_t ret;
|
foreign_class_t ret;
|
||||||
ret.allocate = [](VM& vm) {
|
ret.allocate = [](VM& vm, ModuleAndName mn) {
|
||||||
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
||||||
|
|
||||||
const auto result = detail::ForeignClassHelper<T, Args...>::construct(vm, vm.slot_count() - 1, mem);
|
const auto result = detail::ForeignClassHelper<T, Args...>::construct(vm, vm.slot_count() - 1, mem);
|
||||||
|
|
|
@ -61,7 +61,7 @@ namespace wren {
|
||||||
constexpr auto from = last_whatever + (last_whatever == fname_len ? 0 : 1);
|
constexpr auto from = last_whatever + (last_whatever == fname_len ? 0 : 1);
|
||||||
constexpr auto len = detail::find_token_end(fname + from, fname_len - from);
|
constexpr auto len = detail::find_token_end(fname + from, fname_len - from);
|
||||||
|
|
||||||
constexpr dhandy::bt::string<len> retval{fname + from};
|
constexpr dhandy::bt::string<len> retval{fname + from, 0};
|
||||||
return retval;
|
return retval;
|
||||||
//#elif defined(_MSC_VER)
|
//#elif defined(_MSC_VER)
|
||||||
//void __cdecl guess_class_name<class MyTest>(void)
|
//void __cdecl guess_class_name<class MyTest>(void)
|
||||||
|
|
|
@ -3,6 +3,7 @@ include_files = [
|
||||||
'error_type.hpp',
|
'error_type.hpp',
|
||||||
'guess_class_name.hpp',
|
'guess_class_name.hpp',
|
||||||
'has_method.hpp',
|
'has_method.hpp',
|
||||||
|
'module_and_name.hpp',
|
||||||
'setters_getters.hpp',
|
'setters_getters.hpp',
|
||||||
'string_bt.hpp',
|
'string_bt.hpp',
|
||||||
'StringCRC32.hpp',
|
'StringCRC32.hpp',
|
||||||
|
|
98
include/wrenpp/detail/module_and_name.hpp
Normal file
98
include/wrenpp/detail/module_and_name.hpp
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
/* Copyright 2020-2022, Michele Santullo
|
||||||
|
* This file is part of wrenpp.
|
||||||
|
*
|
||||||
|
* Wrenpp is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* Wrenpp is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with wrenpp. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "string_bt.hpp"
|
||||||
|
#include <string_view>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace wren {
|
||||||
|
namespace detail {
|
||||||
|
template <dhandy::bt::string S>
|
||||||
|
struct ModuleAndNameStaticStorage {
|
||||||
|
static constexpr const auto value = S;
|
||||||
|
};
|
||||||
|
} //unnamed namespace
|
||||||
|
|
||||||
|
//Non-owning, lightweight class for storing a module nome/class name pair.
|
||||||
|
//They are stored as consecutive strings within a single buffer with a
|
||||||
|
//null-char in-between and at the end so that each name is null-terminated
|
||||||
|
//and can be used with C APIs.
|
||||||
|
//Keep the size small, ideally within 2 registers size. Altering this might
|
||||||
|
//require changes to the assembly source files for DynafuncMaker.
|
||||||
|
//When passed as a parameter by value, objects of ModuleAndName fit into
|
||||||
|
//2 registers on 64 bit architectures. This is important because objects
|
||||||
|
//of this class get hardcoded in the dynamic functions that DynafuncMaker
|
||||||
|
//spits out.
|
||||||
|
class ModuleAndName {
|
||||||
|
public:
|
||||||
|
constexpr ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len);
|
||||||
|
|
||||||
|
constexpr const char* module_name_char() const noexcept { return m_base; }
|
||||||
|
constexpr const char* class_name_char() const noexcept { return m_base + 1 + m_mod_name_len; }
|
||||||
|
constexpr std::size_t module_name_len() const noexcept { return m_mod_name_len; }
|
||||||
|
constexpr std::size_t class_name_len() const noexcept { return m_class_name_len; }
|
||||||
|
constexpr std::string_view module_name() const noexcept { return {module_name_char(), m_mod_name_len}; }
|
||||||
|
constexpr std::string_view class_name() const noexcept { return {class_name_char(), m_class_name_len}; }
|
||||||
|
constexpr const char* buffer_address() const noexcept { return m_base; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_base;
|
||||||
|
std::uint32_t m_hash;
|
||||||
|
std::uint16_t m_mod_name_len;
|
||||||
|
std::uint16_t m_class_name_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
union RawAccessModuleAndName {
|
||||||
|
constexpr RawAccessModuleAndName (ModuleAndName mn) :
|
||||||
|
module_and_name(mn)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
ModuleAndName module_and_name;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
void* string;
|
||||||
|
void* data;
|
||||||
|
} raw;
|
||||||
|
|
||||||
|
static_assert(sizeof(raw) == sizeof(module_and_name));
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr ModuleAndName::ModuleAndName (const char* base, std::uint32_t hash, std::size_t mod_name_len, std::size_t class_name_len) :
|
||||||
|
m_base(base),
|
||||||
|
m_hash(hash),
|
||||||
|
m_mod_name_len(mod_name_len),
|
||||||
|
m_class_name_len(class_name_len)
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <dhandy::bt::string S1, dhandy::bt::string S2>
|
||||||
|
constexpr ModuleAndName make_module_and_name() {
|
||||||
|
using dhandy::bt::string;
|
||||||
|
|
||||||
|
constexpr const char* data = detail::ModuleAndNameStaticStorage<S1 + string("\0") + S2>::value.data();
|
||||||
|
constexpr std::uint16_t s1_len = static_cast<std::uint16_t>(S1.size());
|
||||||
|
constexpr std::uint16_t s2_len = static_cast<std::uint16_t>(S2.size());
|
||||||
|
constexpr std::uint32_t hash = 0; //not implemented yet
|
||||||
|
|
||||||
|
return ModuleAndName{data, hash, s1_len, s2_len};
|
||||||
|
}
|
||||||
|
|
||||||
|
//short-hand alias for make_module_and_name
|
||||||
|
template <dhandy::bt::string S1, dhandy::bt::string S2>
|
||||||
|
constexpr ModuleAndName MN = make_module_and_name<S1, S2>();
|
||||||
|
} //namespace wren
|
|
@ -41,7 +41,11 @@ namespace dhandy {
|
||||||
friend constexpr bool implem::eq<S, Ch> (const string<S, Ch>&, const string<S, Ch>&);
|
friend constexpr bool implem::eq<S, Ch> (const string<S, Ch>&, const string<S, Ch>&);
|
||||||
public:
|
public:
|
||||||
using value_type = Ch;
|
using value_type = Ch;
|
||||||
constexpr string ( const value_type* parString );
|
constexpr string ( const string& other ) = default;
|
||||||
|
constexpr string ( const value_type (&parString)[S] );
|
||||||
|
|
||||||
|
//overload for pointers, int is only for overload disambiguation
|
||||||
|
constexpr string ( const value_type* parString, int );
|
||||||
|
|
||||||
constexpr std::size_t size ( void ) const { return S - 1; }
|
constexpr std::size_t size ( void ) const { return S - 1; }
|
||||||
template <std::size_t S2>
|
template <std::size_t S2>
|
||||||
|
@ -52,18 +56,26 @@ namespace dhandy {
|
||||||
template <std::size_t S2> constexpr bool operator== (const string<S2, Ch>&) const { return false; }
|
template <std::size_t S2> constexpr bool operator== (const string<S2, Ch>&) const { return false; }
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
requires (std::is_same_v<Args, typename string<S, Ch>::value_type> && ...)
|
||||||
constexpr string ( Args... );
|
constexpr string ( Args... );
|
||||||
|
|
||||||
constexpr const value_type (&data_arr() const)[S] { return m_data; }
|
constexpr const value_type (&data_arr() const)[S] { return m_data; }
|
||||||
constexpr const value_type* data() const { return m_data; }
|
constexpr const value_type* data() const { return m_data; }
|
||||||
|
|
||||||
private:
|
//can't have any private members but from below this point please
|
||||||
|
//consider everything as private
|
||||||
|
//private:
|
||||||
template <std::size_t... I>
|
template <std::size_t... I>
|
||||||
constexpr string ( std::index_sequence<I...>, const value_type* parString );
|
constexpr string ( std::index_sequence<I...>, const value_type* parString );
|
||||||
|
|
||||||
const value_type m_data[S];
|
const value_type m_data[S];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <std::size_t S, typename Ch>
|
||||||
|
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
|
||||||
|
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
|
||||||
|
}
|
||||||
|
|
||||||
namespace implem {
|
namespace implem {
|
||||||
template <std::size_t S, std::size_t S2, std::size_t... I>
|
template <std::size_t S, std::size_t S2, std::size_t... I>
|
||||||
constexpr string<S + S2 - 1> concat ( std::index_sequence<I...>, const string<S>& parLeft, const string<S2>& parRight ) {
|
constexpr string<S + S2 - 1> concat ( std::index_sequence<I...>, const string<S>& parLeft, const string<S2>& parRight ) {
|
||||||
|
@ -85,13 +97,20 @@ namespace dhandy {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
template <std::size_t S, typename Ch>
|
||||||
inline constexpr string<S, Ch>::string (const value_type* parString) :
|
inline constexpr string<S, Ch>::string (const value_type (&parString)[S]) :
|
||||||
|
string(std::make_index_sequence<S>(), parString)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t S, typename Ch>
|
||||||
|
inline constexpr string<S, Ch>::string (const value_type* parString, int) :
|
||||||
string(std::make_index_sequence<S>(), parString)
|
string(std::make_index_sequence<S>(), parString)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
template <std::size_t S, typename Ch>
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
requires (std::is_same_v<Args, typename string<S, Ch>::value_type> && ...)
|
||||||
inline constexpr string<S, Ch>::string (Args... parArgs) :
|
inline constexpr string<S, Ch>::string (Args... parArgs) :
|
||||||
m_data{parArgs...}
|
m_data{parArgs...}
|
||||||
{
|
{
|
||||||
|
@ -109,16 +128,6 @@ namespace dhandy {
|
||||||
return parStream;
|
return parStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
|
||||||
constexpr auto string<S, Ch>::operator[] (std::size_t parIndex) const -> value_type {
|
|
||||||
return (parIndex < S ? m_data[parIndex] : throw std::out_of_range(""));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
|
||||||
constexpr string<S, Ch> make_string (const Ch (&parData)[S]) {
|
|
||||||
return string<S>(parData);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <std::size_t S, typename Ch>
|
template <std::size_t S, typename Ch>
|
||||||
constexpr bool string<S, Ch>::operator== (const string<S, Ch>& other) const {
|
constexpr bool string<S, Ch>::operator== (const string<S, Ch>& other) const {
|
||||||
return implem::eq(*this, other);
|
return implem::eq(*this, other);
|
||||||
|
@ -127,7 +136,7 @@ namespace dhandy {
|
||||||
template <std::size_t S, typename Ch>
|
template <std::size_t S, typename Ch>
|
||||||
template <std::size_t Start, std::size_t Len>
|
template <std::size_t Start, std::size_t Len>
|
||||||
constexpr auto string<S, Ch>::substr() const {
|
constexpr auto string<S, Ch>::substr() const {
|
||||||
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1)) + make_string("");
|
return string<std::min(S - 1 - std::min(Start, S - 1), Len) + 1, Ch>(m_data + std::min(Start, S - 1), 0) + string("");
|
||||||
}
|
}
|
||||||
} //namespace bt
|
} //namespace bt
|
||||||
} //namespace dhandy
|
} //namespace dhandy
|
||||||
|
|
|
@ -70,6 +70,7 @@ namespace wren {
|
||||||
template <std::size_t Count, std::size_t... Indices>
|
template <std::size_t Count, std::size_t... Indices>
|
||||||
class StringsInVectorImplem<Count, std::index_sequence<Indices...>> : detail::StringsInVectorBase<Indices>... {
|
class StringsInVectorImplem<Count, std::index_sequence<Indices...>> : detail::StringsInVectorBase<Indices>... {
|
||||||
typedef detail::StringsInVectorWordRange WordRange;
|
typedef detail::StringsInVectorWordRange WordRange;
|
||||||
|
template <typename... Strings> friend std::vector<char> strings_to_vector(const Strings&...);
|
||||||
public:
|
public:
|
||||||
template <typename... Strings>
|
template <typename... Strings>
|
||||||
StringsInVectorImplem (const Strings&... strings);
|
StringsInVectorImplem (const Strings&... strings);
|
||||||
|
@ -133,4 +134,10 @@ namespace wren {
|
||||||
|
|
||||||
template <std::size_t Count>
|
template <std::size_t Count>
|
||||||
using StringsInVector = StringsInVectorImplem<Count, decltype(std::make_index_sequence<Count>())>;
|
using StringsInVector = StringsInVectorImplem<Count, decltype(std::make_index_sequence<Count>())>;
|
||||||
|
|
||||||
|
template <typename... Strings>
|
||||||
|
inline std::vector<char> strings_to_vector (const Strings&... strings) {
|
||||||
|
StringsInVector<sizeof...(Strings)> siv{strings...};
|
||||||
|
return siv.m_memory;
|
||||||
|
}
|
||||||
} //namespace wren
|
} //namespace wren
|
||||||
|
|
|
@ -17,16 +17,15 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "module_and_name.hpp"
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace wren {
|
namespace wren {
|
||||||
class VM;
|
class VM;
|
||||||
|
|
||||||
typedef std::tuple<const char*, const char*> ModuleAndName;
|
|
||||||
typedef std::string_view wren_string_t;
|
typedef std::string_view wren_string_t;
|
||||||
typedef void(*finalizer_t)(void*);
|
typedef void(*finalizer_t)(void*);
|
||||||
typedef void(*foreign_method_t)(VM&);
|
typedef void(*foreign_method_t)(VM&, ModuleAndName);
|
||||||
|
|
||||||
struct foreign_class_t {
|
struct foreign_class_t {
|
||||||
foreign_method_t allocate;
|
foreign_method_t allocate;
|
||||||
|
|
|
@ -36,16 +36,16 @@ namespace wren {
|
||||||
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
|
R call (VM& vm, const Handle& object, const Handle& method, const Args&... args);
|
||||||
|
|
||||||
template <typename R, typename... Args>
|
template <typename R, typename... Args>
|
||||||
R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args);
|
R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args);
|
||||||
|
|
||||||
template <typename R, std::size_t N, typename... Args>
|
template <typename R, std::size_t N, typename... Args>
|
||||||
R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args);
|
R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args);
|
||||||
|
|
||||||
template <typename R, std::size_t N, typename... Args>
|
template <typename R, std::size_t N, typename... Args>
|
||||||
R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args);
|
R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args);
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
T* make_wren_object(VM& vm, const ModuleAndName& mn, Args&&... args);
|
T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args);
|
||||||
|
|
||||||
#if defined(WRENPP_WITH_NAME_GUESSING)
|
#if defined(WRENPP_WITH_NAME_GUESSING)
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
|
@ -56,9 +56,9 @@ namespace wren {
|
||||||
foreign_method_t make_method_bindable();
|
foreign_method_t make_method_bindable();
|
||||||
|
|
||||||
void interpret (VM& vm, const std::string& module_name, const std::string& script);
|
void interpret (VM& vm, const std::string& module_name, const std::string& script);
|
||||||
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot);
|
void variable(VM& vm, ModuleAndName mod_and_name, int slot);
|
||||||
void variable(VM& vm, const Handle& handle, int slot);
|
void variable(VM& vm, const Handle& handle, int 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);
|
||||||
void variable_ensure_slot(VM& vm, const Handle& handle, int slot);
|
void variable_ensure_slot(VM& vm, const Handle& handle, int slot);
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@ -97,7 +97,7 @@ namespace wren {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static foreign_method_t make() {
|
static foreign_method_t make() {
|
||||||
return [](VM& vm) {
|
return [](VM& vm, ModuleAndName) {
|
||||||
if constexpr (std::is_same_v<R, void>) {
|
if constexpr (std::is_same_v<R, void>) {
|
||||||
call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
|
call_implem(std::make_integer_sequence<int, sizeof...(Args)>(), vm);
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ namespace wren {
|
||||||
template <auto V> struct MakeMethodBindable;
|
template <auto V> struct MakeMethodBindable;
|
||||||
template <typename T, void(T::*Method)(VM&)> struct MakeMethodBindable<Method> {
|
template <typename T, void(T::*Method)(VM&)> struct MakeMethodBindable<Method> {
|
||||||
static foreign_method_t make() {
|
static foreign_method_t make() {
|
||||||
return [](VM& vm) {
|
return [](VM& vm, ModuleAndName) {
|
||||||
T* obj = foreign<T>(vm, 0);
|
T* obj = foreign<T>(vm, 0);
|
||||||
(obj->*Method)(vm);
|
(obj->*Method)(vm);
|
||||||
};
|
};
|
||||||
|
@ -139,7 +139,7 @@ namespace wren {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, typename... Args>
|
template <typename R, typename... Args>
|
||||||
inline R call (VM& vm, const ModuleAndName& object, const Handle& method, const Args&... args) {
|
inline R call (VM& vm, ModuleAndName object, const Handle& method, const Args&... args) {
|
||||||
vm.ensure_slots(sizeof...(args) + 1);
|
vm.ensure_slots(sizeof...(args) + 1);
|
||||||
variable(vm, object, 0);
|
variable(vm, object, 0);
|
||||||
Handle obj_handle = vm.slot_handle(0);
|
Handle obj_handle = vm.slot_handle(0);
|
||||||
|
@ -148,11 +148,13 @@ namespace wren {
|
||||||
|
|
||||||
template <typename R, std::size_t N, typename... Args>
|
template <typename R, std::size_t N, typename... Args>
|
||||||
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
|
inline R call (VM& vm, const Handle& object, const char (&method)[N], const Args&... args) {
|
||||||
|
using dhandy::bt::string;
|
||||||
|
|
||||||
const constexpr char dummy_name_buff[N] = {0};
|
const constexpr char dummy_name_buff[N] = {0};
|
||||||
const constexpr auto params = dhandy::bt::string<N, char>(dummy_name_buff) +
|
const constexpr auto params = string<N, char>(dummy_name_buff) +
|
||||||
dhandy::bt::make_string("(") +
|
string("(") +
|
||||||
((static_cast<void>(args), dhandy::bt::make_string(",_")) + ... + dhandy::bt::make_string("")).template substr<1>() +
|
((static_cast<void>(args), string(",_")) + ... + string("")).template substr<1>() +
|
||||||
dhandy::bt::make_string(")");
|
string(")");
|
||||||
;
|
;
|
||||||
char cat_buff[params.size() + 1];
|
char cat_buff[params.size() + 1];
|
||||||
std::copy(method, method + N - 1, cat_buff);
|
std::copy(method, method + N - 1, cat_buff);
|
||||||
|
@ -161,7 +163,7 @@ namespace wren {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename R, std::size_t N, typename... Args>
|
template <typename R, std::size_t N, typename... Args>
|
||||||
inline R call (VM& vm, const ModuleAndName& object, const char (&method)[N], const Args&... args) {
|
inline R call (VM& vm, ModuleAndName object, const char (&method)[N], const Args&... args) {
|
||||||
vm.ensure_slots(sizeof...(args) + 1);
|
vm.ensure_slots(sizeof...(args) + 1);
|
||||||
variable(vm, object, 0);
|
variable(vm, object, 0);
|
||||||
Handle obj_handle = vm.slot_handle(0);
|
Handle obj_handle = vm.slot_handle(0);
|
||||||
|
@ -169,7 +171,7 @@ namespace wren {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename... Args>
|
template <typename T, typename... Args>
|
||||||
inline T* make_wren_object(VM& vm, const ModuleAndName& mn, Args&&... args) {
|
inline T* make_wren_object(VM& vm, ModuleAndName mn, Args&&... args) {
|
||||||
variable(vm, mn, 0);
|
variable(vm, mn, 0);
|
||||||
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
void* const mem = vm.set_slot_new_foreign(0, 0, sizeof(T));
|
||||||
T* const obj = new(mem) T{std::forward<Args>(args)...};
|
T* const obj = new(mem) T{std::forward<Args>(args)...};
|
||||||
|
|
|
@ -23,8 +23,15 @@
|
||||||
.global g_dynafunc_end
|
.global g_dynafunc_end
|
||||||
|
|
||||||
g_dynafunc:
|
g_dynafunc:
|
||||||
movq $0xdeadbeefdeadbeef, %rdi
|
//VM pointer, parameter 1
|
||||||
movq $0xbadc0ffee0ddf00d, %rdx
|
movabsq $0xdeadbeefdeadbeef, %rdi
|
||||||
jmp *%rdx
|
//ModuleAndName string part, parameter 2
|
||||||
|
movabsq $0x1badb0021badb002, %rsi
|
||||||
|
//ModuleAndName data part, parameter 3
|
||||||
|
movabsq $0xfee1deadfee1dead, %rdx
|
||||||
|
|
||||||
|
//jump address
|
||||||
|
movabsq $0xbadc0ffee0ddf00d, %rax
|
||||||
|
jmp *%rax
|
||||||
ret
|
ret
|
||||||
g_dynafunc_end:
|
g_dynafunc_end:
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "dynafunc_maker.hpp"
|
#include "dynafunc_maker.hpp"
|
||||||
#include "pvt_config.h"
|
#include "pvt_config.h"
|
||||||
|
#include "wrenpp/detail/strings_in_vector.hpp"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <unistd.h> //for sysconf()
|
#include <unistd.h> //for sysconf()
|
||||||
|
@ -31,6 +32,8 @@
|
||||||
#include <sys/mman.h> //for mprotect()
|
#include <sys/mman.h> //for mprotect()
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <string_view>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace wren {
|
namespace wren {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -44,8 +47,15 @@ namespace wren {
|
||||||
|
|
||||||
constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
|
constexpr unsigned int g_dynafunc_ptr1_size = ASM_PTR_SIZE;
|
||||||
constexpr unsigned int g_dynafunc_ptr2_size = ASM_FUNC_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};
|
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};
|
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_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);
|
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);
|
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);
|
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_ptr1, ptr1);
|
||||||
replace_ptr(out, out + g_dynafunc_len, g_dynafunc_ptr2, ptr2);
|
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
|
} //unnamed namespace
|
||||||
|
|
||||||
|
@ -87,9 +138,11 @@ namespace wren {
|
||||||
clear();
|
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();
|
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;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "wrenpp/detail/wren_types.hpp"
|
#include "wrenpp/detail/wren_types.hpp"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <list>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
namespace wren {
|
namespace wren {
|
||||||
|
@ -27,7 +28,7 @@ namespace wren {
|
||||||
DynafuncMaker();
|
DynafuncMaker();
|
||||||
~DynafuncMaker() noexcept;
|
~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;
|
void clear() noexcept;
|
||||||
|
|
||||||
std::size_t total_memory() const;
|
std::size_t total_memory() const;
|
||||||
|
@ -35,6 +36,7 @@ namespace wren {
|
||||||
private:
|
private:
|
||||||
unsigned char* allocate_chunk();
|
unsigned char* allocate_chunk();
|
||||||
|
|
||||||
|
std::list<std::vector<char>> m_string_params;
|
||||||
std::vector<void*> m_pages;
|
std::vector<void*> m_pages;
|
||||||
std::size_t m_page_size;
|
std::size_t m_page_size;
|
||||||
std::size_t m_used_bytes;
|
std::size_t m_used_bytes;
|
||||||
|
|
20
src/vm.cpp
20
src/vm.cpp
|
@ -89,7 +89,18 @@ namespace wren {
|
||||||
if (func) {
|
if (func) {
|
||||||
DynafuncMaker* const dfm = cb->dynafunc;
|
DynafuncMaker* const dfm = cb->dynafunc;
|
||||||
assert(dfm);
|
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;
|
return retval;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -118,7 +129,12 @@ namespace wren {
|
||||||
if (funcs.allocate) {
|
if (funcs.allocate) {
|
||||||
DynafuncMaker* const dfm = cb->dynafunc;
|
DynafuncMaker* const dfm = cb->dynafunc;
|
||||||
assert(dfm);
|
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 {
|
else {
|
||||||
retval.allocate = nullptr;
|
retval.allocate = nullptr;
|
||||||
|
|
|
@ -72,15 +72,15 @@ namespace wren {
|
||||||
return std::vector<char>{arr.first, arr.first + arr.second};
|
return std::vector<char>{arr.first, arr.first + arr.second};
|
||||||
}
|
}
|
||||||
|
|
||||||
void variable(VM& vm, const ModuleAndName& mod_and_name, int slot) {
|
void variable(VM& vm, ModuleAndName mod_and_name, int slot) {
|
||||||
vm.variable_or_throw(std::get<0>(mod_and_name), std::get<1>(mod_and_name), 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) {
|
void variable (VM& vm, const Handle& handle, int slot) {
|
||||||
vm.set_slot_handle(handle, 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);
|
vm.ensure_slots(1);
|
||||||
variable(vm, mod_and_name, slot);
|
variable(vm, mod_and_name, slot);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue