diff --git a/include/Ark/Compiler/BytecodeReader.hpp b/include/Ark/Compiler/BytecodeReader.hpp index 4fe3d3570..9c006979e 100644 --- a/include/Ark/Compiler/BytecodeReader.hpp +++ b/include/Ark/Compiler/BytecodeReader.hpp @@ -79,7 +79,7 @@ namespace Ark /** * @brief This class is just a helper to * - check if a bytecode is valid - * - display it in a human readable way by using the opcode names + * - display it in a human-readable way by using the opcode names * */ class ARK_API BytecodeReader final diff --git a/include/Ark/VM/State.hpp b/include/Ark/VM/State.hpp index c15a62cd3..9226d47c8 100644 --- a/include/Ark/VM/State.hpp +++ b/include/Ark/VM/State.hpp @@ -133,7 +133,7 @@ namespace Ark * @return true on success * @return false on failure and raise an exception */ - bool compile(const std::string& file, const std::string& output, uint16_t features) const; + [[nodiscard]] bool compile(const std::string& file, const std::string& output, uint16_t features) const; static void throwStateError(const std::string& message) { @@ -151,10 +151,23 @@ namespace Ark std::vector m_constants; std::vector m_filenames; std::vector m_inst_locations; - std::vector m_pages; + std::size_t m_max_page_size; + bytecode_t m_code; // related to the execution - std::unordered_map m_binded; + std::unordered_map m_binded; ///< Values binded to the State, to be used by the VM + + /** + * @brief Get an instruction in a given page, with a given instruction pointer + * + * @param pp page pointer + * @param ip instruction pointer + * @return uint8_t instruction + */ + [[nodiscard]] inline constexpr uint8_t inst(const std::size_t pp, const std::size_t ip) const noexcept + { + return m_code[pp * m_max_page_size + ip]; + } }; } diff --git a/include/Ark/VM/VM.inl b/include/Ark/VM/VM.inl index 22f08568e..d3cbf1ea6 100644 --- a/include/Ark/VM/VM.inl +++ b/include/Ark/VM/VM.inl @@ -306,18 +306,18 @@ inline void VM::call(internal::ExecutionContext& context, const uint16_t argc, V needed_argc = 0; // every argument is a MUT declaration in the bytecode - while (m_state.m_pages[context.pp][index] == STORE) + while (m_state.inst(context.pp, index) == STORE) { needed_argc += 1; index += 4; // instructions are on 4 bytes } // no store? check for CALL_BUILTIN_WITHOUT_RETURN_ADDRESS - if (index == 0 && m_state.m_pages[context.pp][0] == CALL_BUILTIN_WITHOUT_RETURN_ADDRESS) + if (index == 0 && m_state.inst(context.pp, 0) == CALL_BUILTIN_WITHOUT_RETURN_ADDRESS) { - const uint8_t padding = m_state.m_pages[context.pp][context.ip + 1]; - const uint16_t arg = static_cast((m_state.m_pages[context.pp][context.ip + 2] << 8) + - m_state.m_pages[context.pp][context.ip + 3]); + const uint8_t padding = m_state.inst(context.pp, context.ip + 1); + const uint16_t arg = static_cast((m_state.inst(context.pp, context.ip + 2) << 8) + + m_state.inst(context.pp, context.ip + 3)); needed_argc = static_cast((padding << 4) | (arg & 0xf000) >> 12); } diff --git a/lib/std b/lib/std index ce6b59189..b29bde7a3 160000 --- a/lib/std +++ b/lib/std @@ -1 +1 @@ -Subproject commit ce6b591895bab4ab811f803c7126f57e9f76df1a +Subproject commit b29bde7a345cfc34cca362f3f36af7b40a3332fc diff --git a/src/arkreactor/VM/State.cpp b/src/arkreactor/VM/State.cpp index 29ca6d72c..f7acc029a 100644 --- a/src/arkreactor/VM/State.cpp +++ b/src/arkreactor/VM/State.cpp @@ -19,7 +19,8 @@ namespace Ark State::State(const std::vector& libenv) noexcept : m_debug_level(0), m_libenv(libenv), - m_filename(ARK_NO_NAME_FILE) + m_filename(ARK_NO_NAME_FILE), + m_max_page_size(0) { // default value for builtin__sys:args is empty list const Value val(ValueType::List); @@ -178,7 +179,24 @@ namespace Ark m_constants = vals.values; m_filenames = files.filenames; m_inst_locations = inst_locs.locations; - m_pages = pages; + + m_max_page_size = 0; + for (const bytecode_t& page : pages) + { + if (page.size() > m_max_page_size) + m_max_page_size = page.size(); + } + + // Make m_code as a big contiguous chunk of instructions, + // aligned on the biggest page size. + // This might have a downside when we have a single big page and + // a bunch of smaller ones, though I couldn't measure it while testing. + m_code.resize(m_max_page_size * pages.size(), Instruction::NOP); + for (std::size_t i = 0, end = pages.size(); i < end; ++i) + { + for (std::size_t j = 0, end_j = pages[i].size(); j < end_j; ++j) + m_code[i * m_max_page_size + j] = pages[i][j]; + } } void State::reset() noexcept @@ -187,7 +205,8 @@ namespace Ark m_constants.clear(); m_filenames.clear(); m_inst_locations.clear(); - m_pages.clear(); + m_max_page_size = 0; + m_code.clear(); m_binded.clear(); // default value for builtin__sys:args is empty list diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 11b7d5f57..988dfc6ce 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -178,7 +178,7 @@ namespace Ark if (Value* field = closure->refClosure().refScope()[id]; field != nullptr) { // check for CALL instruction (the instruction because context.ip is already on the next instruction word) - if (m_state.m_pages[context.pp][context.ip] == CALL) + if (m_state.inst(context.pp, context.ip) == CALL) return Value(Closure(closure->refClosure().scopePtr(), field->pageAddr())); else return *field; @@ -462,14 +462,14 @@ namespace Ark # define GOTO_HALT() break #endif -#define NEXTOPARG() \ - do \ - { \ - inst = m_state.m_pages[context.pp][context.ip]; \ - padding = m_state.m_pages[context.pp][context.ip + 1]; \ - arg = static_cast((m_state.m_pages[context.pp][context.ip + 2] << 8) + \ - m_state.m_pages[context.pp][context.ip + 3]); \ - context.ip += 4; \ +#define NEXTOPARG() \ + do \ + { \ + inst = m_state.inst(context.pp, context.ip); \ + padding = m_state.inst(context.pp, context.ip + 1); \ + arg = static_cast((m_state.inst(context.pp, context.ip + 2) << 8) + \ + m_state.inst(context.pp, context.ip + 3)); \ + context.ip += 4; \ } while (false) #define DISPATCH() \ NEXTOPARG(); \ @@ -1901,16 +1901,16 @@ namespace Ark arg_names.emplace_back(""); // for formatting, so that we have a space between the function and the args std::size_t index = 0; - while (m_state.m_pages[context.pp][index] == STORE) + while (m_state.inst(context.pp, index) == STORE) { - const auto id = static_cast((m_state.m_pages[context.pp][index + 2] << 8) + m_state.m_pages[context.pp][index + 3]); + const auto id = static_cast((m_state.inst(context.pp, index + 2) << 8) + m_state.inst(context.pp, index + 3)); arg_names.push_back(m_state.m_symbols[id]); index += 4; } // we only the blank space for formatting and no arg names, probably because of a CALL_BUILTIN_WITHOUT_RETURN_ADDRESS if (arg_names.size() == 1 && index == 0) { - assert(m_state.m_pages[context.pp][0] == CALL_BUILTIN_WITHOUT_RETURN_ADDRESS && "expected a CALL_BUILTIN_WITHOUT_RETURN_ADDRESS instruction or STORE instructions"); + assert(m_state.inst(context.pp, 0) == CALL_BUILTIN_WITHOUT_RETURN_ADDRESS && "expected a CALL_BUILTIN_WITHOUT_RETURN_ADDRESS instruction or STORE instructions"); for (std::size_t i = 0; i < expected_arg_count; ++i) arg_names.push_back(std::string(1, static_cast('a' + i))); } diff --git a/tests/benchmarks/resources/parser/bigger.ark b/tests/benchmarks/resources/parser/bigger.ark index 8a07ea805..6d53575cc 100644 --- a/tests/benchmarks/resources/parser/bigger.ark +++ b/tests/benchmarks/resources/parser/bigger.ark @@ -39,13 +39,13 @@ # @param _x the number to pow # @param _a the exponent # @author https://github.com/SuperFola -(let pow (fun (_x _a) (math:exp (* _a (math:ln _x))))) +(let pow (fun (_x _a) (builtin__math:exp (* _a (builtin__math:ln _x))))) # @brief Get the square root of a number # @details Square roots can't be taken for negative numbers for obvious reasons. # @param _x the number # @author https://github.com/SuperFola -(let sqrt (fun (_x) (math:exp (* 0.5 (math:ln _x))))) +(let sqrt (fun (_x) (builtin__math:exp (* 0.5 (builtin__math:ln _x))))) # @brief Run the fibonacci function on a number # @param n the number @@ -71,7 +71,7 @@ (if (or (= 0 (mod n 2)) (= 1 n)) false { - (let k (math:ceil (+ 1 (sqrt n)))) + (let k (builtin__math:ceil (+ 1 (sqrt n)))) (mut i 3) (mut continue true) @@ -91,7 +91,7 @@ (assert (>= n 2) "divs: n must be greater or equal to 2") (mut i 2) (mut divisors [1]) - (let top (math:ceil (/ n 2))) + (let top (builtin__math:ceil (/ n 2))) (while (and (<= i top) (!= top n)) { (if (= (mod n i) 0) @@ -109,7 +109,7 @@ (let log (fun (x n) { (assert (> x 0) "log: x must be greater than 0") (assert (>= n 1) "log: n must be greater or equal to 1") - (math:round (/ (math:ln x) (math:ln n))) })) + (builtin__math:round (/ (builtin__math:ln x) (builtin__math:ln n))) })) # @brief Returns the logarithm base 2 of a number # @param x the number @@ -134,7 +134,7 @@ # =begin # (floordiv 14 6) # Returns 2 # =end -(let floordiv (fun (a b) (math:floor (/ a b)))) +(let floordiv (fun (a b) (builtin__math:floor (/ a b)))) # @brief Create a complex number # @param real the real part of the complex number @@ -710,8 +710,8 @@ (while (< _index (len text)) { (set _e (@ text _index)) - (if (in_range (string:ord _e) 65 90) - (set _e (string:chr (+ (string:ord _e) 32)))) + (if (in_range (builtin__string:ord _e) 65 90) + (set _e (builtin__string:chr (+ (builtin__string:ord _e) 32)))) (set _output (+ _output _e)) (set _index (+ _index 1)) }) _output })) @@ -735,8 +735,8 @@ (while (< _index (len _string)) { (set _e (@ _string _index)) - (if (in_range (string:ord _e) 97 122) - (set _e (string:chr (- (string:ord _e) 32)))) + (if (in_range (builtin__string:ord _e) 97 122) + (set _e (builtin__string:chr (- (builtin__string:ord _e) 32)))) (set _output (+ _output _e)) (set _index (+ _index 1)) }) _output })) @@ -800,7 +800,7 @@ # =end # @author https://github.com/Natendrtfm (let split (fun (_string _separator) { - (mut _at (string:find _string _separator)) + (mut _at (builtin__string:find _string _separator)) (let _seplen (len _separator)) (let _strlen (len _string)) (mut _output []) @@ -819,7 +819,7 @@ (append! _output _last) (set _last "") (set _i (+ _at _seplen)) - (set _at (string:find _string _separator _i)) + (set _at (builtin__string:find _string _separator _i)) (if (= -1 _at) (set _at _strlen)) }) }) @@ -841,7 +841,7 @@ # =end (let replace (fun (_string _pattern _new) { (mut _out _string) - (mut _idx (string:find _out _pattern)) + (mut _idx (builtin__string:find _out _pattern)) (let _pattern_sz (len _pattern)) (while (!= -1 _idx) { @@ -849,7 +849,7 @@ (mut _next_segment (sliceStr _out (+ _idx _pattern_sz) (- (len _out) (+ _idx _pattern_sz)))) (set _out (+ _first_segment _new _next_segment)) - (set _idx (string:find _next_segment _pattern)) + (set _idx (builtin__string:find _next_segment _pattern)) (if (!= -1 _idx) (set _idx (+ _idx (len _first_segment) (len _new)))) }) _out })) @@ -893,7 +893,7 @@ (while (< _index _line_count) { (let _current (@ _lines _index)) - (let _marker_pos (string:find _current "|")) + (let _marker_pos (builtin__string:find _current "|")) (if (= -1 _marker_pos) (set _output (+ _output _current)) (set _output (+ _output (sliceStr _current (+ 1 _marker_pos) (len _current))))) diff --git a/tests/benchmarks/results/10-eaf4ada5.csv b/tests/benchmarks/results/10-eaf4ada5.csv new file mode 100644 index 000000000..6321b9a4b --- /dev/null +++ b/tests/benchmarks/results/10-eaf4ada5.csv @@ -0,0 +1,9 @@ +name,iterations,real_time,cpu_time,time_unit,bytes_per_second,items_per_second,label,error_occurred,error_message +"quicksort",6934,0.100461,0.100319,ms,,,,, +"ackermann/iterations:50",50,32.764,32.7365,ms,,,,, +"fibonacci/iterations:100",100,3.52737,3.52382,ms,,,,, +"builtins",1212,0.571866,0.571354,ms,,,,, +"binary_trees",1,893.398,892.54,ms,,,,, +"for_sum",9,81.0522,80.978,ms,,,,, +"create_closure",907,0.777191,0.776437,ms,,,,, +"create_list",410,1.7468,1.74436,ms,,,,, diff --git a/tests/benchmarks/results/11-eaf4ada5.csv b/tests/benchmarks/results/11-eaf4ada5.csv new file mode 100644 index 000000000..38fee8527 --- /dev/null +++ b/tests/benchmarks/results/11-eaf4ada5.csv @@ -0,0 +1,9 @@ +name,iterations,real_time,cpu_time,time_unit,bytes_per_second,items_per_second,label,error_occurred,error_message +"quicksort",7012,0.0993193,0.0992069,ms,,,,, +"ackermann/iterations:50",50,31.207,31.1729,ms,,,,, +"fibonacci/iterations:100",100,3.48333,3.47967,ms,,,,, +"builtins",1196,0.582098,0.581393,ms,,,,, +"binary_trees",1,889.703,888.661,ms,,,,, +"for_sum",8,85.2439,85.1338,ms,,,,, +"create_closure",903,0.768519,0.767898,ms,,,,, +"create_list",411,1.68982,1.68745,ms,,,,,