.
This commit is contained in:
@@ -72,7 +72,8 @@ target_compile_options(lib${PROJECT_NAME} PRIVATE ${warnings})
|
||||
# tests
|
||||
#
|
||||
|
||||
add_executable(${PROJECT_NAME}-bytecode-test src/bytecode/tests.cc)
|
||||
add_executable(${PROJECT_NAME}-bytecode-test src/bytecode/tests.cc
|
||||
common/overloaded.hh)
|
||||
target_link_libraries(${PROJECT_NAME}-bytecode-test lib${PROJECT_NAME} gtest_main)
|
||||
add_test(NAME tyche_bytecode_test COMMAND ${PROJECT_NAME}-bytecode-test)
|
||||
|
||||
|
||||
@@ -83,9 +83,9 @@ The bytecode file is composed of the following sections:
|
||||
[0:3]: Magic
|
||||
[4]: VM format
|
||||
* [0x1] Index: pointers to each one of the sections, up to 8
|
||||
Each pointer: 4 bits
|
||||
Each pointer: 4 bytes
|
||||
* [0x2] Constants: all constants (such as strings) used in the code
|
||||
* Table of 4-bit constant indexes with pointer to constant
|
||||
* Table of 4-byte constant indexes with pointer to constant
|
||||
* Raw constant data
|
||||
* [0x3] Functions: Pointer to functions within the code
|
||||
[0:3]: function pointer
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
namespace tyche {
|
||||
|
||||
void ByteArray::add_byte(uint32_t addr, uint8_t byte)
|
||||
void ByteArray::set_byte(uint32_t addr, uint8_t byte)
|
||||
{
|
||||
try {
|
||||
data_.at(addr) = byte;
|
||||
@@ -14,39 +14,39 @@ void ByteArray::add_byte(uint32_t addr, uint8_t byte)
|
||||
}
|
||||
}
|
||||
|
||||
void ByteArray::add_int(uint32_t addr, int32_t value)
|
||||
void ByteArray::set_int(uint32_t addr, int32_t value)
|
||||
{
|
||||
uint32_t zz = ((uint32_t)(value << 1)) ^ ((uint32_t)(value >> 31));
|
||||
while (zz > 0x7F) {
|
||||
add_byte(addr++, (zz & 0x7F) | 0x80);
|
||||
set_byte(addr++, (zz & 0x7F) | 0x80);
|
||||
zz >>= 7;
|
||||
}
|
||||
add_byte(addr, zz & 0x7F);
|
||||
set_byte(addr, zz & 0x7F);
|
||||
}
|
||||
|
||||
void ByteArray::add_uint32(uint32_t addr, uint32_t value)
|
||||
void ByteArray::set_uint32(uint32_t addr, uint32_t value)
|
||||
{
|
||||
add_byte(addr, (uint8_t)(value));
|
||||
add_byte(addr+1, (uint8_t)(value >> 8));
|
||||
add_byte(addr+2, (uint8_t)(value >> 16));
|
||||
add_byte(addr+3, (uint8_t)(value >> 24));
|
||||
set_byte(addr, (uint8_t) (value));
|
||||
set_byte(addr+1, (uint8_t) (value >> 8));
|
||||
set_byte(addr+2, (uint8_t) (value >> 16));
|
||||
set_byte(addr+3, (uint8_t) (value >> 24));
|
||||
}
|
||||
|
||||
void ByteArray::add_float(uint32_t addr, float value)
|
||||
void ByteArray::set_float(uint32_t addr, float value)
|
||||
{
|
||||
uint32_t bits;
|
||||
std::memcpy(&bits, &value, 4);
|
||||
add_byte(addr, (uint8_t)(bits));
|
||||
add_byte(addr+1, (uint8_t)(bits >> 8));
|
||||
add_byte(addr+2, (uint8_t)(bits >> 16));
|
||||
add_byte(addr+3, (uint8_t)(bits >> 24));
|
||||
set_byte(addr, (uint8_t) (bits));
|
||||
set_byte(addr+1, (uint8_t) (bits >> 8));
|
||||
set_byte(addr+2, (uint8_t) (bits >> 16));
|
||||
set_byte(addr+3, (uint8_t) (bits >> 24));
|
||||
}
|
||||
|
||||
void ByteArray::add_string(uint32_t addr, std::string const& str)
|
||||
void ByteArray::set_string(uint32_t addr, std::string const& str)
|
||||
{
|
||||
for (uint8_t c: str)
|
||||
add_byte(addr++, c);
|
||||
add_byte(addr, 0);
|
||||
set_byte(addr++, c);
|
||||
set_byte(addr, 0);
|
||||
}
|
||||
|
||||
uint8_t ByteArray::get_byte(uint32_t addr) const
|
||||
@@ -97,4 +97,9 @@ std::pair<std::string, size_t> ByteArray::get_string(uint32_t addr) const
|
||||
return { data, data.size() + 1 };
|
||||
}
|
||||
|
||||
void ByteArray::append_bytearray(ByteArray const& bytearray)
|
||||
{
|
||||
data_.insert(data_.end(), bytearray.data().begin(), bytearray.data().end());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,17 +13,18 @@ public:
|
||||
ByteArray() = default;
|
||||
explicit ByteArray(std::vector<uint8_t> data) : data_(std::move(data)) {}
|
||||
|
||||
void add_byte(uint32_t addr, uint8_t byte);
|
||||
void add_uint32(uint32_t addr, uint32_t value);
|
||||
void add_int(uint32_t addr, int32_t value);
|
||||
void add_float(uint32_t addr, float value);
|
||||
void add_string(uint32_t addr, std::string const& str);
|
||||
void set_byte(uint32_t addr, uint8_t byte);
|
||||
void set_uint32(uint32_t addr, uint32_t value);
|
||||
void set_int(uint32_t addr, int32_t value);
|
||||
void set_float(uint32_t addr, float value);
|
||||
void set_string(uint32_t addr, std::string const& str);
|
||||
|
||||
void append_byte(uint32_t addr, uint8_t byte) { add_byte(data_.size(), byte); }
|
||||
void append_uint32(uint32_t addr, uint32_t value) { add_uint32(data_.size(), value); }
|
||||
void append_int(uint32_t addr, int32_t value) { add_int(data_.size(), value); }
|
||||
void append_float(uint32_t addr, float value) { add_float(data_.size(), value); }
|
||||
void append_string(uint32_t addr, std::string const& str) { add_string(data_.size(), str); }
|
||||
void append_byte(uint8_t byte) { set_byte(data_.size(), byte); }
|
||||
void append_uint32(uint32_t value) { set_uint32(data_.size(), value); }
|
||||
void append_int(int32_t value) { set_int(data_.size(), value); }
|
||||
void append_float(float value) { set_float(data_.size(), value); }
|
||||
void append_string(std::string const& str) { set_string(data_.size(), str); }
|
||||
void append_bytearray(ByteArray const& bytearray);
|
||||
|
||||
[[nodiscard]] uint8_t get_byte(uint32_t addr) const;
|
||||
[[nodiscard]] uint32_t get_uint32(uint32_t addr) const;
|
||||
@@ -32,6 +33,7 @@ public:
|
||||
[[nodiscard]] std::pair<std::string, size_t> get_string(uint32_t addr) const;
|
||||
|
||||
[[nodiscard]] std::vector<uint8_t> const& data() const { return data_; }
|
||||
[[nodiscard]] size_t size() const { return data_.size(); }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> data_;
|
||||
|
||||
@@ -1,23 +1,44 @@
|
||||
#include "bytecode.hh"
|
||||
#include "../common/overloaded.hh"
|
||||
|
||||
namespace tyche {
|
||||
|
||||
Bytecode::Bytecode(BytecodePrototype const& bp)
|
||||
{
|
||||
// header
|
||||
byte_array_.add_uint32(0, MAGIC);
|
||||
byte_array_.add_byte(4, VERSION);
|
||||
|
||||
// constants
|
||||
std::vector<uint32_t> constant_indexes;
|
||||
std::vector<uint8_t> constant_array;
|
||||
std::vector<uint32_t> constant_table;
|
||||
ByteArray constant_array;
|
||||
uint32_t idx = 0;
|
||||
for (auto const& constant: bp.constants) {
|
||||
|
||||
constant_table.emplace_back(idx);
|
||||
std::visit(overloaded {
|
||||
[&](int32_t i) { constant_array.append_int(i); },
|
||||
[&](float f) { constant_array.append_float(f); },
|
||||
[&](std::string const& s) { constant_array.append_string(s); },
|
||||
}, constant);
|
||||
idx = constant_array.size();
|
||||
}
|
||||
|
||||
// constants table
|
||||
|
||||
// function table
|
||||
|
||||
//
|
||||
// build binary
|
||||
//
|
||||
|
||||
// header
|
||||
byte_array_.set_uint32(0, MAGIC);
|
||||
byte_array_.set_byte(4, VERSION);
|
||||
|
||||
// index - other entries created later
|
||||
byte_array_.set_uint32(HEADER_SZ, HEADER_SZ + INDEX_SZ);
|
||||
|
||||
// constants
|
||||
idx = HEADER_SZ + INDEX_SZ;
|
||||
for (auto const& const_idx: constant_table) {
|
||||
byte_array_.set_uint32(idx, const_idx);
|
||||
idx += 4;
|
||||
}
|
||||
byte_array_.append_bytearray(constant_array);
|
||||
}
|
||||
|
||||
uint32_t Bytecode::n_constants() const
|
||||
|
||||
@@ -31,6 +31,8 @@ private:
|
||||
ByteArray byte_array_;
|
||||
static constexpr uint8_t VERSION = 1;
|
||||
static constexpr uint32_t MAGIC = 0x74b3c138;
|
||||
static constexpr uint32_t HEADER_SZ = 16,
|
||||
INDEX_SZ = 8 * 4;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ TEST(ByteArray, ByteArray)
|
||||
|
||||
#define TESTX(a, ...) test([](ByteArray& ba) { a; }, std::vector<uint8_t>({ __VA_ARGS__ }));
|
||||
|
||||
TESTX(ba.add_byte(1, 0xab), 0x00, 0xab)
|
||||
TESTX(ba.set_byte(1, 0xab), 0x00, 0xab)
|
||||
|
||||
ByteArray ba;
|
||||
ba.add_byte(1, 0xab); ASSERT_EQ(ba.get_byte(1), 0xab);
|
||||
ba.set_byte(1, 0xab); ASSERT_EQ(ba.get_byte(1), 0xab);
|
||||
|
||||
ba.add_int(1, 12); ASSERT_EQ(ba.get_int(1), std::make_pair(12, 1));
|
||||
ba.add_int(1, -12); ASSERT_EQ(ba.get_int(1), std::make_pair(-12, 1));
|
||||
|
||||
8
src/common/overloaded.hh
Normal file
8
src/common/overloaded.hh
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef TYCHE_OVERLOADED_HH
|
||||
#define TYCHE_OVERLOADED_HH
|
||||
|
||||
// used by std::visitor
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
|
||||
#endif //TYCHE_OVERLOADED_HH
|
||||
Reference in New Issue
Block a user