History

Initial public commit for Dis VM

arr committed 10 years ago

Commit f95902eNo parent (first commit)40 files · +9358 −0Browse files

Showing the changes to src/include/runtime.h (1 of 40 files). Show all

Unified · Split

src/include/runtime.h+846−0
@@ -0,0 +1,846 @@
1+//
2+// Dis VM
3+// File: runtime.h
4+// Author: arr
5+//
6+
7+#ifndef _DISVM_SRC_INCLUDE_RUNTIME_H_
8+#define _DISVM_SRC_INCLUDE_RUNTIME_H_
9+
10+#include <cstdint>
11+#include <cassert>
12+#include <atomic>
13+#include <vector>
14+#include <string>
15+#include <memory>
16+#include <deque>
17+#include <unordered_map>
18+#include <mutex>
19+#include <functional>
20+#include "opcodes.h"
21+
22+namespace disvm
23+{
24+ // VM forward declation
25+ class vm_t;
26+
27+ namespace runtime
28+ {
29+ //
30+ // VM primitive data type definitions
31+ //
32+
33+ using byte_t = uint8_t;
34+ using short_word_t = int16_t;
35+ using word_t = int32_t;
36+ using short_real_t = float;
37+ using real_t = double;
38+ using big_t = int64_t;
39+ using pointer_t = std::size_t *;
40+ using vm_pc_t = word_t;
41+
42+ //
43+ // VM memory management
44+ //
45+
46+ // VM forward declation
47+ class vm_alloc_t;
48+
49+ // Finalizer callback for allocations.
50+ using vm_alloc_instance_finalizer_t = void(*)(vm_alloc_t *);
51+
52+ // VM type description
53+ class type_descriptor_t final
54+ {
55+ public: // static
56+ static vm_alloc_instance_finalizer_t no_finalizer;
57+
58+ // Create a type descriptor for type of the supplied size and pointers based on the supplied map.
59+ static std::shared_ptr<const type_descriptor_t> create(const word_t size);
60+ static std::shared_ptr<const type_descriptor_t> create(const word_t size, const std::vector<byte_t> &pointer_map);
61+ static std::shared_ptr<const type_descriptor_t> create(
62+ const word_t size,
63+ const word_t pointer_map_length,
64+ const byte_t *pointer_map,
65+ vm_alloc_instance_finalizer_t finalizer = type_descriptor_t::no_finalizer);
66+
67+ private:
68+ type_descriptor_t(word_t size_in_bytes, word_t map_in_bytes, const byte_t * pointer_map, vm_alloc_instance_finalizer_t finalizer);
69+
70+ public:
71+ type_descriptor_t(const type_descriptor_t&) = delete;
72+ type_descriptor_t& operator=(const type_descriptor_t&) = delete;
73+
74+ const word_t size_in_bytes;
75+ const word_t map_in_bytes;
76+ const byte_t * const pointer_map;
77+ const vm_alloc_instance_finalizer_t finalizer;
78+ };
79+
80+ // Access to type descriptors for VM intrinsic types.
81+ class intrinsic_type_desc final
82+ {
83+ private:
84+ friend vm_t;
85+ static std::atomic_bool is_initialized;
86+ static void initialize();
87+
88+ public:
89+ // Templated type descriptor getter
90+ template<typename IntrinsicType>
91+ static std::shared_ptr<const type_descriptor_t> type();
92+ };
93+
94+ // Type used to indicate allocated memory should be zeroed out.
95+ struct zero_memory_t
96+ { };
97+
98+ // VM memory allocation
99+ class vm_alloc_t
100+ {
101+ public: // static
102+ static const zero_memory_t zero_memory;
103+
104+ static void *operator new(std::size_t sz);
105+ static void operator delete(void *ptr);
106+
107+ static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td);
108+ static vm_alloc_t *allocate(std::shared_ptr<const type_descriptor_t> td, const zero_memory_t &);
109+ static vm_alloc_t *copy(const vm_alloc_t &other);
110+ static vm_alloc_t *from_allocation(pointer_t allocation);
111+
112+ template <typename T>
113+ static T *from_allocation(pointer_t allocation)
114+ {
115+ auto alloc_inst = vm_alloc_t::from_allocation(allocation);
116+ assert(alloc_inst == nullptr || alloc_inst->alloc_type == intrinsic_type_desc::type<T>());
117+ return dynamic_cast<T *>(alloc_inst);
118+ }
119+
120+ protected:
121+ vm_alloc_t(std::shared_ptr<const type_descriptor_t> td);
122+
123+ public:
124+ virtual ~vm_alloc_t();
125+
126+ std::size_t add_ref();
127+ std::size_t release();
128+ std::size_t get_ref_count() const;
129+
130+ std::shared_ptr<const type_descriptor_t> alloc_type;
131+
132+ // Reserved for use by the garbage collector.
133+ // This should not be accessed by any other component.
134+ pointer_t gc_reserved;
135+
136+ public:
137+ pointer_t allocation() const;
138+
139+ private:
140+ std::atomic<std::size_t> _ref_count;
141+ };
142+
143+ //
144+ // VM intrinsic type definitions
145+ //
146+
147+ // Type to contain the maximum UTF-8 character value
148+ using rune_t = uint32_t;
149+
150+ // VM string type
151+ class vm_string_t final : public vm_alloc_t
152+ {
153+ public: //static
154+ static std::shared_ptr<const type_descriptor_t> type_desc();
155+
156+ // Compare two string objects
157+ static int compare(const vm_string_t *s1, const vm_string_t *s2);
158+
159+ public:
160+ vm_string_t();
161+ vm_string_t(std::size_t encoded_str_len, const uint8_t *encoded_str);
162+ vm_string_t(const vm_string_t &s1, const vm_string_t &s2);
163+ vm_string_t(const vm_string_t &other, word_t begin_index, word_t end_index);
164+ vm_string_t(const vm_string_t &) = delete;
165+ ~vm_string_t();
166+
167+ // Returns this string.
168+ vm_string_t &append(const vm_string_t &other);
169+
170+ word_t get_length() const;
171+
172+ rune_t get_rune(word_t index) const;
173+
174+ void set_rune(word_t index, rune_t value);
175+
176+ int compare_to(const vm_string_t *s) const;
177+
178+ const char *str() const;
179+
180+ private:
181+ word_t _length;
182+ word_t _length_max;
183+ mutable std::mutex _encoded_str_lock;
184+ mutable char *_encoded_str;
185+ mutable union string_memory_t
186+ {
187+ uint8_t local[16]; // Optimization for short strings
188+ uint8_t *alloc;
189+ } _mem;
190+
191+ uint8_t _character_size; // 1 byte (ASCII) or 4 bytes (multi-byte)
192+ bool _is_alloc;
193+ };
194+
195+ // VM array type
196+ class vm_array_t final : public vm_alloc_t
197+ {
198+ public: //static
199+ static std::shared_ptr<const type_descriptor_t> type_desc();
200+
201+ public:
202+ vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t count);
203+ vm_array_t(std::shared_ptr<const type_descriptor_t> td, word_t count, const zero_memory_t&);
204+ vm_array_t(vm_array_t *original, word_t begin_index, word_t count);
205+ vm_array_t(const vm_string_t *s);
206+ ~vm_array_t();
207+
208+ std::shared_ptr<const type_descriptor_t> get_element_type() const;
209+
210+ word_t get_length() const;
211+
212+ pointer_t at(word_t index) const;
213+
214+ template<typename T>
215+ T& at(word_t index) const
216+ {
217+ return *reinterpret_cast<T *>(at(index));
218+ }
219+
220+ // Copy the contents of the source array into this array starting at index
221+ void copy_from(const vm_array_t &source, word_t this_begin_index);
222+
223+ private:
224+ std::shared_ptr<const type_descriptor_t> _element_type;
225+ vm_array_t *_original;
226+ word_t _length;
227+ byte_t *_arr;
228+ };
229+
230+ // VM list type
231+ class vm_list_t final : public vm_alloc_t
232+ {
233+ public: //static
234+ static std::shared_ptr<const type_descriptor_t> type_desc();
235+
236+ public:
237+ vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tail = nullptr);
238+ ~vm_list_t();
239+
240+ std::shared_ptr<const type_descriptor_t> get_element_type() const;
241+
242+ word_t get_length() const;
243+
244+ vm_list_t* get_tail() const;
245+
246+ vm_list_t* drop_tail();
247+
248+ // Returns a pointer to the value
249+ pointer_t value() const;
250+
251+ private:
252+ std::shared_ptr<const type_descriptor_t> _element_type;
253+ vm_list_t *_tail;
254+
255+ // Utilizing a union so that all value types can
256+ // be stored without allocating any extra memory.
257+ mutable union element_memory_t
258+ {
259+ pointer_t alloc;
260+ uint64_t local;
261+ } _mem;
262+
263+ const bool _is_alloc;
264+ };
265+
266+ // VM forward declation
267+ class vm_channel_t;
268+
269+ // VM request mutex
270+ struct vm_request_mutex_t
271+ {
272+ vm_request_mutex_t();
273+
274+ std::mutex pending_request_lock;
275+ bool pending_request;
276+ };
277+
278+ // VM channel request
279+ class vm_channel_request_t final
280+ {
281+ public:
282+ // Create a request using the ID of the requesting thread and an associated request mutex.
283+ vm_channel_request_t(uint32_t thread_id, vm_request_mutex_t &request_mutex);
284+
285+ uint32_t thread_id;
286+
287+ // Callback used to indicate the request was handled in the supplied channel.
288+ // This is only called in the event the request was not immediately serviced.
289+ std::function<void(const vm_channel_t &)> request_handled_callback;
290+
291+ // Data of the request
292+ pointer_t data;
293+
294+ std::reference_wrapper<vm_request_mutex_t> request_mutex;
295+ };
296+
297+ // VM channel type
298+ class vm_channel_t final : public vm_alloc_t
299+ {
300+ public: //static
301+ static std::shared_ptr<const type_descriptor_t> type_desc();
302+
303+ public:
304+ vm_channel_t(
305+ std::shared_ptr<const type_descriptor_t> td,
306+ std::function<void(pointer_t, pointer_t, const type_descriptor_t *)> transfer,
307+ word_t buffer_len);
308+ ~vm_channel_t();
309+
310+ std::shared_ptr<const type_descriptor_t> get_data_type() const;
311+
312+ // Send data into the channel.
313+ // Returns true if the data was sent, otherwise request is queued and false returned.
314+ bool send_data(vm_channel_request_t &send_request);
315+
316+ // Receive data from the channel.
317+ // Returns true if data was received, otherwise request is queued and false returned.
318+ bool receive_data(vm_channel_request_t &receive_request);
319+
320+ // Cancel an outstanding request from a thread.
321+ void cancel_request(uint32_t thread_id);
322+
323+ private:
324+ // Try to send data into the channel buffer.
325+ // Returns true if data was sent to buffer, otherwise false.
326+ bool try_send_to_buffer(vm_channel_request_t &send_request);
327+
328+ // Try to receive data from the channel buffer.
329+ // Returns true if data was received from buffer, otherwise false.
330+ bool try_receive_from_buffer(vm_channel_request_t &receive_request);
331+
332+ private:
333+ std::mutex _data_lock;
334+ std::shared_ptr<const type_descriptor_t> _data_type;
335+ std::function<void(pointer_t, pointer_t, const type_descriptor_t *)> _data_transfer;
336+
337+ vm_array_t *_data_buffer;
338+ uint32_t _data_buffer_head; // Next element to remove from buffer
339+ uint32_t _data_buffer_count; // Count of elements in buffer
340+
341+ using request_queue_t = std::deque<vm_channel_request_t>;
342+ request_queue_t _data_senders;
343+ request_queue_t _data_receivers;
344+ };
345+
346+ // Alt channel entry.
347+ static_assert(sizeof(word_t) == sizeof(pointer_t), "Alt channel stack layout will be invalid.");
348+ struct vm_alt_channel_stack_layout_t
349+ {
350+ word_t alloc;
351+ word_t data;
352+ };
353+
354+ // Alt channel layout as defined by the specification for the 'alt' instruction.
355+ struct vm_alt_stack_layout_t
356+ {
357+ word_t send_count;
358+ word_t receive_count;
359+ vm_alt_channel_stack_layout_t channels[1];
360+ };
361+
362+ // Runtime constants
363+ struct runtime_constants
364+ {
365+ static const auto nil = std::size_t{ 0 };
366+
367+ static const auto invalid_program_counter = vm_pc_t{ ~0 };
368+
369+ static const auto default_register_count = std::size_t{ 4 };
370+ static const auto default_register_size_bytes = sizeof(word_t);
371+
372+ // See VM frame definition
373+ static const auto fixed_point_register_1_frame_offset = std::size_t{ default_register_count * default_register_size_bytes };
374+ static const auto fixed_point_register_2_frame_offset = fixed_point_register_1_frame_offset + (2 * default_register_size_bytes);
375+ };
376+
377+ // Addressing mode for middle instruction data
378+ enum class address_mode_middle_t
379+ {
380+ none = 0,
381+ small_immediate = 1,
382+ small_offset_indirect_fp = 2,
383+ small_offset_indirect_mp = 3,
384+ };
385+
386+ // Middle instruction data
387+ struct middle_data_t
388+ {
389+ address_mode_middle_t mode;
390+ word_t register1;
391+ };
392+
393+ // Addressing mode for source and destination instruction data
394+ enum class address_mode_t
395+ {
396+ offset_indirect_mp = 0,
397+ offset_indirect_fp = 1,
398+ immediate = 2,
399+ none = 3,
400+ offset_double_indirect_mp = 4,
401+ offset_double_indirect_fp = 5,
402+ reserved_1 = 6,
403+ reserved_2 = 7,
404+ };
405+
406+ // Source and destination instruction data
407+ struct inst_data_generic_t
408+ {
409+ address_mode_t mode;
410+ word_t register1;
411+ word_t register2;
412+ };
413+
414+ using src_data_t = inst_data_generic_t;
415+ using dest_data_t = inst_data_generic_t;
416+
417+ // VM forward declation
418+ class vm_registers_t;
419+
420+ // Instruction execution operation
421+ using vm_exec_t = void(*)(vm_registers_t &, vm_t &);
422+
423+ // Opcode execution operation
424+ struct vm_exec_op_t
425+ {
426+ opcode_t opcode;
427+ src_data_t source;
428+ middle_data_t middle;
429+ dest_data_t destination;
430+ };
431+
432+ // VM Instruction (code section of module)
433+ union vm_instruction_t
434+ {
435+ vm_exec_op_t op;
436+ vm_exec_t native;
437+ };
438+
439+ // Flags that dictate the runtime operations of the module
440+ // [SPEC] Values past 'shared_module' are not fully documented.
441+ enum class runtime_flags_t
442+ {
443+ must_compile = 1 << 0,
444+ dont_compile = 1 << 1,
445+ share_module = 1 << 2, // [TODO] Respect this setting
446+ reserved_1 = 1 << 3, // DYNMOD
447+ has_import_deprecated = 1 << 4,
448+ has_handler = 1 << 5,
449+ has_import = 1 << 6,
450+
451+ builtin = 1 << 7,
452+ };
453+
454+ // Module header
455+ struct header_t
456+ {
457+ word_t magic_number;
458+ struct
459+ {
460+ word_t length;
461+ std::unique_ptr<byte_t[]> signature;
462+ } Signature;
463+
464+ runtime_flags_t runtime_flag;
465+ word_t stack_extent;
466+ word_t code_size;
467+ word_t data_size;
468+ word_t type_size;
469+ word_t export_size;
470+ vm_pc_t entry_pc;
471+ word_t entry_type; // Stack frame type
472+ };
473+
474+ // Export function entry
475+ struct export_function_t
476+ {
477+ export_function_t() = default;
478+ export_function_t(export_function_t &&);
479+
480+ export_function_t(const export_function_t &) = delete;
481+ export_function_t &operator=(const export_function_t &) = delete;
482+
483+ ~export_function_t();
484+
485+ vm_pc_t pc;
486+ word_t frame_type;
487+ word_t sig;
488+ std::unique_ptr<vm_string_t> name;
489+ };
490+
491+ // Import function entry
492+ struct import_function_t
493+ {
494+ import_function_t() = default;
495+ import_function_t(import_function_t &&);
496+
497+ import_function_t(const import_function_t &) = delete;
498+ import_function_t &operator=(const import_function_t &) = delete;
499+
500+ ~import_function_t();
501+
502+ word_t sig;
503+ std::unique_ptr<vm_string_t> name;
504+ };
505+
506+ // Import table for module
507+ struct import_vm_module_t
508+ {
509+ import_vm_module_t() = default;
510+ import_vm_module_t(import_vm_module_t &&);
511+
512+ import_vm_module_t(const import_vm_module_t &) = delete;
513+ import_vm_module_t &operator=(const import_vm_module_t &) = delete;
514+
515+ ~import_vm_module_t() = default;
516+
517+ std::vector<import_function_t> functions;
518+ };
519+
520+ // Exception entry for handler
521+ struct exception_t
522+ {
523+ exception_t() = default;
524+ exception_t(exception_t &&);
525+
526+ exception_t(const exception_t &) = delete;
527+ exception_t &operator=(const exception_t &) = delete;
528+
529+ ~exception_t();
530+
531+ vm_pc_t pc;
532+ std::unique_ptr<vm_string_t> name;
533+ };
534+
535+ // Exception handler
536+ struct handler_t
537+ {
538+ handler_t() = default;
539+ handler_t(handler_t &&);
540+
541+ handler_t(const handler_t &) = delete;
542+ handler_t &operator=(const handler_t &) = delete;
543+
544+ ~handler_t() = default;
545+
546+ // Byte offset in the handling frame the exception should be placed.
547+ word_t exception_offset;
548+ vm_pc_t begin_pc;
549+ vm_pc_t end_pc;
550+
551+ // Number of cases in exception table where the caught exception is of exception type.
552+ // See exceptions in Limbo language for details.
553+ word_t exception_type_count;
554+
555+ std::shared_ptr<const type_descriptor_t> type_desc;
556+ std::vector<exception_t> exception_table;
557+ };
558+
559+ using code_section_t = std::vector<vm_instruction_t>;
560+ using type_section_map_t = std::vector<std::shared_ptr<const type_descriptor_t>>;
561+ using export_section_t = std::unordered_multimap<word_t, const export_function_t>;
562+ using import_section_t = std::vector<import_vm_module_t>;
563+ using handler_section_t = std::vector<handler_t>;
564+
565+ // VM module
566+ struct vm_module_t
567+ {
568+ vm_module_t() = default;
569+ vm_module_t(const vm_module_t &) = delete;
570+ vm_module_t &operator=(const vm_module_t &) = delete;
571+
572+ ~vm_module_t();
573+
574+ // Contains a magic number, digital signature, runtime flags, sizes of the other sections, and a description of the entry point
575+ header_t header;
576+
577+ // Describes a sequence of instructions for the virtual machine
578+ code_section_t code_section;
579+
580+ // template module pointer
581+ std::unique_ptr<vm_alloc_t> original_mp;
582+
583+ // Type descriptors describing the layout of pointers within data types
584+ type_section_map_t type_section;
585+
586+ // Module name
587+ std::unique_ptr<vm_string_t> module_name;
588+
589+ // List of functions exported by this module
590+ export_section_t export_section;
591+
592+ // List of all functions imported from other modules
593+ import_section_t import_section;
594+
595+ // Lists all exception handlers declared in the module
596+ handler_section_t handler_section;
597+ };
598+
599+ // Reference to a function in an imported module.
600+ struct vm_module_function_ref_t
601+ {
602+ vm_pc_t entry_pc;
603+ word_t frame_type;
604+ };
605+
606+ // Reference to a module
607+ class vm_module_ref_t final : public vm_alloc_t
608+ {
609+ public: //static
610+ static std::shared_ptr<const type_descriptor_t> type_desc();
611+
612+ public:
613+ vm_module_ref_t(std::shared_ptr<const vm_module_t> module);
614+ vm_module_ref_t(std::shared_ptr<const vm_module_t> module, const import_vm_module_t &imports);
615+ ~vm_module_ref_t();
616+
617+ std::shared_ptr<const vm_module_t> module;
618+ vm_alloc_t *mp_base;
619+ const code_section_t &code_section;
620+ const type_section_map_t &type_section;
621+
622+ bool is_builtin_module() const;
623+ const vm_module_function_ref_t& get_function_ref(word_t index) const;
624+
625+ private:
626+ const bool _builtin_module;
627+ std::unique_ptr<vm_array_t> _function_refs;
628+ };
629+
630+ // VM stack frame
631+ class vm_frame_t final
632+ {
633+ public:
634+ vm_frame_t(std::shared_ptr<const type_descriptor_t> &frame_type);
635+ ~vm_frame_t();
636+
637+ std::shared_ptr<const type_descriptor_t> frame_type;
638+
639+ // Copy the frame contents
640+ void copy_frame_contents(const vm_frame_t &other);
641+
642+ // Pointer to the base of the frame.
643+ pointer_t base() const;
644+
645+ template<typename T>
646+ T& base() const
647+ {
648+ return *reinterpret_cast<T *>(base());
649+ }
650+
651+ vm_pc_t &prev_pc() const;
652+ vm_frame_t *&prev_frame() const;
653+
654+ // This is only set if this frame represents a module transition.
655+ vm_module_ref_t *&prev_module_ref() const;
656+
657+ // Fixed point register positions in frame
658+ // [SPEC] These are not defined in the vm spec.
659+
660+ // 'Stmp' in libinterp/xec.c
661+ pointer_t fixed_point_register_1() const;
662+
663+ // 'Dtmp' in libinterp/xec.c
664+ pointer_t fixed_point_register_2() const;
665+ };
666+
667+ // Callback for stack walk.
668+ // Returning 'false' during the stack walk will terminate the walk.
669+ // The second parameter is reserved for internal use by the VM and should not be manipulated.
670+ using vm_stack_walk_callback_t = std::function<bool(const vm_frame_t *f, const void *reserved)>;
671+
672+ // VM stack
673+ class vm_stack_t final
674+ {
675+ public:
676+ vm_stack_t(std::size_t stack_extent);
677+ ~vm_stack_t();
678+
679+ // Allocate a new frame instance.
680+ vm_frame_t *alloc_frame(std::shared_ptr<const type_descriptor_t> frame_type);
681+
682+ // Push the latest allocated frame as the new top frame.
683+ vm_frame_t *push_frame();
684+
685+ // Remove the top frame and return the next frame in the stack.
686+ vm_frame_t *pop_frame();
687+
688+ // Return the current top frame.
689+ vm_frame_t *peek_frame() const;
690+
691+ // Walk the stack getting a callback for each frame.
692+ // This function is __not__ thread safe.
693+ void walk_stack(vm_stack_walk_callback_t callback) const;
694+
695+ private:
696+ std::unique_ptr<vm_alloc_t> _mem;
697+ };
698+
699+ // Walk the supplied stack and faulting module find the handler, handling stack frame, and program counter for the supplied exception ID.
700+ // If an exception handler cannot be found an 'unhandled_user_exception' exception will be thrown.
701+ std::tuple<const handler_t *, vm_frame_t *, vm_pc_t> find_exception_handler(
702+ const vm_stack_t &stack,
703+ const vm_module_ref_t &faulting_module,
704+ const vm_pc_t faulting_pc,
705+ const vm_string_t &exception_id);
706+
707+ // VM thread states
708+ enum class vm_thread_state_t
709+ {
710+ unknown = 0,
711+
712+ blocked_in_alt, // blocked in alt instruction
713+ blocked_sending, // blocked waiting to send
714+ blocked_receiving, // blocked waiting to receive
715+
716+ debug, // thread is running under a debugger
717+ ready, // ready to run
718+ running,
719+
720+ release, // interpreter released - executing non-vm instructions
721+
722+ exiting, // exit instruction
723+ empty_stack,
724+
725+ broken, // thread crashed
726+ };
727+
728+ // Forward declaration
729+ class vm_thread_t;
730+
731+ // VM registers
732+ class vm_registers_t
733+ {
734+ public:
735+ vm_registers_t(
736+ const vm_thread_t &thread,
737+ vm_module_ref_t &entry);
738+ ~vm_registers_t();
739+
740+ const vm_thread_t &thread;
741+ vm_stack_t stack; // Frame pointer access (FP)
742+ vm_pc_t pc; // Program counter (Index into module code section)
743+ vm_alloc_t *mp_base; // Module data base pointer (MP)
744+ vm_module_ref_t *module_ref; // Module reference
745+ vm_request_mutex_t request_mutex;
746+ vm_thread_state_t current_thread_state;
747+ pointer_t src;
748+ pointer_t mid;
749+ pointer_t dest;
750+ };
751+
752+ // VM thread
753+ class vm_thread_t final : public vm_alloc_t
754+ {
755+ public: //static
756+ static std::shared_ptr<const type_descriptor_t> type_desc();
757+
758+ public:
759+ vm_thread_t(
760+ vm_module_ref_t &entry,
761+ uint32_t parent_thread_id);
762+ vm_thread_t(
763+ vm_module_ref_t &entry,
764+ const vm_frame_t &initial_frame,
765+ vm_pc_t start_pc,
766+ uint32_t parent_thread_id);
767+
768+ ~vm_thread_t();
769+
770+ vm_thread_state_t execute(vm_t &virtual_machine, uint32_t quanta);
771+
772+ vm_thread_state_t get_state() const;
773+
774+ uint32_t get_thread_id() const;
775+
776+ uint32_t get_parent_thread_id() const;
777+
778+ const vm_registers_t& get_registers() const;
779+
780+ private:
781+ const uint32_t _thread_id;
782+ const uint32_t _parent_thread_id;
783+ vm_registers_t _registers;
784+ };
785+
786+ //
787+ // VM interfaces
788+ //
789+
790+ // VM thread scheduler control interface
791+ class vm_scheduler_control_t
792+ {
793+ public:
794+ virtual ~vm_scheduler_control_t() = 0;
795+
796+ // Indicates the scheduler should enqueue the blocked thread with the supplied ID.
797+ // There is no indication if this function failed or succeeded.
798+ virtual void enqueue_blocked_thread(uint32_t thread_id) = 0;
799+
800+ // Get all VM threads
801+ virtual std::vector<std::shared_ptr<const vm_thread_t>> get_all_threads() const = 0;
802+ };
803+
804+ // VM thread scheduler interface
805+ class vm_scheduler_t
806+ {
807+ public:
808+ virtual ~vm_scheduler_t() = 0;
809+
810+ // Returns true if there are no vm threads executing, scheduled to be executed, or blocked.
811+ virtual bool is_idle() const = 0;
812+
813+ // Get controller
814+ virtual vm_scheduler_control_t &get_controller() const = 0;
815+
816+ // Schedule the supplied thread for execution
817+ virtual const vm_thread_t& schedule_thread(std::unique_ptr<vm_thread_t> thread) = 0;
818+ };
819+
820+ // VM garbage collector interface
821+ class vm_garbage_collector_t
822+ {
823+ public:
824+ // The supplied allocation is guaranteed to be valid for the lifetime of the callback.
825+ using vm_alloc_callback_t = std::function<void(const vm_alloc_t *)>;
826+
827+ public:
828+ virtual ~vm_garbage_collector_t() = 0;
829+
830+ // Supply an allocation for the collector to track.
831+ // Note that it is assumed the collector implementation will increment the reference count on the supplied alloc.
832+ virtual void track_allocation(vm_alloc_t *alloc) = 0;
833+
834+ // Enumerate allocations that are being tracked by the collector.
835+ // See callback type description.
836+ virtual void enum_tracked_allocations(vm_alloc_callback_t callback) const = 0;
837+
838+ // Called by the scheduler to inform the collector it should attempt to free resources.
839+ // All VM threads are guaranteed to be idle when called.
840+ // Returns true if the collection algorithm was run, otherwise false.
841+ virtual bool collect(std::vector<std::shared_ptr<const vm_thread_t>> &threads) = 0;
842+ };
843+ }
844+}
845+
846+#endif // _DISVM_SRC_INCLUDE_RUNTIME_H_

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t