965 lines · 32.5 KB · C
RawDownload
//// Dis VM// File: runtime.h// Author: arr// #ifndef _DISVM_SRC_INCLUDE_RUNTIME_H_#define _DISVM_SRC_INCLUDE_RUNTIME_H_ #include <cstdint>#include <cassert>#include <atomic>#include <vector>#include <string>#include <memory>#include <deque>#include <unordered_map>#include <mutex>#include <functional>#include "opcodes.h" namespace disvm{    // Forward declaration    class vm_t;     namespace runtime    {        //        // VM primitive data type definitions        //         using byte_t = uint8_t;        using short_word_t = int16_t;        using word_t = int32_t;        using short_real_t = float;        using real_t = double;        using big_t = int64_t;        using pointer_t = std::size_t *;        using vm_pc_t = word_t;         //        // VM memory management        //         // Forward declaration        class vm_alloc_t;         // Finalizer callback for allocations.        using vm_alloc_instance_finalizer_t = void(*)(vm_alloc_t *);         // VM type description        class type_descriptor_t final        {        public: // static            static vm_alloc_instance_finalizer_t no_finalizer;             // Create a type descriptor for type of the supplied size and pointers based on the supplied map.            static std::shared_ptr<const type_descriptor_t> create(const word_t size_in_bytes);            static std::shared_ptr<const type_descriptor_t> create(const word_t size_in_bytes, const std::vector<byte_t> &pointer_map);            static std::shared_ptr<const type_descriptor_t> create(                const word_t size_in_bytes,                const word_t pointer_map_length,                const byte_t *pointer_map,                vm_alloc_instance_finalizer_t finalizer = type_descriptor_t::no_finalizer);         public:            type_descriptor_t(word_t size_in_bytes, word_t map_in_bytes, const byte_t * pointer_map, vm_alloc_instance_finalizer_t finalizer, const char *debug_name);            type_descriptor_t(const type_descriptor_t&) = delete;            type_descriptor_t& operator=(const type_descriptor_t&) = delete;             bool is_equal(const type_descriptor_t *) const;             const word_t size_in_bytes;            const word_t map_in_bytes;            const byte_t * const pointer_map;            const vm_alloc_instance_finalizer_t finalizer;#ifndef NDEBUG            const char *debug_type_name;#endif        };         // Access to type descriptors for VM intrinsic types        class intrinsic_type_desc final        {        public:            // Templated type descriptor getter            template<typename IntrinsicType>            static std::shared_ptr<const type_descriptor_t> type();        };         // VM memory allocation        class vm_alloc_t        {        public: // static            static void *operator new(std::size_t sz);            static void operator delete(void *ptr);             static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td);            static vm_alloc_t *copy(const vm_alloc_t &other);             static vm_alloc_t *from_allocation(pointer_t allocation)            {                if (allocation == nullptr)                    return nullptr;                 return reinterpret_cast<vm_alloc_t *>(reinterpret_cast<uint8_t *>(allocation) - sizeof(vm_alloc_t));            }             template <typename T>            static T *from_allocation(pointer_t allocation)            {                auto alloc_inst = vm_alloc_t::from_allocation(allocation);                assert(alloc_inst == nullptr || alloc_inst->alloc_type->is_equal(intrinsic_type_desc::type<T>().get()));                return static_cast<T *>(alloc_inst);            }         protected:            vm_alloc_t(std::shared_ptr<const type_descriptor_t> td);         public:            virtual ~vm_alloc_t();             std::size_t add_ref();            std::size_t release();            std::size_t get_ref_count() const;             std::shared_ptr<const type_descriptor_t> alloc_type;             // Reserved for use by the garbage collector.            // This should not be accessed by any other component.            pointer_t gc_reserved;         public:            pointer_t get_allocation() const            {                // Remove const on the this pointer so the offset can be computed.                auto non_const_this = const_cast<vm_alloc_t *>(this);                return reinterpret_cast<pointer_t>(reinterpret_cast<uint8_t *>(non_const_this) + sizeof(vm_alloc_t));            }             template <typename T>            T *get_allocation() const            {                return reinterpret_cast<T *>(get_allocation());            }         private:            std::atomic<std::size_t> _ref_count;        };         //        // VM intrinsic type definitions        //         // Type to contain the maximum UTF-8 character value        using rune_t = uint32_t;         // VM string type        class vm_string_t final : public vm_alloc_t        {        public: //static            static std::shared_ptr<const type_descriptor_t> type_desc();             // Compare two string objects            static int compare(const vm_string_t *s1, const vm_string_t *s2);         public:            vm_string_t();            vm_string_t(std::size_t encoded_str_len, const uint8_t *encoded_str);            vm_string_t(const vm_string_t &s1, const vm_string_t &s2);            vm_string_t(const vm_string_t &other, word_t begin_index, word_t end_index);            vm_string_t(const vm_string_t &) = delete;            ~vm_string_t();             // Returns this string.            vm_string_t &append(const vm_string_t &other);             // Returns the character length of the string.            word_t get_length() const;             rune_t get_rune(word_t index) const;             void set_rune(word_t index, rune_t value);             int compare_to(const vm_string_t *s) const;             const char *str() const;         private:            word_t _length;            word_t _length_max;            mutable std::mutex _encoded_str_lock;            mutable char *_encoded_str;            mutable union string_memory_t            {                uint8_t local[16]; // Optimization for short strings                uint8_t *alloc;            } _mem;             uint8_t _character_size; // 1 byte (ASCII) or 4 bytes (multi-byte)            bool _is_alloc;        };         // VM array type        class vm_array_t final : public vm_alloc_t        {        public: //static            static std::shared_ptr<const type_descriptor_t> type_desc();         public:            vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t length);            vm_array_t(vm_array_t &original, word_t begin_index, word_t length);            vm_array_t(const vm_string_t *s);            ~vm_array_t();             std::shared_ptr<const type_descriptor_t> get_element_type() const;             word_t get_length() const;             pointer_t at(word_t index) const;             template<typename T>            T& at(word_t index) const            {                return *reinterpret_cast<T *>(at(index));            }             // Copy the contents of the source array into this array starting at index            void copy_from(const vm_array_t &source, word_t this_begin_index);         private:            std::shared_ptr<const type_descriptor_t> _element_type;            vm_array_t *_original;            word_t _length;            byte_t *_arr;        };         // VM list type        class vm_list_t final : public vm_alloc_t        {        public: //static            static std::shared_ptr<const type_descriptor_t> type_desc();         public:            vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail = nullptr);            ~vm_list_t();             std::shared_ptr<const type_descriptor_t> get_element_type() const;             word_t get_length() const;             vm_list_t* get_tail() const;             void set_tail(vm_list_t *new_tail);             // Returns a pointer to the value            pointer_t value() const;         private:            std::shared_ptr<const type_descriptor_t> _element_type;            vm_list_t *_tail;             // Utilizing a union so that all value types can             // be stored without allocating any extra memory.            mutable union element_memory_t            {                pointer_t alloc;                uint64_t local;            } _mem;             const bool _is_alloc;        };         // Forward declaration        class vm_channel_t;         // VM request mutex        struct vm_request_mutex_t        {            vm_request_mutex_t();             std::mutex pending_request_lock;            bool pending_request;        };         // VM channel request        class vm_channel_request_t final        {        public:            // Create a request using the ID of the requesting thread and an associated request mutex.            vm_channel_request_t(uint32_t thread_id, vm_request_mutex_t &request_mutex);             uint32_t thread_id;             // Callback used to indicate the request was handled in the supplied channel.            // This is only called in the event the request was not immediately serviced.            std::function<void(const vm_channel_t &)> request_handled_callback;             // Data of the request            pointer_t data;             std::reference_wrapper<vm_request_mutex_t> request_mutex;        };         // VM channel type        class vm_channel_t final : public vm_alloc_t        {        public: //static            static std::shared_ptr<const type_descriptor_t> type_desc();             using data_transfer_func_t = void(*)(pointer_t, pointer_t, const type_descriptor_t *);         public:            vm_channel_t(                std::shared_ptr<const type_descriptor_t> td,                data_transfer_func_t transfer,                word_t buffer_len);            ~vm_channel_t();             std::shared_ptr<const type_descriptor_t> get_data_type() const;             // Send data into the channel.            // Returns true if the data was sent, otherwise request is queued and false returned.            bool send_data(vm_channel_request_t &send_request);             // Receive data from the channel.            // Returns true if data was received, otherwise request is queued and false returned.            bool receive_data(vm_channel_request_t &receive_request);             // Cancel an outstanding request from a thread.            void cancel_request(uint32_t thread_id);             word_t get_buffer_size() const;         private:            // Try to send data into the channel buffer.            // Returns true if data was sent to buffer, otherwise false.            bool try_send_to_buffer(vm_channel_request_t &send_request);             // Try to receive data from the channel buffer.            // Returns true if data was received from buffer, otherwise false.            bool try_receive_from_buffer(vm_channel_request_t &receive_request);         private:            std::mutex _data_lock;            std::shared_ptr<const type_descriptor_t> _data_type;            data_transfer_func_t _data_transfer;             vm_array_t *_data_buffer;            uint32_t _data_buffer_head; // Next element to remove from buffer            uint32_t _data_buffer_count; // Count of elements in buffer             using request_queue_t = std::deque<vm_channel_request_t>;            request_queue_t _data_senders;            request_queue_t _data_receivers;        };         // Alt channel entry.        static_assert(sizeof(word_t) == sizeof(pointer_t), "Alt channel stack layout will be invalid.");        struct vm_alt_channel_stack_layout_t        {            word_t alloc;            word_t data;        };         // Alt channel layout as defined by the specification for the 'alt' instruction.        struct vm_alt_stack_layout_t        {            word_t send_count;            word_t receive_count;            vm_alt_channel_stack_layout_t channels[1];        };         // Runtime constants        namespace runtime_constants        {            const auto nil = std::size_t{ 0 };             const auto invalid_program_counter = vm_pc_t{ ~0 };        };         // Addressing mode for middle instruction data        enum class address_mode_middle_t        {            none = 0,            small_immediate = 1,            small_offset_indirect_fp = 2,            small_offset_indirect_mp = 3,        };         // Middle instruction data        struct middle_data_t        {            address_mode_middle_t mode;            word_t register1;        };         // Addressing mode for source and destination instruction data        enum class address_mode_t        {            offset_indirect_mp = 0,            offset_indirect_fp = 1,            immediate = 2,            none = 3,            offset_double_indirect_mp = 4,            offset_double_indirect_fp = 5,            reserved_1 = 6,            reserved_2 = 7,        };         // Source and destination instruction data        struct inst_data_generic_t        {            address_mode_t mode;            word_t register1;            word_t register2;        };         using src_data_t = inst_data_generic_t;        using dest_data_t = inst_data_generic_t;         // Forward declaration        class vm_registers_t;         // Instruction execution operation        using vm_exec_t = void(*)(vm_registers_t &, vm_t &);         // Addressing code - defines addressing mode for all registers        // bit  7  6  5  4  3  2  1  0        //     m1 m0 s2 s1 s0 d2 d1 d0        using addr_code_t = uint8_t;         // Opcode execution operation        struct vm_exec_op_t        {            opcode_t opcode;            addr_code_t addr_code;            src_data_t source;            middle_data_t middle;            dest_data_t destination;        };         // VM Instruction (code section of module)        union vm_instruction_t        {            vm_exec_op_t op;            vm_exec_t native;        };         // Flags that dictate the runtime operations of the module        // [SPEC] Values past 'shared_module' are not fully documented.        enum class runtime_flags_t        {            must_compile = 1 << 0,            dont_compile = 1 << 1,            share_module = 1 << 2, // [TODO] Respect this setting            reserved_1 = 1 << 3, // DYNMOD            has_import_deprecated = 1 << 4,            has_handler = 1 << 5,            has_import = 1 << 6,             // [SPEC] Added to handle built-in modules            builtin = 1 << 7,        };         // Module header        struct header_t        {            word_t magic_number;            struct            {                word_t length;                std::unique_ptr<byte_t[]> signature;            } Signature;             runtime_flags_t runtime_flag;            word_t stack_extent;            word_t code_size;            word_t data_size;            word_t type_size;            word_t export_size;            vm_pc_t entry_pc;            word_t entry_type; // Stack frame type        };         // Export function entry        struct export_function_t        {            export_function_t() = default;            export_function_t(export_function_t &&);             export_function_t(const export_function_t &) = delete;            export_function_t &operator=(const export_function_t &) = delete;             ~export_function_t();             vm_pc_t pc;            word_t frame_type;            word_t sig;

Lines 1–500 of 965.