diff --git a/.idea/ctestState.xml b/.idea/ctestState.xml index 1bbf61b..156f501 100644 --- a/.idea/ctestState.xml +++ b/.idea/ctestState.xml @@ -2,9 +2,10 @@ - - - + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 1f00baf..3e1aaa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,32 +60,34 @@ FetchContent_MakeAvailable(googletest) add_library(lib${PROJECT_NAME} SHARED src/common/overloaded.hh - src/common/bytearray.hh - src/common/bytearray.cc - src/bytecode/bytecode.cc - src/bytecode/bytecode.hh - src/bytecode/bytecodeprototype.hh - src/bytecode/constant.hh - src/bytecode/bc_exceptions.hh - src/assembler/lexer.cc - src/assembler/lexer.hh - src/assembler/assembler.cc - src/assembler/assembler.hh - src/assembler/as_exceptions.hh - src/instructions/instruction.hh - src/instructions/instruction.cc - src/vm/code.cc - src/vm/code.hh - src/vm/value.cc - src/vm/value.hh - src/vm/stack.cc - src/vm/stack.hh - src/vm/vm_exceptions.hh - src/vm/vm.cc - src/vm/vm.hh - src/vm/expr.cc - src/vm/expr.hh - src/vm/location.hh + src/bytearray/bytearray.hh + src/bytearray/bytearray.cc + src/bytearray/bytearraybuilder.hh + src/bytearray/bytearraybuilder.cc + #src/bytecode/bytecode.cc + #src/bytecode/bytecode.hh + #src/bytecode/bytecodeprototype.hh + #src/bytecode/constant.hh + #src/bytecode/bc_exceptions.hh + #src/assembler/lexer.cc + #src/assembler/lexer.hh + #src/assembler/assembler.cc + #src/assembler/assembler.hh + #src/assembler/as_exceptions.hh + #src/instructions/instruction.hh + #src/instructions/instruction.cc + #src/vm/code.cc + #src/vm/code.hh + #src/vm/value.cc + #src/vm/value.hh + #src/vm/stack.cc + #src/vm/stack.hh + #src/vm/vm_exceptions.hh + #src/vm/vm.cc + #src/vm/vm.hh + #src/vm/expr.cc + #src/vm/expr.hh + #src/vm/location.hh ) target_compile_options(lib${PROJECT_NAME} PRIVATE ${warnings}) @@ -96,6 +98,10 @@ target_compile_options(lib${PROJECT_NAME} PRIVATE ${warnings}) enable_testing() +add_executable(${PROJECT_NAME}-bytearray-test src/bytearray/tests.cc) +target_link_libraries(${PROJECT_NAME}-bytearray-test lib${PROJECT_NAME} gtest_main) +add_test(NAME tyche_bytearray_test COMMAND ${PROJECT_NAME}-bytearray-test) + add_executable(${PROJECT_NAME}-bytecode-test src/bytecode/tests.cc) target_link_libraries(${PROJECT_NAME}-bytecode-test lib${PROJECT_NAME} gtest_main) add_test(NAME tyche_bytecode_test COMMAND ${PROJECT_NAME}-bytecode-test) @@ -104,7 +110,9 @@ add_executable(${PROJECT_NAME}-vm-test src/vm/tests.cc) target_link_libraries(${PROJECT_NAME}-vm-test lib${PROJECT_NAME} gtest_main) add_test(NAME tyche_vm_test COMMAND ${PROJECT_NAME}-vm-test) -add_executable(${PROJECT_NAME}-as-test src/assembler/tests.cc) +add_executable(${PROJECT_NAME}-as-test src/assembler/tests.cc + src/bytearray/bytearraybuilder.cc + src/bytearray/bytearraybuilder.hh) target_link_libraries(${PROJECT_NAME}-as-test lib${PROJECT_NAME} gtest_main) add_test(NAME tyche_as_test COMMAND ${PROJECT_NAME}-as-test) diff --git a/src/assembler/assembler.cc b/src/assembler/assembler.cc index f2df9a1..c2c7696 100644 --- a/src/assembler/assembler.cc +++ b/src/assembler/assembler.cc @@ -10,7 +10,7 @@ using namespace std::string_literals; namespace tyche::as { -ByteArray Assembler::assemble() +StaticByteArray Assembler::assemble() { bc::BytecodePrototype bp; diff --git a/src/assembler/assembler.hh b/src/assembler/assembler.hh index eea7acf..f0ee57f 100644 --- a/src/assembler/assembler.hh +++ b/src/assembler/assembler.hh @@ -5,7 +5,7 @@ #include #include "lexer.hh" -#include "../common/bytearray.hh" +#include "../bytearray/bytearray.hh" #include "../bytecode/bytecodeprototype.hh" namespace tyche::as { @@ -14,7 +14,7 @@ class Assembler { public: explicit Assembler(std::string source) : lexer_(std::move(source) + "\n") {} - [[nodiscard]] ByteArray assemble(); + [[nodiscard]] StaticByteArray assemble(); private: Lexer lexer_; diff --git a/src/assembler/tests.cc b/src/assembler/tests.cc index 328c731..fc79443 100644 --- a/src/assembler/tests.cc +++ b/src/assembler/tests.cc @@ -47,7 +47,7 @@ TEST(Assember, Assembler) bp.functions.at(1).code.append_byte((uint8_t) Instruction::PushInt16); bp.functions.at(1).code.append_int16(5000); bp.functions.at(1).code.append_byte((uint8_t) Instruction::Return); - ByteArray expected = Bytecode::generate(bp); + StaticByteArray expected = Bytecode::generate(bp); std::string src = R"( .const @@ -64,7 +64,7 @@ TEST(Assember, Assembler) ret )"; - ByteArray actual = Assembler(src).assemble(); + StaticByteArray actual = Assembler(src).assemble(); ASSERT_EQ(expected, actual); } diff --git a/src/bytearray/bytearray.cc b/src/bytearray/bytearray.cc new file mode 100644 index 0000000..a261e70 --- /dev/null +++ b/src/bytearray/bytearray.cc @@ -0,0 +1,81 @@ +#include "bytearray.hh" + +#include +#include + +namespace tyche { + +uint8_t StaticByteArray::get_byte(uint32_t addr) const +{ + return data_.at(addr); +} + +uint16_t StaticByteArray::get_uint16(uint32_t addr) const +{ + return (uint32_t) get_byte(addr) + | (uint32_t) get_byte(addr+1) << 8; +} + +uint32_t StaticByteArray::get_uint32(uint32_t addr) const +{ + return (uint32_t) get_byte(addr) + | (uint32_t) get_byte(addr+1) << 8 + | (uint32_t) get_byte(addr+2) << 16 + | (uint32_t) get_byte(addr+3) << 24; +} + +int8_t StaticByteArray::get_int8(uint32_t addr) const +{ + return std::bit_cast(get_byte(addr)); +} + +int16_t StaticByteArray::get_int16(uint32_t addr) const +{ + return (uint16_t) get_byte(addr) + | (uint16_t) get_byte(addr+1) << 8; +} + +int32_t StaticByteArray::get_int32(uint32_t addr) const +{ + return std::bit_cast((uint32_t) get_byte(addr) + | (uint32_t) get_byte(addr+1) << 8 + | (uint32_t) get_byte(addr+2) << 16 + | (uint32_t) get_byte(addr+3) << 24); +} + +float StaticByteArray::get_float(uint32_t addr) const +{ + uint32_t bits = (uint32_t) get_byte(addr) + | (uint32_t) get_byte(addr+1) << 8 + | (uint32_t) get_byte(addr+2) << 16 + | (uint32_t) get_byte(addr+3) << 24; + float value; + std::memcpy(&value, &bits, 4); + return value; +} + +std::pair StaticByteArray::get_string_ptr(uint32_t addr) const +{ + return { (const char *) &data_.at(addr), strlen((const char *) &data_.at(addr)) + 1 }; +} + +std::string StaticByteArray::hexdump() const +{ + auto to_hex = [](uint32_t value, size_t n_chars) -> std::string { + char buf[15]; + snprintf(buf, sizeof buf, "%0*X", (int) n_chars, value); + return { buf }; + }; + + std::string out; + for (size_t i = 0; i < data_.size(); ++i) { + if (i % 16 == 0) + out += to_hex(i, 4) + " | "; + out += to_hex(data_.at(i), 2) + " "; + if (i % 16 == 15) + out += "\n"; + } + return out + "\n"; +} + +} \ No newline at end of file diff --git a/src/bytearray/bytearray.hh b/src/bytearray/bytearray.hh new file mode 100644 index 0000000..3aee5de --- /dev/null +++ b/src/bytearray/bytearray.hh @@ -0,0 +1,44 @@ +#ifndef TYCHE_BYTEARRAY_HH +#define TYCHE_BYTEARRAY_HH + +#include +#include +#include +#include + +namespace tyche { + +class StaticByteArray { +public: + explicit StaticByteArray(std::vector const& data) : data_(data) {} + + explicit StaticByteArray(StaticByteArray const& ba) : data_(ba.data()) {} + + // not assignable or moveable + StaticByteArray(StaticByteArray&&) = delete; + StaticByteArray& operator=(StaticByteArray const&) = delete; + StaticByteArray& operator=(StaticByteArray&&) = delete; + + [[nodiscard]] uint8_t get_byte(uint32_t addr) const; + [[nodiscard]] uint16_t get_uint16(uint32_t addr) const; + [[nodiscard]] uint32_t get_uint32(uint32_t addr) const; + [[nodiscard]] int8_t get_int8(uint32_t addr) const; + [[nodiscard]] int16_t get_int16(uint32_t addr) const; + [[nodiscard]] int32_t get_int32(uint32_t addr) const; + [[nodiscard]] float get_float(uint32_t addr) const; + [[nodiscard]] std::pair get_string_ptr(uint32_t addr) const; + + [[nodiscard]] std::vector const& data() const { return data_; } + [[nodiscard]] size_t size() const { return data_.size(); } + + [[nodiscard]] std::string hexdump() const; + + friend bool operator==(StaticByteArray const& lhs, StaticByteArray const& rhs) { return lhs.data_ == rhs.data_; } + +private: + const std::vector data_ {}; +}; + +} + +#endif //TYCHE_BYTEARRAY_HH diff --git a/src/bytearray/bytearraybuilder.cc b/src/bytearray/bytearraybuilder.cc new file mode 100644 index 0000000..a2bf660 --- /dev/null +++ b/src/bytearray/bytearraybuilder.cc @@ -0,0 +1,88 @@ +#include "bytearraybuilder.hh" + +namespace tyche { + +ByteArrayBuilder& ByteArrayBuilder::set_byte(uint32_t addr, uint8_t byte) +{ + if (data_.size() < (addr + 1)) + data_.resize(addr + 1, 0); + data_.at(addr) = byte; + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_int8(uint32_t addr, int8_t value) +{ + set_byte(addr, (uint8_t) value); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_int16(uint32_t addr, int16_t value) +{ + set_byte(addr, (uint8_t) (value)); + set_byte(addr+1, (uint8_t) (value >> 8)); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_int32(uint32_t addr, int32_t value) +{ + 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)); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_uint16(uint32_t addr, uint16_t value) +{ + set_byte(addr, (uint8_t) (value)); + set_byte(addr+1, (uint8_t) (value >> 8)); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_uint32(uint32_t addr, uint32_t value) +{ + 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)); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_float(uint32_t addr, float value) +{ + uint32_t bits; + std::memcpy(&bits, &value, 4); + 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)); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_string(uint32_t addr, std::string const& str) +{ + for (uint8_t c: str) + set_byte(addr++, c); + set_byte(addr, 0); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::set_bytearray(uint32_t addr, ByteArrayBuilder const& bytearray) +{ + for (uint8_t byte: bytearray.data_) + set_byte(addr++, byte); + return *this; +} + +ByteArrayBuilder& ByteArrayBuilder::append_bytearray(ByteArrayBuilder const& bytearray) +{ + data_.insert(data_.end(), bytearray.data_.begin(), bytearray.data_.end()); + return *this; +} + +StaticByteArray ByteArrayBuilder::build() const +{ + return StaticByteArray(data_); +} + +} diff --git a/src/bytearray/bytearraybuilder.hh b/src/bytearray/bytearraybuilder.hh new file mode 100644 index 0000000..b05f4ba --- /dev/null +++ b/src/bytearray/bytearraybuilder.hh @@ -0,0 +1,45 @@ +#ifndef TYCHE_BYTEARRAYBUILDER_HH +#define TYCHE_BYTEARRAYBUILDER_HH + +#include +#include +#include + +#include "bytearray.hh" + +namespace tyche { + +class ByteArrayBuilder { +public: + ByteArrayBuilder& set_byte(uint32_t addr, uint8_t byte); + ByteArrayBuilder& set_uint16(uint32_t addr, uint16_t value); + ByteArrayBuilder& set_uint32(uint32_t addr, uint32_t value); + ByteArrayBuilder& set_int8(uint32_t addr, int8_t value); + ByteArrayBuilder& set_int16(uint32_t addr, int16_t value); + ByteArrayBuilder& set_int32(uint32_t addr, int32_t value); + ByteArrayBuilder& set_float(uint32_t addr, float value); + ByteArrayBuilder& set_string(uint32_t addr, std::string const& str); + ByteArrayBuilder& set_bytearray(uint32_t addr, ByteArrayBuilder const& bytearray); + + ByteArrayBuilder& append_byte(uint8_t byte) { set_byte(data_.size(), byte); return *this; } + ByteArrayBuilder& append_uint16(uint16_t value) { set_uint16(data_.size(), value); return *this; } + ByteArrayBuilder& append_uint32(uint32_t value) { set_uint32(data_.size(), value); return *this; } + ByteArrayBuilder& append_int8(int8_t value) { set_int8(data_.size(), value); return *this; } + ByteArrayBuilder& append_int16(int16_t value) { set_int16(data_.size(), value); return *this; } + ByteArrayBuilder& append_int32(int32_t value) { set_int32(data_.size(), value); return *this; } + ByteArrayBuilder& append_float(float value) { set_float(data_.size(), value); return *this; } + ByteArrayBuilder& append_string(std::string const& str) { set_string(data_.size(), str); return *this; } + ByteArrayBuilder& append_bytearray(ByteArrayBuilder const& bytearray); + + [[nodiscard]] std::vector const& data() const { return data_; } + [[nodiscard]] size_t size() const { return data_.size(); } + + [[nodiscard]] StaticByteArray build() const; + +private: + std::vector data_ {}; +}; + +} + +#endif //TYCHE_BYTEARRAYBUILDER_HH diff --git a/src/bytearray/tests.cc b/src/bytearray/tests.cc new file mode 100644 index 0000000..8ba9bd8 --- /dev/null +++ b/src/bytearray/tests.cc @@ -0,0 +1,51 @@ +#include "gtest/gtest.h" + +#include +#include + +#include "bytearray.hh" +#include "bytearraybuilder.hh" + +using namespace tyche; + +TEST(StaticByteArray, StaticByteArray) +{ + auto test = [](std::function const& f, std::vector const& expected) { + ByteArrayBuilder ba; + f(ba); + ASSERT_EQ(ba.data().size(), expected.size()); + ASSERT_EQ(std::memcmp(ba.data().data(), expected.data(), ba.data().size()), 0); + }; + +#define TESTX(a, ...) test([](ByteArrayBuilder& ba) { a; }, std::vector({ __VA_ARGS__ })); + + TESTX(ba.set_byte(1, 0xab), 0x00, 0xab) + + ByteArrayBuilder ba; + { auto b = ba.set_byte(1, 0xab).build(); ASSERT_EQ(b.get_byte(1), 0xab); } + + { auto b = ba.set_int8(1, 12).build(); ASSERT_EQ(b.get_int8(1), 12); } + { auto b = ba.set_int8(1, -12).build(); ASSERT_EQ(b.get_int8(1), -12); } + { auto b = ba.set_int16(1, 5000).build(); ASSERT_EQ(b.get_int16(1), 5000); } + { auto b = ba.set_int32(1, 5000300).build(); ASSERT_EQ(b.get_int32(1), 5000300); } + { auto b = ba.set_int32(1, -5000300).build(); ASSERT_EQ(b.get_int32(1), -5000300); } + + { auto b = ba.set_float(1, 3.14).build(); ASSERT_FLOAT_EQ(b.get_float(1), 3.14); } + { auto b = ba.set_float(1, -3.14).build(); ASSERT_FLOAT_EQ(b.get_float(1), -3.14); } + { auto b = ba.set_float(1, -5000300.1324).build(); ASSERT_FLOAT_EQ(b.get_float(1), -5000300.1324); } + + { + auto b = ba.set_string(1, "Hello world!").build(); + auto str = b.get_string_ptr(1); + EXPECT_STREQ(str.first, "Hello world!"); + ASSERT_EQ(str.second, 13); + } + +#undef TESTX +} + +int main(int argc, char** argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git a/src/bytecode/bytecode.cc b/src/bytecode/bytecode.cc index b8554d1..fe21a6b 100644 --- a/src/bytecode/bytecode.cc +++ b/src/bytecode/bytecode.cc @@ -5,29 +5,29 @@ namespace tyche::bc { -Bytecode::Bytecode(ByteArray ba) - : byte_array_(std::move(ba)) +Bytecode::Bytecode(StaticByteArray const* ba) + : byte_array_(ba) { // check file size - if (byte_array_.size() < (TOC_START + TOC_SZ)) + if (byte_array_->size() < (TOC_START + TOC_SZ)) throw BytecodeParsingError("Invalid bytecode format (file too short)"); // check magic number and version - if (byte_array_.get_uint32(0) != MAGIC_NUMBER) + if (byte_array_->get_uint32(0) != MAGIC_NUMBER) throw BytecodeParsingError("Invalid bytecode format (magic number not matching)"); - if (byte_array_.get_uint32(4) != BYTECODE_VERSION) + if (byte_array_->get_uint32(4) != BYTECODE_VERSION) throw BytecodeParsingError("Unexpected bytecode format version"); // load cache - cache_.constants_idx_addr = byte_array_.get_uint32(TOC_START); - cache_.n_constants = byte_array_.get_uint16(TOC_START + 4); - cache_.functions_idx_addr = byte_array_.get_uint32(TOC_START + (1 * TOC_RECORD_SZ)); - cache_.n_functions = byte_array_.get_uint16(TOC_START + (1 * TOC_RECORD_SZ) + 4); - cache_.constants_start_addr = byte_array_.get_uint32(TOC_START + (2 * TOC_RECORD_SZ)); - uint32_t code_start = byte_array_.get_uint32(TOC_START + (3 * TOC_RECORD_SZ)); + cache_.constants_idx_addr = byte_array_->get_uint32(TOC_START); + cache_.n_constants = byte_array_->get_uint16(TOC_START + 4); + cache_.functions_idx_addr = byte_array_->get_uint32(TOC_START + (1 * TOC_RECORD_SZ)); + cache_.n_functions = byte_array_->get_uint16(TOC_START + (1 * TOC_RECORD_SZ) + 4); + cache_.constants_start_addr = byte_array_->get_uint32(TOC_START + (2 * TOC_RECORD_SZ)); + uint32_t code_start = byte_array_->get_uint32(TOC_START + (3 * TOC_RECORD_SZ)); for (uint32_t i = 0; i < cache_.n_functions; ++i) { - cache_.function_addr.emplace_back(code_start + byte_array_.get_uint32(cache_.functions_idx_addr + (i * FUNCTION_RECORD_SZ))); - cache_.function_sz.emplace_back(byte_array_.get_uint32(cache_.functions_idx_addr + (i * FUNCTION_RECORD_SZ) + 8)); + cache_.function_addr.emplace_back(code_start + byte_array_->get_uint32(cache_.functions_idx_addr + (i * FUNCTION_RECORD_SZ))); + cache_.function_sz.emplace_back(byte_array_->get_uint32(cache_.functions_idx_addr + (i * FUNCTION_RECORD_SZ) + 8)); } } @@ -43,12 +43,12 @@ uint32_t Bytecode::n_functions() const ConstantValue Bytecode::get_constant(uint32_t idx) const { - uint32_t constant_idx = byte_array_.get_uint32(cache_.constants_idx_addr + (idx * CONST_RECORD_SZ)); - switch ((ConstantType) byte_array_.get_byte(cache_.constants_start_addr + constant_idx)) { + uint32_t constant_idx = byte_array_->get_uint32(cache_.constants_idx_addr + (idx * CONST_RECORD_SZ)); + switch ((ConstantType) byte_array_->get_byte(cache_.constants_start_addr + constant_idx)) { case CONST_TYPE_FLOAT: - return byte_array_.get_float(cache_.constants_start_addr + constant_idx + 1); + return byte_array_->get_float(cache_.constants_start_addr + constant_idx + 1); case CONST_TYPE_STRING: - return byte_array_.get_string_ptr(cache_.constants_start_addr + constant_idx + 1).first; + return byte_array_->get_string_ptr(cache_.constants_start_addr + constant_idx + 1).first; default: throw BytecodeParsingError("Invalid bytecode format (invalid constant type)"); } @@ -58,8 +58,8 @@ Bytecode::FunctionDef Bytecode::get_function_def(uint32_t function_id) const { uint32_t idx = cache_.functions_idx_addr + (function_id * FUNCTION_RECORD_SZ); return { - .n_params = byte_array_.get_uint16(idx + 4), - .locals = byte_array_.get_uint16(idx + 6), + .n_params = byte_array_->get_uint16(idx + 4), + .locals = byte_array_->get_uint16(idx + 6), }; } @@ -70,34 +70,34 @@ uint32_t Bytecode::get_function_sz(uint32_t function_id) const uint8_t Bytecode::get_code_byte(uint32_t function_id, uint32_t idx) const { - return byte_array_.get_byte(cache_.function_addr.at(function_id) + idx); + return byte_array_->get_byte(cache_.function_addr.at(function_id) + idx); } int8_t Bytecode::get_code_int8(uint32_t function_id, uint32_t idx) const { - return byte_array_.get_int8(cache_.function_addr.at(function_id) + idx); + return byte_array_->get_int8(cache_.function_addr.at(function_id) + idx); } int16_t Bytecode::get_code_int16(uint32_t function_id, uint32_t idx) const { - return byte_array_.get_int16(cache_.function_addr.at(function_id) + idx); + return byte_array_->get_int16(cache_.function_addr.at(function_id) + idx); } int32_t Bytecode::get_code_int32(uint32_t function_id, uint32_t idx) const { - return byte_array_.get_int32(cache_.function_addr.at(function_id) + idx); + return byte_array_->get_int32(cache_.function_addr.at(function_id) + idx); } -ByteArray Bytecode::generate(BytecodePrototype const& bp) +StaticByteArray Bytecode::generate(BytecodePrototype const& bp) { // header section - ByteArray header; + ByteArrayBuilder header; header.set_uint32(0, MAGIC_NUMBER); header.set_byte(4, BYTECODE_VERSION); // constants - ByteArray constant_indexes; - ByteArray raw_constants; + ByteArrayBuilder constant_indexes; + ByteArrayBuilder raw_constants; uint32_t idx = 0; for (auto const& constant: bp.constants) { @@ -116,8 +116,8 @@ ByteArray Bytecode::generate(BytecodePrototype const& bp) } // functions - ByteArray functions_indexes; - ByteArray raw_code; + ByteArrayBuilder functions_indexes; + ByteArrayBuilder raw_code; uint32_t idx_idx = 0, code_idx = 0; for (auto const& f: bp.functions) { @@ -135,7 +135,7 @@ ByteArray Bytecode::generate(BytecodePrototype const& bp) uint32_t raw_constant_start = function_idx_start + functions_indexes.size(); uint32_t raw_code_start = raw_constant_start + raw_constants.size(); - ByteArray toc; + ByteArrayBuilder toc; if (!bp.constants.empty()) { toc.set_uint32(SEC_CONST_IDX * TOC_RECORD_SZ, CONST_IDX_START); toc.set_uint32(SEC_CONST_IDX * TOC_RECORD_SZ + 4, constant_indexes.size() / CONST_RECORD_SZ); @@ -153,14 +153,14 @@ ByteArray Bytecode::generate(BytecodePrototype const& bp) // assemble bytecode // - ByteArray ba; + ByteArrayBuilder ba; ba.set_bytearray(0, header); ba.set_bytearray(TOC_START, toc); ba.set_bytearray(CONST_IDX_START, constant_indexes); ba.set_bytearray(function_idx_start, functions_indexes); ba.set_bytearray(raw_constant_start, raw_constants); ba.set_bytearray(raw_code_start, raw_code); - return ba; + return ba.build(); } } \ No newline at end of file diff --git a/src/bytecode/bytecode.hh b/src/bytecode/bytecode.hh index 5835ab8..55fd0d1 100644 --- a/src/bytecode/bytecode.hh +++ b/src/bytecode/bytecode.hh @@ -1,7 +1,7 @@ #ifndef TYCHE_BYTECODE_HH #define TYCHE_BYTECODE_HH -#include "../common/bytearray.hh" +#include "../bytearray/bytearray.hh" #include "bytecodeprototype.hh" #include "constant.hh" @@ -9,8 +9,7 @@ namespace tyche::bc { class Bytecode { public: - Bytecode() = default; - explicit Bytecode(ByteArray ba); + explicit Bytecode(StaticByteArray const* ba); [[nodiscard]] uint32_t n_constants() const; [[nodiscard]] uint32_t n_functions() const; @@ -28,10 +27,10 @@ public: // TODO - debugging info - [[nodiscard]] static ByteArray generate(BytecodePrototype const& bp); + [[nodiscard]] static StaticByteArray generate(BytecodePrototype const& bp); private: - ByteArray byte_array_; // the actual data + StaticByteArray const* byte_array_; // the actual data static constexpr uint8_t BYTECODE_VERSION = 1; static constexpr uint32_t MAGIC_NUMBER = 0x74b3c138; diff --git a/src/bytecode/bytecodeprototype.hh b/src/bytecode/bytecodeprototype.hh index 908bb2f..562627e 100644 --- a/src/bytecode/bytecodeprototype.hh +++ b/src/bytecode/bytecodeprototype.hh @@ -5,17 +5,17 @@ #include #include #include -#include "../common/bytearray.hh" +#include "../bytearray/bytearraybuilder.hh" namespace tyche::bc { struct BytecodePrototype { struct Function { - uint16_t n_pars; - uint16_t n_locals; - ByteArray code {}; + uint16_t n_pars; + uint16_t n_locals; + ByteArrayBuilder code {}; - Function(uint16_t n_pars_, uint16_t n_locals_) : n_pars(n_pars_), n_locals(n_locals_), code(ByteArray {}) {} + Function(uint16_t n_pars_, uint16_t n_locals_) : n_pars(n_pars_), n_locals(n_locals_), code(ByteArrayBuilder {}) {} }; using ConstantValue = std::variant; diff --git a/src/bytecode/tests.cc b/src/bytecode/tests.cc index fa02e34..6cae72b 100644 --- a/src/bytecode/tests.cc +++ b/src/bytecode/tests.cc @@ -3,43 +3,46 @@ #include #include -#include "../common/bytearray.hh" +#include "../bytearray/bytearray.hh" +#include "../bytearray/bytearraybuilder.hh" #include "bytecodeprototype.hh" #include "bytecode.hh" using namespace tyche; using namespace tyche::bc; -TEST(ByteArray, ByteArray) +TEST(StaticByteArray, StaticByteArray) { - auto test = [](std::function const& f, std::vector const& expected) { - ByteArray ba; + auto test = [](std::function const& f, std::vector const& expected) { + ByteArrayBuilder ba; f(ba); ASSERT_EQ(ba.data().size(), expected.size()); ASSERT_EQ(std::memcmp(ba.data().data(), expected.data(), ba.data().size()), 0); }; -#define TESTX(a, ...) test([](ByteArray& ba) { a; }, std::vector({ __VA_ARGS__ })); +#define TESTX(a, ...) test([](ByteArrayBuilder& ba) { a; }, std::vector({ __VA_ARGS__ })); TESTX(ba.set_byte(1, 0xab), 0x00, 0xab) - ByteArray ba; - ba.set_byte(1, 0xab); ASSERT_EQ(ba.get_byte(1), 0xab); + ByteArrayBuilder ba; + { auto b = ba.set_byte(1, 0xab).build(); ASSERT_EQ(b.get_byte(1), 0xab); } - ba.set_int8(1, 12); ASSERT_EQ(ba.get_int8(1), 12); - ba.set_int8(1, -12); ASSERT_EQ(ba.get_int8(1), -12); - ba.set_int16(1, 5000); ASSERT_EQ(ba.get_int16(1), 5000); - ba.set_int32(1, 5000300); ASSERT_EQ(ba.get_int32(1), 5000300); - ba.set_int32(1, -5000300); ASSERT_EQ(ba.get_int32(1), -5000300); + { auto b = ba.set_int8(1, 12).build(); ASSERT_EQ(b.get_int8(1), 12); } + { auto b = ba.set_int8(1, -12).build(); ASSERT_EQ(b.get_int8(1), -12); } + { auto b = ba.set_int16(1, 5000).build(); ASSERT_EQ(b.get_int16(1), 5000); } + { auto b = ba.set_int32(1, 5000300).build(); ASSERT_EQ(b.get_int32(1), 5000300); } + { auto b = ba.set_int32(1, -5000300).build(); ASSERT_EQ(b.get_int32(1), -5000300); } - ba.set_float(1, 3.14); ASSERT_FLOAT_EQ(ba.get_float(1), 3.14); - ba.set_float(1, -3.14); ASSERT_FLOAT_EQ(ba.get_float(1), -3.14); - ba.set_float(1, -5000300.1324); ASSERT_FLOAT_EQ(ba.get_float(1), -5000300.1324); + { auto b = ba.set_float(1, 3.14).build(); ASSERT_FLOAT_EQ(b.get_float(1), 3.14); } + { auto b = ba.set_float(1, -3.14).build(); ASSERT_FLOAT_EQ(b.get_float(1), -3.14); } + { auto b = ba.set_float(1, -5000300.1324).build(); ASSERT_FLOAT_EQ(b.get_float(1), -5000300.1324); } - ba.set_string(1, "Hello world!"); - auto str = ba.get_string_ptr(1); - EXPECT_STREQ(str.first, "Hello world!"); - ASSERT_EQ(str.second, 13); + { + auto b = ba.set_string(1, "Hello world!").build(); + auto str = b.get_string_ptr(1); + EXPECT_STREQ(str.first, "Hello world!"); + ASSERT_EQ(str.second, 13); + } #undef TESTX } @@ -76,7 +79,7 @@ TEST(Bytecode, Constants) CONST_TYPE_STRING, 'H', 'E', 'L', 'L', 'O', 0x00 }; - ByteArray ba = Bytecode::generate(bp); + StaticByteArray ba = Bytecode::generate(bp); ASSERT_EQ(ba.data(), expected); } @@ -115,7 +118,7 @@ TEST(Bytecode, Code) 0x68, 42, 0x42, }; - ByteArray ba = Bytecode::generate(bp); + StaticByteArray ba = Bytecode::generate(bp); ASSERT_EQ(ba.data(), expected); } @@ -135,12 +138,12 @@ TEST(Bytecode, Parsing) auto& ff = bp.functions.emplace_back(2, 1); ff.code.append_byte(0x42); - ByteArray ba = Bytecode::generate(bp); + StaticByteArray ba = Bytecode::generate(bp); // print(ba.data()); // read bytecode - Bytecode bc(std::move(ba)); + Bytecode bc(&ba); ASSERT_EQ(bc.n_constants(), 2); ASSERT_EQ(bc.n_functions(), 2); diff --git a/src/common/bytearray.cc b/src/common/bytearray.cc deleted file mode 100644 index cb3e973..0000000 --- a/src/common/bytearray.cc +++ /dev/null @@ -1,149 +0,0 @@ -#include "bytearray.hh" - -#include -#include - -namespace tyche { - -void ByteArray::set_byte(uint32_t addr, uint8_t byte) -{ - if (data_.size() < (addr + 1)) - data_.resize(addr + 1, 0); - data_.at(addr) = byte; -} - -void ByteArray::set_int8(uint32_t addr, int8_t value) -{ - set_byte(addr, (uint8_t) value); -} - -void ByteArray::set_int16(uint32_t addr, int16_t value) -{ - set_byte(addr, (uint8_t) (value)); - set_byte(addr+1, (uint8_t) (value >> 8)); -} - -void ByteArray::set_int32(uint32_t addr, int32_t value) -{ - 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::set_uint16(uint32_t addr, uint16_t value) -{ - set_byte(addr, (uint8_t) (value)); - set_byte(addr+1, (uint8_t) (value >> 8)); -} - -void ByteArray::set_uint32(uint32_t addr, uint32_t value) -{ - 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::set_float(uint32_t addr, float value) -{ - uint32_t bits; - std::memcpy(&bits, &value, 4); - 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::set_string(uint32_t addr, std::string const& str) -{ - for (uint8_t c: str) - set_byte(addr++, c); - set_byte(addr, 0); -} - -void ByteArray::set_bytearray(uint32_t addr, ByteArray const& bytearray) -{ - for (uint8_t byte: bytearray.data()) - set_byte(addr++, byte); -} - -uint8_t ByteArray::get_byte(uint32_t addr) const -{ - return data_.at(addr); -} - -uint16_t ByteArray::get_uint16(uint32_t addr) const -{ - return (uint32_t) get_byte(addr) - | (uint32_t) get_byte(addr+1) << 8; -} - -uint32_t ByteArray::get_uint32(uint32_t addr) const -{ - return (uint32_t) get_byte(addr) - | (uint32_t) get_byte(addr+1) << 8 - | (uint32_t) get_byte(addr+2) << 16 - | (uint32_t) get_byte(addr+3) << 24; -} - -int8_t ByteArray::get_int8(uint32_t addr) const -{ - return std::bit_cast(get_byte(addr)); -} - -int16_t ByteArray::get_int16(uint32_t addr) const -{ - return (uint16_t) get_byte(addr) - | (uint16_t) get_byte(addr+1) << 8; -} - -int32_t ByteArray::get_int32(uint32_t addr) const -{ - return std::bit_cast((uint32_t) get_byte(addr) - | (uint32_t) get_byte(addr+1) << 8 - | (uint32_t) get_byte(addr+2) << 16 - | (uint32_t) get_byte(addr+3) << 24); -} - -float ByteArray::get_float(uint32_t addr) const -{ - uint32_t bits = (uint32_t) get_byte(addr) - | (uint32_t) get_byte(addr+1) << 8 - | (uint32_t) get_byte(addr+2) << 16 - | (uint32_t) get_byte(addr+3) << 24; - float value; - std::memcpy(&value, &bits, 4); - return value; -} - -std::pair ByteArray::get_string_ptr(uint32_t addr) const -{ - return { (const char *) &data_.at(addr), strlen((const char *) &data_.at(addr)) + 1 }; -} - -void ByteArray::append_bytearray(ByteArray const& bytearray) -{ - data_.insert(data_.end(), bytearray.data().begin(), bytearray.data().end()); -} - -std::string ByteArray::hexdump() const -{ - auto to_hex = [](uint32_t value, size_t n_chars) -> std::string { - char buf[15]; - snprintf(buf, sizeof buf, "%0*X", (int) n_chars, value); - return { buf }; - }; - - std::string out; - for (size_t i = 0; i < data_.size(); ++i) { - if (i % 16 == 0) - out += to_hex(i, 4) + " | "; - out += to_hex(data_.at(i), 2) + " "; - if (i % 16 == 15) - out += "\n"; - } - return out + "\n"; -} - -} \ No newline at end of file diff --git a/src/common/bytearray.hh b/src/common/bytearray.hh deleted file mode 100644 index d3ed12f..0000000 --- a/src/common/bytearray.hh +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef TYCHE_BYTEARRAY_HH -#define TYCHE_BYTEARRAY_HH - -#include -#include -#include -#include - -namespace tyche { - -class ByteArray { -public: - ByteArray() = default; - explicit ByteArray(std::vector data) : data_(std::move(data)) {} - - void set_byte(uint32_t addr, uint8_t byte); - void set_uint16(uint32_t addr, uint16_t value); - void set_uint32(uint32_t addr, uint32_t value); - void set_int8(uint32_t addr, int8_t value); - void set_int16(uint32_t addr, int16_t value); - void set_int32(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 set_bytearray(uint32_t addr, ByteArray const& bytearray); - - void append_byte(uint8_t byte) { set_byte(data_.size(), byte); } - void append_uint16(uint16_t value) { set_uint16(data_.size(), value); } - void append_uint32(uint32_t value) { set_uint32(data_.size(), value); } - void append_int8(int8_t value) { set_int8(data_.size(), value); } - void append_int16(int16_t value) { set_int16(data_.size(), value); } - void append_int32(int32_t value) { set_int32(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]] uint16_t get_uint16(uint32_t addr) const; - [[nodiscard]] uint32_t get_uint32(uint32_t addr) const; - [[nodiscard]] int8_t get_int8(uint32_t addr) const; - [[nodiscard]] int16_t get_int16(uint32_t addr) const; - [[nodiscard]] int32_t get_int32(uint32_t addr) const; - [[nodiscard]] float get_float(uint32_t addr) const; - [[nodiscard]] std::pair get_string_ptr(uint32_t addr) const; - - [[nodiscard]] std::vector const& data() const { return data_; } - [[nodiscard]] size_t size() const { return data_.size(); } - - [[nodiscard]] std::string hexdump() const; - - friend bool operator==(ByteArray const& lhs, ByteArray const& rhs) { return lhs.data_ == rhs.data_; } - -private: - std::vector data_ {}; -}; - -} - -#endif //TYCHE_BYTEARRAY_HH diff --git a/src/vm/code.cc b/src/vm/code.cc index 75a98d3..372e2b3 100644 --- a/src/vm/code.cc +++ b/src/vm/code.cc @@ -4,9 +4,9 @@ namespace tyche::vm { -FunctionId Code::import_bytecode(ByteArray incoming) +FunctionId Code::import_bytecode(StaticByteArray const* incoming) { - bc::Bytecode bc(std::move(incoming)); + bc::Bytecode bc(incoming); // TODO - adjust function calls, constants bytecode_ = std::move(bc); diff --git a/src/vm/code.hh b/src/vm/code.hh index 6296018..90b4639 100644 --- a/src/vm/code.hh +++ b/src/vm/code.hh @@ -17,7 +17,7 @@ struct Operation class Code { public: - FunctionId import_bytecode(ByteArray incoming); + FunctionId import_bytecode(StaticByteArray const* incoming); [[nodiscard]] std::string disassemble() const;