Skip to content

Commit

Permalink
[#79] feat(vm): add transient and opaque instances
Browse files Browse the repository at this point in the history
  • Loading branch information
Try authored Aug 19, 2023
1 parent 727f6b5 commit a348a38
Show file tree
Hide file tree
Showing 4 changed files with 332 additions and 67 deletions.
72 changes: 70 additions & 2 deletions include/phoenix/script.hh
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,17 @@ namespace phoenix {
/// \brief A pointer which may be used by the user of this API
void* user_ptr = nullptr;

protected:
PHOENIX_INTERNAL virtual std::uint8_t* data() {
return reinterpret_cast<std::uint8_t*>(this);
}

PHOENIX_INTERNAL virtual const std::uint8_t* data() const {
return reinterpret_cast<const std::uint8_t*>(this);
}

private:
friend class transient_instance;
friend class symbol;
friend class script;
friend class vm;
Expand All @@ -226,6 +236,54 @@ namespace phoenix {
const std::type_info* _m_type {nullptr};
};

/// \brief Represents an object associated with an instance in the script.
///
/// Instances allocated with init_opaque will be backed up by this class with plain memory storage
class opaque_instance final : public instance {
public:
PHOENIX_INTERNAL opaque_instance(symbol const& sym, std::vector<symbol*> const& members);
PHOENIX_INTERNAL ~opaque_instance();

protected:
friend class symbol;

PHOENIX_INTERNAL std::uint8_t* data() override {
return _m_storage.get();
}

PHOENIX_INTERNAL const std::uint8_t* data() const override {
return _m_storage.get();
}

private:
template <typename T, typename... Args>
PHOENIX_INTERNAL T* construct_at(size_t offset, Args&&... args);

std::unique_ptr<std::uint8_t[]> _m_storage;
std::vector<std::string*> _m_strings;
};

/// \brief Represents object instance in the script with no defined backing to memory.
///
/// Expected to be used for DMA mods or to emulate variable-like access to engine-functions.
class transient_instance : public instance {
public:
transient_instance();
~transient_instance();

protected:
friend class symbol;

virtual void set_int(symbol const& sym, uint16_t index, std::int32_t value) = 0;
virtual std::int32_t get_int(symbol const& sym, uint16_t index) = 0;

virtual void set_float(symbol const& sym, uint16_t index, float value) = 0;
virtual float get_float(symbol const& sym, uint16_t index) = 0;

virtual void set_string(symbol const& sym, uint16_t index, std::string_view value) = 0;
virtual const std::string& get_string(symbol const& sym, uint16_t index) = 0;
};

/// \brief The base class for all exceptions thrown by interacting with a script.
struct script_error : public error {
using error::error;
Expand Down Expand Up @@ -573,8 +631,9 @@ namespace phoenix {
if (*_m_registered_to != *context->_m_type)
throw illegal_context_type {this, *context->_m_type};

auto data_ptr = context->data();
std::uint32_t target_offset = offset_as_member() + index * sizeof(T);
return reinterpret_cast<const T*>(reinterpret_cast<const char*>(context.get()) + target_offset);
return reinterpret_cast<const T*>(data_ptr + target_offset);
}

template <typename T>
Expand All @@ -584,8 +643,9 @@ namespace phoenix {
if (*_m_registered_to != *context->_m_type)
throw illegal_context_type {this, *context->_m_type};

auto data_ptr = context->data();
std::uint32_t target_offset = offset_as_member() + index * sizeof(T);
return reinterpret_cast<T*>(reinterpret_cast<char*>(context.get()) + target_offset);
return reinterpret_cast<T*>(data_ptr + target_offset);
}

private:
Expand Down Expand Up @@ -792,6 +852,14 @@ namespace phoenix {
return find_symbol_by_index(inst->_m_symbol_index);
}

[[nodiscard]] PHOENIX_API std::vector<symbol*> find_class_members(symbol const& cls);

inline void register_as_opaque(std::string_view class_name) {
return register_as_opaque(find_symbol_by_name(class_name));
}

void register_as_opaque(symbol* sym);

protected:
PHOENIX_INTERNAL script() = default;

Expand Down
16 changes: 16 additions & 0 deletions include/phoenix/vm.hh
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,8 @@ namespace phoenix {
return inst;
}

std::shared_ptr<instance> init_opaque_instance(symbol* sym);

/// \brief Initializes an instance with the given type into \p instance
/// \tparam _instance_t The type of the instance to initialize (ie. C_NPC).
/// \param instance The instance to initialize.
Expand Down Expand Up @@ -962,6 +964,20 @@ namespace phoenix {
}
}

[[nodiscard]] PHOENIX_API std::int32_t
get_int(std::shared_ptr<instance>& context,
std::variant<int32_t, float, symbol*, std::shared_ptr<instance>>& value,
uint16_t index);
[[nodiscard]] PHOENIX_API float
get_float(std::shared_ptr<instance>& context,
std::variant<int32_t, float, symbol*, std::shared_ptr<instance>>& value,
uint16_t index);

PHOENIX_API void set_int(std::shared_ptr<instance>& context, symbol* ref, uint16_t index, std::int32_t value);
PHOENIX_API void set_float(std::shared_ptr<instance>& context, symbol* ref, uint16_t index, float value);
PHOENIX_API void
set_string(std::shared_ptr<instance>& context, symbol* ref, uint16_t index, std::string_view value);

private:
std::array<daedalus_stack_frame, stack_size> _m_stack;
uint16_t _m_stack_ptr {0};
Expand Down
151 changes: 151 additions & 0 deletions source/script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,58 @@ namespace phoenix {
return syms;
}

std::vector<symbol*> script::find_class_members(const symbol& cls) {
std::vector<symbol*> members {};

for (auto& sym : _m_symbols) {
if (!sym.is_member() || sym.parent() != cls.index())
continue;
members.push_back(&sym);
}

return members;
}

void script::register_as_opaque(symbol* sym) {
auto members = find_class_members(*sym);

auto registered_to = &typeid(opaque_instance);
size_t class_size = 0;

for (auto* member : members) {
member->_m_registered_to = registered_to;

switch (member->type()) {
case datatype::void_:
case datatype::float_:
case datatype::integer:
case datatype::class_:
case datatype::function:
case datatype::prototype:
case datatype::instance:
member->_m_member_offset = class_size;
class_size += 4 * member->count();
break;
case datatype::string: {
auto align = alignof(std::string);
auto offset = class_size;

auto remain = offset % align;
auto offset_remain = remain == 0 ? 0 : align - remain;

class_size += offset_remain;
member->_m_member_offset = class_size;

class_size += sizeof(std::string) * member->count();
break;
}
}
}

sym->_m_registered_to = registered_to;
sym->_m_class_size = class_size;
}

symbol* script::add_temporary_strings_symbol() {
symbol sym {};
sym._m_name = "$PHOENIX_FAKE_STRINGS";
Expand Down Expand Up @@ -345,6 +397,11 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
return reinterpret_cast<transient_instance&>(*context).get_string(*this, index);
}

return *get_member_ptr<std::string>(index, context);
} else {
return std::get<std::unique_ptr<std::string[]>>(_m_value)[index];
Expand All @@ -363,6 +420,11 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
return reinterpret_cast<transient_instance&>(*context).get_float(*this, index);
}

return *get_member_ptr<float>(index, context);
} else {
return std::get<std::unique_ptr<float[]>>(_m_value)[index];
Expand All @@ -381,6 +443,11 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
return reinterpret_cast<transient_instance&>(*context).get_int(*this, index);
}

