diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba85f590e..1ff622c8e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,7 +142,7 @@ jobs: install-arkscript: runs-on: ${{ matrix.os }} - name: Install ArkScript on ${{ matrix.os }} + name: "Install ArkScript on ${{ matrix.os }} (static: ${{ matrix.static }})" needs: [ check ] strategy: diff --git a/CMakeLists.txt b/CMakeLists.txt index e1843b1c4..be6731074 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -202,7 +202,7 @@ endif () # Create the different (optional) targets ##################################################### -if (ARK_BUILD_MODULES) +if (ARK_BUILD_MODULES AND NOT ARK_STATIC) get_directory_property(old_dir_compile_options COMPILE_OPTIONS) add_compile_options(-w) add_subdirectory(${ark_SOURCE_DIR}/lib/modules) @@ -358,8 +358,8 @@ if (ARK_BUILD_EXE) RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif () -if (ARK_SANITIZERS) - message(STATUS "Enabling address sanitizer and undefined behavior sanitizer") +if (ARK_SANITIZERS AND NOT ARK_STATIC) + message(STATUS "Enabling ASAN and UBSAN") add_address_sanitizer() add_undefined_sanitizer() endif () diff --git a/include/Ark/Compiler/AST/Node.hpp b/include/Ark/Compiler/AST/Node.hpp index 923afef7e..e2fde7cb8 100644 --- a/include/Ark/Compiler/AST/Node.hpp +++ b/include/Ark/Compiler/AST/Node.hpp @@ -261,7 +261,7 @@ namespace Ark::internal * @param node * @return std::string a string corresponding to the node type */ - inline std::string typeToString(const Node& node) noexcept + ARK_ALWAYS_INLINE inline std::string typeToString(const Node& node) noexcept { if (node.nodeType() == NodeType::Symbol) { diff --git a/include/Ark/Compiler/IntermediateRepresentation/Entity.hpp b/include/Ark/Compiler/IntermediateRepresentation/Entity.hpp index 869e8fab3..6f7bae73d 100644 --- a/include/Ark/Compiler/IntermediateRepresentation/Entity.hpp +++ b/include/Ark/Compiler/IntermediateRepresentation/Entity.hpp @@ -60,25 +60,25 @@ namespace Ark::internal::IR [[nodiscard]] Word bytecode() const; - [[nodiscard]] inline label_t label() const { return m_label; } + [[nodiscard]] label_t label() const { return m_label; } - [[nodiscard]] inline Kind kind() const { return m_kind; } + [[nodiscard]] Kind kind() const { return m_kind; } - [[nodiscard]] inline Instruction inst() const { return m_inst; } + [[nodiscard]] Instruction inst() const { return m_inst; } - [[nodiscard]] inline uint16_t primaryArg() const { return m_primary_arg; } + [[nodiscard]] uint16_t primaryArg() const { return m_primary_arg; } - [[nodiscard]] inline uint16_t secondaryArg() const { return m_secondary_arg; } + [[nodiscard]] uint16_t secondaryArg() const { return m_secondary_arg; } - [[nodiscard]] inline uint16_t tertiaryArg() const { return m_tertiary_arg; } + [[nodiscard]] uint16_t tertiaryArg() const { return m_tertiary_arg; } void setSourceLocation(const std::string& filename, std::size_t line); - [[nodiscard]] inline bool hasValidSourceLocation() const { return !m_source_file.empty(); } + [[nodiscard]] bool hasValidSourceLocation() const { return !m_source_file.empty(); } - [[nodiscard]] inline const std::string& filename() const { return m_source_file; } + [[nodiscard]] const std::string& filename() const { return m_source_file; } - [[nodiscard]] inline std::size_t sourceLine() const { return m_source_line; } + [[nodiscard]] std::size_t sourceLine() const { return m_source_line; } private: Kind m_kind; diff --git a/include/Ark/State.hpp b/include/Ark/State.hpp index da8c49349..9822f72c1 100644 --- a/include/Ark/State.hpp +++ b/include/Ark/State.hpp @@ -195,7 +195,7 @@ namespace Ark * @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 + [[nodiscard]] ARK_ALWAYS_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/Utils/Platform.hpp b/include/Ark/Utils/Platform.hpp index a104c07a5..1a2a9fa9a 100644 --- a/include/Ark/Utils/Platform.hpp +++ b/include/Ark/Utils/Platform.hpp @@ -17,6 +17,14 @@ # define ARK_OS_LINUX #endif +#if defined(__GNUC__) || defined(__clang__) +# define ARK_ALWAYS_INLINE __attribute__((always_inline)) +#elif defined(_MSC_VER) && !defined(__clang__) +# define ARK_ALWAYS_INLINE __forceinline +#else +# define ARK_ALWAYS_INLINE +#endif + #ifndef ARK_STATIC # ifdef ARK_OS_WINDOWS // Windows compilers need specific (and different) keywords for export and import @@ -36,7 +44,7 @@ // the same keyword is used for both importing and exporting # define ARK_API __attribute__((__visibility__("default"))) # else -// GCC < 4 has no mechanism to explicitely hide symbols, everything's exported +// GCC < 4 has no mechanism to explicitly hide symbols, everything's exported # define ARK_API # endif # endif diff --git a/include/Ark/VM/Debugger.hpp b/include/Ark/VM/Debugger.hpp index edb2462e4..0515675c5 100644 --- a/include/Ark/VM/Debugger.hpp +++ b/include/Ark/VM/Debugger.hpp @@ -96,12 +96,12 @@ namespace Ark::internal void registerInstruction(uint32_t word) noexcept; - [[nodiscard]] inline bool isRunning() const noexcept + [[nodiscard]] ARK_ALWAYS_INLINE bool isRunning() const noexcept { return m_running; } - [[nodiscard]] inline bool shouldQuitVM() const noexcept + [[nodiscard]] ARK_ALWAYS_INLINE bool shouldQuitVM() const noexcept { return m_quit_vm; } diff --git a/include/Ark/VM/Helpers.hpp b/include/Ark/VM/Helpers.hpp index 8c56f3324..a13d4f56f 100644 --- a/include/Ark/VM/Helpers.hpp +++ b/include/Ark/VM/Helpers.hpp @@ -20,7 +20,7 @@ namespace Ark::helper { using namespace internal; - inline Value tail(Value* a) + inline ARK_ALWAYS_INLINE Value tail(Value* a) { if (a->valueType() == ValueType::List) { @@ -49,7 +49,7 @@ namespace Ark::helper { *a }); } - inline Value head(Value* a) + inline ARK_ALWAYS_INLINE Value head(Value* a) { if (a->valueType() == ValueType::List) { @@ -71,7 +71,7 @@ namespace Ark::helper { *a }); } - inline Value at(Value& container, Value& index, VM& vm) + inline ARK_ALWAYS_INLINE Value at(Value& container, Value& index, VM& vm) { if (index.valueType() != ValueType::Number) throw types::TypeCheckingError( @@ -110,7 +110,7 @@ namespace Ark::helper { container, index }); } - inline Value atAt(const Value* x, const Value* y, Value& list) + inline ARK_ALWAYS_INLINE Value atAt(const Value* x, const Value* y, Value& list) { if (y->valueType() != ValueType::Number || x->valueType() != ValueType::Number || list.valueType() != ValueType::List) @@ -148,7 +148,7 @@ namespace Ark::helper return Value(std::string(1, list.list()[static_cast(idx_y)].stringRef()[static_cast(idx_x)])); } - inline double doMath(double a, double b, const Instruction op) + inline ARK_ALWAYS_INLINE double doMath(double a, double b, const Instruction op) { if (op == ADD) a += b; @@ -166,7 +166,7 @@ namespace Ark::helper return a; } - inline std::string mathInstToStr(const Instruction op) + inline ARK_ALWAYS_INLINE std::string mathInstToStr(const Instruction op) { if (op == ADD) return "+"; diff --git a/include/Ark/VM/ScopeView.hpp b/include/Ark/VM/ScopeView.hpp index 11fec5315..37120006e 100644 --- a/include/Ark/VM/ScopeView.hpp +++ b/include/Ark/VM/ScopeView.hpp @@ -47,7 +47,16 @@ namespace Ark::internal * @param id The symbol id of the variable * @param val The value linked to the symbol */ - void pushBack(uint16_t id, Value&& val) noexcept; + ARK_ALWAYS_INLINE void pushBack(uint16_t id, Value&& val) noexcept + { + if (id < m_min_id) + m_min_id = id; + if (id > m_max_id) + m_max_id = id; + + m_storage[m_start + m_size] = std::make_pair(id, std::move(val)); + ++m_size; + } /** * @brief Put a value in the scope @@ -55,7 +64,16 @@ namespace Ark::internal * @param id The symbol id of the variable * @param val The value linked to the symbol */ - void pushBack(uint16_t id, const Value& val) noexcept; + ARK_ALWAYS_INLINE void pushBack(uint16_t id, const Value& val) noexcept + { + if (id < m_min_id) + m_min_id = id; + if (id > m_max_id) + m_max_id = id; + + m_storage[m_start + m_size] = std::make_pair(id, val); + ++m_size; + } /** * @brief Insert one or more pairs at the beginning of the scope @@ -72,7 +90,10 @@ namespace Ark::internal * @return true On success * @return false Otherwise */ - [[nodiscard]] bool maybeHas(uint16_t id) const noexcept; + [[nodiscard]] ARK_ALWAYS_INLINE bool maybeHas(const uint16_t id) const noexcept + { + return m_min_id <= id && id <= m_max_id; + } /** * @brief Get a value from its symbol id @@ -103,7 +124,7 @@ namespace Ark::internal * * @return const pair_t& */ - [[nodiscard]] inline const pair_t& atPos(const std::size_t i) const noexcept + [[nodiscard]] ARK_ALWAYS_INLINE const pair_t& atPos(const std::size_t i) const noexcept { return m_storage[m_start + i]; } @@ -113,7 +134,7 @@ namespace Ark::internal * * @return const pair_t& */ - [[nodiscard]] inline pair_t& atPosReverse(const std::size_t i) noexcept + [[nodiscard]] ARK_ALWAYS_INLINE pair_t& atPosReverse(const std::size_t i) noexcept { return m_storage[m_start + m_size - 1 - i]; } @@ -128,7 +149,7 @@ namespace Ark::internal * * @return const std::size_t */ - [[nodiscard]] inline std::size_t size() const noexcept + [[nodiscard]] ARK_ALWAYS_INLINE std::size_t size() const noexcept { return m_size; } @@ -138,7 +159,7 @@ namespace Ark::internal * * @return std::size_t */ - [[nodiscard]] inline std::size_t storageEnd() const noexcept + [[nodiscard]] ARK_ALWAYS_INLINE std::size_t storageEnd() const noexcept { return m_start + m_size; } diff --git a/include/Ark/VM/VM.hpp b/include/Ark/VM/VM.hpp index aa0b70566..ea91b457d 100644 --- a/include/Ark/VM/VM.hpp +++ b/include/Ark/VM/VM.hpp @@ -105,7 +105,7 @@ namespace Ark * @brief Return a pointer to the first execution context, for the main thread of the app * @return internal::ExecutionContext* */ - inline internal::ExecutionContext* getDefaultContext() const + [[nodiscard]] internal::ExecutionContext* getDefaultContext() const { return m_execution_contexts.front().get(); } @@ -167,7 +167,7 @@ namespace Ark */ [[noreturn]] static void throwVMError(internal::ErrorKind kind, const std::string& message); - [[nodiscard]] inline const bytecode_t& bytecode() const + [[nodiscard]] const bytecode_t& bytecode() const { return m_state.m_bytecode; } @@ -204,6 +204,14 @@ namespace Ark template void unsafeRun(internal::ExecutionContext& context, std::size_t untilFrameCount = 0); + [[noreturn]] static ARK_ALWAYS_INLINE void stackOverflowError(const internal::ExecutionContext& context) + { + if (context.pp != 0) + throw Error("Stack overflow. You could consider rewriting your function to make use of tail-call optimization."); + else + throw Error("Stack overflow. Are you trying to call a function with too many arguments?"); + } + /** * @brief Initialize the VM according to the parameters * @@ -221,7 +229,7 @@ namespace Ark * @param context * @return Value* nullptr if the symbol could not be loaded */ - [[nodiscard]] inline Value* loadSymbol(uint16_t id, internal::ExecutionContext& context); + [[nodiscard]] inline ARK_ALWAYS_INLINE Value* loadSymbol(uint16_t id, internal::ExecutionContext& context); /** * @brief Load a symbol by its (reversed) index in the current scope @@ -230,7 +238,7 @@ namespace Ark * @param context * @return Value* */ - [[nodiscard]] inline Value* loadSymbolFromIndex(uint16_t index, internal::ExecutionContext& context); + [[nodiscard]] inline ARK_ALWAYS_INLINE Value* loadSymbolFromIndex(uint16_t index, internal::ExecutionContext& context); /** * @brief Load a constant from the constant table by its id @@ -238,7 +246,7 @@ namespace Ark * @param id * @return Value* */ - [[nodiscard]] inline Value* loadConstAsPtr(uint16_t id) const; + [[nodiscard]] inline ARK_ALWAYS_INLINE Value* loadConstAsPtr(uint16_t id) const; /** * @brief Create a new symbol with an associated value in the current scope @@ -247,7 +255,7 @@ namespace Ark * @param val * @param context */ - inline void store(uint16_t id, const Value* val, internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE void store(uint16_t id, const Value* val, internal::ExecutionContext& context); /** * @brief Change the value of a symbol given its identifier @@ -256,9 +264,9 @@ namespace Ark * @param val * @param context */ - inline void setVal(uint16_t id, const Value* val, internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE void setVal(uint16_t id, const Value* val, internal::ExecutionContext& context); - inline void jump(uint16_t address, internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE void jump(uint16_t address, internal::ExecutionContext& context); Value getField(Value* closure, uint16_t id, const internal::ExecutionContext& context, bool push_with_env = false); @@ -276,9 +284,9 @@ namespace Ark * @param context * @return Value* */ - inline Value* pop(internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE Value* pop(internal::ExecutionContext& context); - inline Value* peek(internal::ExecutionContext& context, std::size_t offset = 0); + inline ARK_ALWAYS_INLINE Value* peek(internal::ExecutionContext& context, std::size_t offset = 0); /** * @brief Return a pointer to the top of the stack without consuming it, and resolve it if possible @@ -287,7 +295,7 @@ namespace Ark * @param offset * @return Value* */ - inline Value* peekAndResolveAsPtr(internal::ExecutionContext& context, std::size_t offset = 0); + inline ARK_ALWAYS_INLINE Value* peekAndResolveAsPtr(internal::ExecutionContext& context, std::size_t offset = 0); /** * @brief Push a value on the stack @@ -295,7 +303,7 @@ namespace Ark * @param value * @param context */ - inline void push(const Value& value, internal::ExecutionContext& context) noexcept; + inline ARK_ALWAYS_INLINE void push(const Value& value, internal::ExecutionContext& context) noexcept; /** * @brief Push a value on the stack @@ -303,7 +311,7 @@ namespace Ark * @param value * @param context */ - inline void push(Value&& value, internal::ExecutionContext& context) noexcept; + inline ARK_ALWAYS_INLINE void push(Value&& value, internal::ExecutionContext& context) noexcept; /** * @brief Push a value on the stack as a reference @@ -311,7 +319,7 @@ namespace Ark * @param valptr * @param context */ - inline void push(Value* valptr, internal::ExecutionContext& context) noexcept; + inline ARK_ALWAYS_INLINE void push(Value* valptr, internal::ExecutionContext& context) noexcept; /** * @brief Pop a value from the stack and resolve it if possible, then return it @@ -319,7 +327,7 @@ namespace Ark * @param context * @return Value* */ - inline Value* popAndResolveAsPtr(internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE Value* popAndResolveAsPtr(internal::ExecutionContext& context); // ================================================ // locals related @@ -334,6 +342,10 @@ namespace Ark */ inline Value* findNearestVariable(uint16_t id, internal::ExecutionContext& context) noexcept; + // ================================================ + // function calls + // ================================================ + /** * @brief Destroy the current frame and get back to the previous one, resuming execution * @@ -342,7 +354,28 @@ namespace Ark * * @param context */ - inline void returnFromFuncCall(internal::ExecutionContext& context); + inline ARK_ALWAYS_INLINE void returnFromFuncCall(internal::ExecutionContext& context); + + /** + * @brief Function called when the CALL instruction is met in the bytecode + * + * @param context + * @param argc number of arguments already sent + * @param function_ptr optional pointer to the function to call. If not provided, obtain it from the stack (unless or_address is not 0) + * @param or_address optional page address, used if non-zero and function_ptr is nullptr + */ + inline ARK_ALWAYS_INLINE void call(internal::ExecutionContext& context, uint16_t argc, Value* function_ptr = nullptr, internal::PageAddr_t or_address = 0); + + /** + * @brief Builtin called when the CALL_BUILTIN instruction is met in the bytecode + * + * @param context + * @param builtin the builtin to call + * @param argc number of arguments already sent + * @param remove_return_address remove the return address pushed by the compiler + * @param remove_builtin remove the builtin that was pushed to the stack for the call + */ + inline ARK_ALWAYS_INLINE void callBuiltin(internal::ExecutionContext& context, const Value& builtin, uint16_t argc, bool remove_return_address = true, bool remove_builtin = true); /** * @brief Load a plugin from a constant id @@ -392,27 +425,6 @@ namespace Ark * @param colorize */ void backtrace(internal::ExecutionContext& context, std::ostream& os = std::cerr, bool colorize = true); - - /** - * @brief Function called when the CALL instruction is met in the bytecode - * - * @param context - * @param argc number of arguments already sent - * @param function_ptr optional pointer to the function to call. If not provided, obtain it from the stack (unless or_address is not 0) - * @param or_address optional page address, used if non-zero and function_ptr is nullptr - */ - inline void call(internal::ExecutionContext& context, uint16_t argc, Value* function_ptr = nullptr, internal::PageAddr_t or_address = 0); - - /** - * @brief Builtin called when the CALL_BUILTIN instruction is met in the bytecode - * - * @param context - * @param builtin the builtin to call - * @param argc number of arguments already sent - * @param remove_return_address remove the return address pushed by the compiler - * @param remove_builtin remove the builtin that was pushed to the stack for the call - */ - inline void callBuiltin(internal::ExecutionContext& context, const Value& builtin, uint16_t argc, bool remove_return_address = true, bool remove_builtin = true); }; #include "VM.inl" diff --git a/include/Ark/VM/VM.inl b/include/Ark/VM/VM.inl index 7bd2b7b0b..65dd3f78d 100644 --- a/include/Ark/VM/VM.inl +++ b/include/Ark/VM/VM.inl @@ -94,7 +94,7 @@ inline Value VM::resolve(internal::ExecutionContext* context, const std::vector< #pragma region "instruction helpers" -inline Value* VM::loadSymbol(const uint16_t id, internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE Value* VM::loadSymbol(const uint16_t id, internal::ExecutionContext& context) { context.last_symbol = id; if (Value* var = findNearestVariable(context.last_symbol, context); var != nullptr) [[likely]] @@ -109,7 +109,7 @@ inline Value* VM::loadSymbol(const uint16_t id, internal::ExecutionContext& cont return nullptr; } -inline Value* VM::loadSymbolFromIndex(const uint16_t index, internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE Value* VM::loadSymbolFromIndex(const uint16_t index, internal::ExecutionContext& context) { // we need to load symbols from the end, because function calls add a reference to the current function // upon calling it. Which changes the index by 1, making it less clear, because it needs special @@ -121,12 +121,12 @@ inline Value* VM::loadSymbolFromIndex(const uint16_t index, internal::ExecutionC return &value; } -inline Value* VM::loadConstAsPtr(const uint16_t id) const +inline ARK_ALWAYS_INLINE Value* VM::loadConstAsPtr(const uint16_t id) const { return &m_state.m_constants[id]; } -inline void VM::store(const uint16_t id, const Value* val, internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE void VM::store(const uint16_t id, const Value* val, internal::ExecutionContext& context) { // avoid adding the pair (id, _) multiple times, with different values Value* local = context.locals.back()[id]; @@ -136,7 +136,7 @@ inline void VM::store(const uint16_t id, const Value* val, internal::ExecutionCo *local = *val; } -inline void VM::setVal(const uint16_t id, const Value* val, internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE void VM::setVal(const uint16_t id, const Value* val, internal::ExecutionContext& context) { if (Value* var = findNearestVariable(id, context); var != nullptr) [[likely]] { @@ -154,7 +154,7 @@ inline void VM::setVal(const uint16_t id, const Value* val, internal::ExecutionC val->toString(*this))); } -inline void VM::jump(const uint16_t address, internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE void VM::jump(const uint16_t address, internal::ExecutionContext& context) { // instructions are on 4 bytes! context.ip = address * 4; @@ -164,7 +164,7 @@ inline void VM::jump(const uint16_t address, internal::ExecutionContext& context #pragma region "stack management" -inline Value* VM::pop(internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE Value* VM::pop(internal::ExecutionContext& context) { if (context.sp > 0) [[likely]] { @@ -174,7 +174,7 @@ inline Value* VM::pop(internal::ExecutionContext& context) return &m_undefined_value; } -inline Value* VM::peek(internal::ExecutionContext& context, const std::size_t offset) +inline ARK_ALWAYS_INLINE Value* VM::peek(internal::ExecutionContext& context, const std::size_t offset) { if (context.sp > offset) { @@ -184,7 +184,7 @@ inline Value* VM::peek(internal::ExecutionContext& context, const std::size_t of return &m_undefined_value; } -inline Value* VM::peekAndResolveAsPtr(internal::ExecutionContext& context, const std::size_t offset) +inline ARK_ALWAYS_INLINE Value* VM::peekAndResolveAsPtr(internal::ExecutionContext& context, const std::size_t offset) { if (context.sp > offset) { @@ -196,26 +196,26 @@ inline Value* VM::peekAndResolveAsPtr(internal::ExecutionContext& context, const return &m_undefined_value; } -inline void VM::push(const Value& value, internal::ExecutionContext& context) noexcept +inline ARK_ALWAYS_INLINE void VM::push(const Value& value, internal::ExecutionContext& context) noexcept { context.stack[context.sp] = value; ++context.sp; } -inline void VM::push(Value&& value, internal::ExecutionContext& context) noexcept +inline ARK_ALWAYS_INLINE void VM::push(Value&& value, internal::ExecutionContext& context) noexcept { context.stack[context.sp] = std::move(value); ++context.sp; } -inline void VM::push(Value* valptr, internal::ExecutionContext& context) noexcept +inline ARK_ALWAYS_INLINE void VM::push(Value* valptr, internal::ExecutionContext& context) noexcept { context.stack[context.sp].m_type = ValueType::Reference; context.stack[context.sp].m_value = valptr; ++context.sp; } -inline Value* VM::popAndResolveAsPtr(internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE Value* VM::popAndResolveAsPtr(internal::ExecutionContext& context) { Value* tmp = pop(context); if (tmp->valueType() == ValueType::Reference) @@ -235,14 +235,14 @@ inline Value* VM::findNearestVariable(const uint16_t id, internal::ExecutionCont return nullptr; } -inline void VM::returnFromFuncCall(internal::ExecutionContext& context) +inline ARK_ALWAYS_INLINE void VM::returnFromFuncCall(internal::ExecutionContext& context) { --context.fc; context.stacked_closure_scopes.pop_back(); context.locals.pop_back(); } -inline void VM::call(internal::ExecutionContext& context, const uint16_t argc, Value* function_ptr, const internal::PageAddr_t or_address) +inline ARK_ALWAYS_INLINE void VM::call(internal::ExecutionContext& context, const uint16_t argc, Value* function_ptr, const internal::PageAddr_t or_address) { using namespace internal; @@ -358,7 +358,7 @@ inline void VM::call(internal::ExecutionContext& context, const uint16_t argc, V throwArityError(argc, needed_argc, context, /* skip_function= */ function_ptr == nullptr); } -inline void VM::callBuiltin(internal::ExecutionContext& context, const Value& builtin, const uint16_t argc, const bool remove_return_address, const bool remove_builtin) +inline ARK_ALWAYS_INLINE void VM::callBuiltin(internal::ExecutionContext& context, const Value& builtin, const uint16_t argc, const bool remove_return_address, const bool remove_builtin) { using namespace Ark::literals; diff --git a/lib/std b/lib/std index 0faef4071..4e04827c4 160000 --- a/lib/std +++ b/lib/std @@ -1 +1 @@ -Subproject commit 0faef4071c91b62d84cfca0629e306e6c95da8b3 +Subproject commit 4e04827c4fadda5c6a57507e90da876a2e90d16a diff --git a/src/arkreactor/VM/ScopeView.cpp b/src/arkreactor/VM/ScopeView.cpp index 94869287a..4e85230ad 100644 --- a/src/arkreactor/VM/ScopeView.cpp +++ b/src/arkreactor/VM/ScopeView.cpp @@ -10,28 +10,6 @@ namespace Ark::internal m_storage(storage), m_start(start), m_size(0), m_min_id(MaxValue16Bits), m_max_id(0) {} - void ScopeView::pushBack(uint16_t id, Value&& val) noexcept - { - if (id < m_min_id) - m_min_id = id; - if (id > m_max_id) - m_max_id = id; - - m_storage[m_start + m_size] = std::make_pair(id, std::move(val)); - ++m_size; - } - - void ScopeView::pushBack(uint16_t id, const Value& val) noexcept - { - if (id < m_min_id) - m_min_id = id; - if (id > m_max_id) - m_max_id = id; - - m_storage[m_start + m_size] = std::make_pair(id, val); - ++m_size; - } - void ScopeView::insertFront(const std::vector& values) noexcept { const std::size_t offset_by = values.size(); @@ -62,11 +40,6 @@ namespace Ark::internal m_size += offset_by; } - bool ScopeView::maybeHas(const uint16_t id) const noexcept - { - return m_min_id <= id && id <= m_max_id; - } - Value* ScopeView::operator[](const uint16_t id_to_look_for) noexcept { if (!maybeHas(id_to_look_for)) diff --git a/src/arkreactor/VM/VM.cpp b/src/arkreactor/VM/VM.cpp index 988823256..dba3cd6b5 100644 --- a/src/arkreactor/VM/VM.cpp +++ b/src/arkreactor/VM/VM.cpp @@ -46,7 +46,7 @@ namespace Ark m_exit_code = 0; context.locals.clear(); - context.locals.reserve(128); + context.locals.reserve(64); context.locals.emplace_back(context.scopes_storage.data(), 0); // loading bound stuff @@ -321,14 +321,7 @@ namespace Ark else { // mark the used context as ready to be used again - for (std::size_t i = 1; i < m_execution_contexts.size(); ++i) - { - if (m_execution_contexts[i].get() == ec) - { - ec->setActive(false); - break; - } - } + ec->setActive(false); } } @@ -469,27 +462,22 @@ namespace Ark # define GOTO_HALT() break #endif -#define FETCH_NEXT_INSTRUCTION() \ - 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; \ - context.inst_exec_counter = (context.inst_exec_counter + 1) % VMOverflowBufferSize; \ - if constexpr (WithDebugger) \ - { \ - if (!m_debugger) initDebugger(context); \ - m_debugger->registerInstruction(static_cast((inst << 24) | (padding << 16) | arg)); \ - } \ - if (context.inst_exec_counter < 2 && context.sp >= VMStackSize) \ - { \ - if (context.pp != 0) \ - throw Error("Stack overflow. You could consider rewriting your function to make use of tail-call optimization."); \ - else \ - throw Error("Stack overflow. Are you trying to call a function with too many arguments?"); \ - } \ +#define FETCH_NEXT_INSTRUCTION() \ + 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; \ + context.inst_exec_counter = (context.inst_exec_counter + 1) % VMOverflowBufferSize; \ + if constexpr (WithDebugger) \ + { \ + if (!m_debugger) initDebugger(context); \ + m_debugger->registerInstruction(static_cast((inst << 24) | (padding << 16) | arg)); \ + } \ + if (context.inst_exec_counter < 2 && context.sp >= VMStackSize) \ + stackOverflowError(context); \ } while (false) #define DISPATCH() \ FETCH_NEXT_INSTRUCTION(); \ diff --git a/tests/benchmarks/results/015-2f53e79e.csv b/tests/benchmarks/results/015-2f53e79e.csv new file mode 100644 index 000000000..9d4858307 --- /dev/null +++ b/tests/benchmarks/results/015-2f53e79e.csv @@ -0,0 +1,11 @@ +name,iterations,real_time,cpu_time,time_unit,bytes_per_second,items_per_second,label,error_occurred,error_message +"quicksort",7777,0.0898954,0.0897916,ms,,,,, +"ackermann/iterations:50",50,30.3846,30.3572,ms,,,,, +"fibonacci/iterations:100",100,2.96052,2.95734,ms,,,,, +"builtins",1200,0.578368,0.577753,ms,,,,, +"binary_trees",1,840.857,839.947,ms,,,,, +"for_sum",9,77.2381,77.1461,ms,,,,, +"create_closure/iterations:500",500,0.753453,0.752774,ms,,,,, +"create_list/iterations:500",500,1.68291,1.68105,ms,,,,, +"create_list_with_ref/iterations:500",500,1.46395,1.46262,ms,,,,, +"n_queens/iterations:50",50,11.9545,11.9399,ms,,,,,