2021-03-22 21:26:05 +01:00
|
|
|
#include "cs_bcode.hh"
|
2021-03-23 01:45:35 +01:00
|
|
|
#include "cs_state.hh"
|
2021-05-02 22:44:38 +02:00
|
|
|
#include "cs_vm.hh"
|
2021-03-22 21:26:05 +01:00
|
|
|
|
2021-03-23 23:32:25 +01:00
|
|
|
namespace cubescript {
|
2021-03-22 21:26:05 +01:00
|
|
|
|
|
|
|
/* public API impls */
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref::bcode_ref(bcode *v): p_code(v) {
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_addref(v->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
}
|
2021-03-23 23:29:32 +01:00
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref::bcode_ref(bcode_ref const &v):
|
2021-03-22 21:26:05 +01:00
|
|
|
p_code(v.p_code)
|
|
|
|
{
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_addref(p_code->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
}
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref::~bcode_ref() {
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_unref(p_code->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
}
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref &bcode_ref::operator=(
|
|
|
|
bcode_ref const &v
|
2021-03-22 21:26:05 +01:00
|
|
|
) {
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_unref(p_code->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
p_code = v.p_code;
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_addref(p_code->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref &bcode_ref::operator=(bcode_ref &&v) {
|
2021-05-05 03:16:32 +02:00
|
|
|
bcode_unref(p_code->raw());
|
2021-03-22 21:26:05 +01:00
|
|
|
p_code = v.p_code;
|
|
|
|
v.p_code = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2021-04-01 05:05:43 +02:00
|
|
|
LIBCUBESCRIPT_EXPORT bool bcode_ref::empty() const {
|
|
|
|
if (!p_code) {
|
|
|
|
return true;
|
|
|
|
}
|
2021-05-05 03:16:32 +02:00
|
|
|
return (*p_code->raw() & BC_INST_OP_MASK) == BC_INST_EXIT;
|
2021-04-01 05:05:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LIBCUBESCRIPT_EXPORT bcode_ref::operator bool() const {
|
|
|
|
return p_code != nullptr;
|
|
|
|
}
|
|
|
|
|
2021-05-02 22:44:38 +02:00
|
|
|
LIBCUBESCRIPT_EXPORT any_value bcode_ref::call(state &cs) const {
|
|
|
|
any_value ret{};
|
2021-05-05 03:16:32 +02:00
|
|
|
vm_exec(state_p{cs}.ts(), p_code->raw(), ret);
|
2021-05-02 22:44:38 +02:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
LIBCUBESCRIPT_EXPORT loop_state bcode_ref::call_loop(
|
|
|
|
state &cs, any_value &ret
|
|
|
|
) const {
|
|
|
|
auto &ts = state_p{cs}.ts();
|
|
|
|
++ts.loop_level;
|
|
|
|
try {
|
|
|
|
ret = call(cs);
|
|
|
|
} catch (break_exception) {
|
|
|
|
--ts.loop_level;
|
|
|
|
return loop_state::BREAK;
|
|
|
|
} catch (continue_exception) {
|
|
|
|
--ts.loop_level;
|
|
|
|
return loop_state::CONTINUE;
|
|
|
|
} catch (...) {
|
|
|
|
--ts.loop_level;
|
|
|
|
throw;
|
|
|
|
}
|
|
|
|
return loop_state::NORMAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
LIBCUBESCRIPT_EXPORT loop_state bcode_ref::call_loop(state &cs) const {
|
|
|
|
any_value ret{};
|
|
|
|
return call_loop(cs, ret);
|
|
|
|
}
|
|
|
|
|
2021-03-22 21:26:05 +01:00
|
|
|
/* private funcs */
|
|
|
|
|
|
|
|
struct bcode_hdr {
|
2021-03-23 23:29:32 +01:00
|
|
|
internal_state *cs; /* needed to construct the allocator */
|
2021-03-22 21:26:05 +01:00
|
|
|
std::size_t asize; /* alloc size of the bytecode block */
|
2021-03-23 23:29:32 +01:00
|
|
|
bcode bc; /* BC_INST_START + refcount */
|
2021-03-22 21:26:05 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/* returned address is the 'init' member of the header */
|
2021-03-25 01:52:03 +01:00
|
|
|
std::uint32_t *bcode_alloc(internal_state *cs, std::size_t sz) {
|
|
|
|
auto a = std_allocator<std::uint32_t>{cs};
|
2021-03-22 21:26:05 +01:00
|
|
|
std::size_t hdrs = sizeof(bcode_hdr) / sizeof(std::uint32_t);
|
|
|
|
auto p = a.allocate(sz + hdrs - 1);
|
2021-05-14 22:10:16 +02:00
|
|
|
bcode_hdr *hdr;
|
|
|
|
std::memcpy(&hdr, &p, sizeof(hdr));
|
2021-03-25 01:52:03 +01:00
|
|
|
hdr->cs = cs;
|
2021-03-22 21:26:05 +01:00
|
|
|
hdr->asize = sz + hdrs - 1;
|
|
|
|
return p + hdrs - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* bc's address must be the 'init' member of the header */
|
|
|
|
static inline void bcode_free(std::uint32_t *bc) {
|
|
|
|
auto *rp = bc + 1 - (sizeof(bcode_hdr) / sizeof(std::uint32_t));
|
2021-05-14 22:10:16 +02:00
|
|
|
bcode_hdr *hdr;
|
|
|
|
std::memcpy(&hdr, &rp, sizeof(hdr));
|
2021-03-23 23:29:32 +01:00
|
|
|
std_allocator<std::uint32_t>{hdr->cs}.deallocate(rp, hdr->asize);
|
2021-03-22 21:26:05 +01:00
|
|
|
}
|
|
|
|
|
2021-04-01 05:18:20 +02:00
|
|
|
static inline void bcode_incr(std::uint32_t *bc) {
|
2021-03-22 21:26:05 +01:00
|
|
|
*bc += 0x100;
|
|
|
|
}
|
|
|
|
|
2021-04-01 05:18:20 +02:00
|
|
|
static inline void bcode_decr(std::uint32_t *bc) {
|
2021-03-22 21:26:05 +01:00
|
|
|
*bc -= 0x100;
|
|
|
|
if (std::int32_t(*bc) < 0x100) {
|
|
|
|
bcode_free(bc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
void bcode_addref(std::uint32_t *code) {
|
2021-03-22 21:26:05 +01:00
|
|
|
if (!code) {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-23 23:29:32 +01:00
|
|
|
if ((*code & BC_INST_OP_MASK) == BC_INST_START) {
|
2021-03-22 21:26:05 +01:00
|
|
|
bcode_incr(code);
|
|
|
|
return;
|
|
|
|
}
|
2021-03-23 23:29:32 +01:00
|
|
|
switch (code[-1]&BC_INST_OP_MASK) {
|
|
|
|
case BC_INST_START:
|
2021-03-22 21:26:05 +01:00
|
|
|
bcode_incr(&code[-1]);
|
|
|
|
break;
|
2021-03-23 23:29:32 +01:00
|
|
|
case BC_INST_OFFSET:
|
2021-03-22 21:26:05 +01:00
|
|
|
code -= std::ptrdiff_t(code[-1] >> 8);
|
|
|
|
bcode_incr(code);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bcode_unref(std::uint32_t *code) {
|
|
|
|
if (!code) {
|
|
|
|
return;
|
|
|
|
}
|
2021-03-23 23:29:32 +01:00
|
|
|
if ((*code & BC_INST_OP_MASK) == BC_INST_START) {
|
2021-03-22 21:26:05 +01:00
|
|
|
bcode_decr(code);
|
|
|
|
return;
|
|
|
|
}
|
2021-03-23 23:29:32 +01:00
|
|
|
switch (code[-1]&BC_INST_OP_MASK) {
|
|
|
|
case BC_INST_START:
|
2021-03-22 21:26:05 +01:00
|
|
|
bcode_decr(&code[-1]);
|
|
|
|
break;
|
2021-03-23 23:29:32 +01:00
|
|
|
case BC_INST_OFFSET:
|
2021-03-22 21:26:05 +01:00
|
|
|
code -= std::ptrdiff_t(code[-1] >> 8);
|
|
|
|
bcode_decr(code);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-22 22:01:49 +01:00
|
|
|
/* empty fallbacks */
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
static std::uint32_t emptyrets[VAL_ANY] = {
|
|
|
|
BC_RET_NULL, BC_RET_INT, BC_RET_FLOAT, BC_RET_STRING
|
2021-03-22 22:01:49 +01:00
|
|
|
};
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
empty_block *bcode_init_empty(internal_state *cs) {
|
|
|
|
auto a = std_allocator<empty_block>{cs};
|
|
|
|
auto *p = a.allocate(VAL_ANY);
|
|
|
|
for (std::size_t i = 0; i < VAL_ANY; ++i) {
|
|
|
|
p[i].init.init = BC_INST_START + 0x100;
|
|
|
|
p[i].code = BC_INST_EXIT | emptyrets[i];
|
2021-03-22 22:01:49 +01:00
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
void bcode_free_empty(internal_state *cs, empty_block *empty) {
|
|
|
|
std_allocator<empty_block>{cs}.deallocate(empty, VAL_ANY);
|
2021-03-31 01:35:02 +02:00
|
|
|
}
|
2021-03-22 22:01:49 +01:00
|
|
|
|
2021-03-23 23:29:32 +01:00
|
|
|
bcode *bcode_get_empty(empty_block *empty, std::size_t val) {
|
2021-05-12 03:55:20 +02:00
|
|
|
return &empty[val >> BC_INST_RET].init + 1;
|
2021-03-22 22:01:49 +01:00
|
|
|
}
|
|
|
|
|
2021-03-23 23:32:25 +01:00
|
|
|
} /* namespace cubescript */
|