return *get_member_ptr<std::int32_t>(index, context);
} else {
return std::get<std::unique_ptr<std::int32_t[]>>(_m_value)[index];
Expand All @@ -399,6 +466,12 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
reinterpret_cast<transient_instance&>(*context).set_string(*this, index, value);
return;
}

*get_member_ptr<std::string>(index, context) = value;
} else {
std::get<std::unique_ptr<std::string[]>>(_m_value).get()[index] = value;
Expand All @@ -417,6 +490,12 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
reinterpret_cast<transient_instance&>(*context).set_float(*this, index, value);
return;
}

*get_member_ptr<float>(index, context) = value;
} else {
std::get<std::unique_ptr<float[]>>(_m_value)[index] = value;
Expand All @@ -435,6 +514,12 @@ namespace phoenix {
if (context == nullptr) {
throw no_context(this);
}

if (context->symbol_index() == unset && context->_m_type == &typeid(transient_instance)) {
reinterpret_cast<transient_instance&>(*context).set_int(*this, index, value);
return;
}

*get_member_ptr<std::int32_t>(index, context) = value;
} else {
std::get<std::unique_ptr<std::int32_t[]>>(_m_value)[index] = value;
Expand Down Expand Up @@ -463,4 +548,70 @@ namespace phoenix {
else
_m_flags &= ~symbol_flag::access_trap;
}

opaque_instance::opaque_instance(const symbol& sym, const std::vector<symbol*>& members) {
size_t str_count = 0;
for (auto* member : members) {
if (member->type() != datatype::string)
continue;
str_count += member->count();
}

_m_storage.reset(new uint8_t[sym.class_size()]());
_m_strings.resize(str_count, nullptr);

str_count = 0;
for (auto* member : members) {
unsigned offset = member->offset_as_member();

for (auto i = 0U; i < member->count(); ++i) {
switch (member->type()) {
case datatype::float_:
this->construct_at<float>(offset, 0);
offset += 4;
break;
case datatype::integer:
this->construct_at<int>(offset, 0);
offset += 4;
break;
case datatype::string:
_m_strings[str_count] = this->construct_at<std::string>(offset, "");
str_count++;
offset += sizeof(std::string);
break;
case datatype::function:
this->construct_at<int>(offset, 0);
offset += 4;
break;
case datatype::class_:
case datatype::prototype:
case datatype::instance:
case datatype::void_:
this->construct_at<int>(offset);
offset += 4;
break;
}
}
}
}

opaque_instance::~opaque_instance() {
for (auto& i : _m_strings)
i->std::string::~string();
}

template <typename T, typename... Args>
T* opaque_instance::construct_at(size_t offset, Args&&... args) {
auto align = alignof(T);
auto remain = offset % align;
auto real_offset = remain == 0 ? offset : offset + (align - remain);
return new (static_cast<void*>(&_m_storage[real_offset])) T(std::forward<Args>(args)...);
}

transient_instance::transient_instance() {
_m_type = &typeid(transient_instance);
}

transient_instance::~transient_instance() {}

} // namespace phoenix
Loading

0 comments on commit a348a38

Please sign in to comment.