diff --git a/src/wren/vm.cpp b/src/wren/vm.cpp index faaf54f..a63d263 100644 --- a/src/wren/vm.cpp +++ b/src/wren/vm.cpp @@ -19,39 +19,55 @@ namespace wren { void write_fn (WrenVM* wvm, const char* text) { auto cb = static_cast(wrenGetUserData(wvm)); assert(cb); - assert(cb->write_fn and cb->config_obj and cb->vm); - cb->write_fn(*cb->config_obj, cb->vm, text); + assert(cb->write_fn and cb->config_obj and cb->owner); + cb->write_fn(*cb->config_obj, cb->owner, text); } void error_fn (WrenVM* wvm, WrenErrorType type, const char* module, int line, const char* message) { auto cb = static_cast(wrenGetUserData(wvm)); assert(cb); - assert(cb->error_fn and cb->config_obj and cb->vm); - cb->error_fn(*cb->config_obj, cb->vm, to_error_type(type), module, line, message); + assert(cb->error_fn and cb->config_obj and cb->owner); + cb->error_fn(*cb->config_obj, cb->owner, to_error_type(type), module, line, message); } const char* resolve_module_fn (WrenVM* wvm, const char* importer, const char* name) { auto cb = static_cast(wrenGetUserData(wvm)); assert(cb); - assert(cb->resolve_module_fn and cb->config_obj and cb->vm); - return cb->resolve_module_fn(*cb->config_obj, cb->vm, importer, name); + assert(cb->resolve_module_fn and cb->config_obj and cb->owner); + return cb->resolve_module_fn(*cb->config_obj, cb->owner, importer, name); } char* load_module_fn (WrenVM* wvm, const char* name) { auto cb = static_cast(wrenGetUserData(wvm)); assert(cb); - assert(cb->load_module_fn and cb->config_obj and cb->vm); - return cb->load_module_fn(*cb->config_obj, cb->vm, name); + assert(cb->load_module_fn and cb->config_obj and cb->owner); + return cb->load_module_fn(*cb->config_obj, cb->owner, name); } } //unnamed namespace + struct VM::LocalData { + explicit LocalData (const detail::Callbacks& cb) : + callbacks(cb), + wvm(nullptr) + {} + ~LocalData() noexcept { + if (wvm) + wrenFreeVM(wvm); +#if !defined(NDEBUG) + wvm = nullptr; +#endif + } + + detail::Callbacks callbacks; + WrenVM* wvm; + }; + VM::VM (Configuration* conf, const detail::Callbacks& cb) : - m_callbacks(cb), - m_vm(nullptr) + m_local(std::make_unique(cb)) { WrenConfiguration wconf; wrenInitConfiguration(&wconf); - wconf.userData = static_cast(&m_callbacks); + wconf.userData = static_cast(&m_local->callbacks); wconf.initialHeapSize = conf->initial_heap_size(); wconf.minHeapSize = conf->min_heap_size(); @@ -72,33 +88,20 @@ namespace wren { if (cb.load_module_fn) wconf.loadModuleFn = &load_module_fn; - m_vm = wrenNewVM(&wconf); - if (not m_vm) + m_local->wvm = wrenNewVM(&wconf); + if (not m_local->wvm) throw std::runtime_error("Failed to initialize Wren VM"); } - VM::VM (VM&& other) : - m_vm(nullptr) - { - std::swap(m_vm, other.m_vm); - m_callbacks = other.m_callbacks; - wrenSetUserData(m_vm, &m_callbacks); - } - - VM::~VM() noexcept { - if (m_vm) - wrenFreeVM(m_vm); -#if !defined(NDEBUG) - m_vm = nullptr; -#endif - } + VM::VM (VM&& other) = default; + VM::~VM() noexcept = default; void VM::interpret (const char* module_name, const char* script) { using std::string; using std::runtime_error; - const WrenInterpretResult res = wrenInterpret(m_vm, module_name, script); + const WrenInterpretResult res = wrenInterpret(m_local->wvm, module_name, script); switch (res) { case WREN_RESULT_COMPILE_ERROR: throw runtime_error(string("Compilation of ") + module_name + " has failed"); diff --git a/src/wren/vm.hpp b/src/wren/vm.hpp index d46c59e..80f53ca 100644 --- a/src/wren/vm.hpp +++ b/src/wren/vm.hpp @@ -3,10 +3,7 @@ #include "has_method.hpp" #include "error_type.hpp" #include - -extern "C" { - typedef struct WrenVM WrenVM; -} //extern C +#include namespace wren { class Configuration; @@ -21,7 +18,7 @@ namespace wren { char* (*load_module_fn)(Configuration&, VM*, const char*) {nullptr}; Configuration* config_obj {nullptr}; - VM* vm {nullptr}; + VM* owner {nullptr}; }; } //namespace detail @@ -37,13 +34,14 @@ namespace wren { void interpret (const std::string& module_name, const std::string& script); private: + struct LocalData; + VM (Configuration* conf, const detail::Callbacks&); template detail::Callbacks to_callbacks (T& conf); - detail::Callbacks m_callbacks; - WrenVM* m_vm; + std::unique_ptr m_local; }; namespace detail { @@ -76,7 +74,7 @@ namespace wren { detail::Callbacks ret; ret.config_obj = &conf; - ret.vm = this; + ret.owner = this; if constexpr (detail::method_write::exists::value) ret.write_fn = &detail::AnyFunctionWrap::template call<&T::write_fn>;