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/vm/vm.cpp (1 of 40 files). Show all

Unified · Split

src/vm/vm.cpp+197−0
@@ -0,0 +1,197 @@
1//
2// Dis VM
3// File: vm.cpp
4// Author: arr
5//
6
7#include <cassert>
8#include <memory>
9#include <algorithm>
10#include <disvm.h>
11#include <debug.h>
12#include <runtime.h>
13#include <exceptions.h>
14#include <builtin_module.h>
15#include "scheduler.h"
16#include "garbage_collector.h"
17
18using namespace disvm;
19using namespace disvm::runtime;
20
21vm_t::loaded_module_t::loaded_module_t(std::unique_ptr<runtime::vm_string_t> origin, std::shared_ptr<const runtime::vm_module_t> module)
22 : origin{ std::move(origin) }
23 , module{ module }
24{
25 assert(this->origin != nullptr);
26}
27
28vm_t::loaded_module_t::loaded_module_t(loaded_module_t &&other)
29 : origin{ std::move(other.origin) }
30 , module{ std::move(other.module) }
31{
32}
33
34vm_t::loaded_module_t::~loaded_module_t()
35{
36 if (origin != nullptr)
37 origin->release();
38}
39
40vm_t::vm_t(
41 create_vm_interface_callback_t<runtime::vm_scheduler_t> create_scheduler,
42 create_vm_interface_callback_t<runtime::vm_garbage_collector_t> create_gc)
43{
44 // Initialize intrinsic type descriptors
45 intrinsic_type_desc::initialize();
46
47 // Initialize built-in modules.
48 builtin::initialize_builtin_modules();
49
50 if (create_gc == nullptr)
51 _gc = std::make_unique<default_garbage_collector_t>(*this);
52 else
53 _gc = create_gc(*this);
54
55 if (create_scheduler == nullptr)
56 {
57 const auto system_thread_count = uint32_t{ 1 };
58
59 // The Inferno implementation defined the thread quanta as 2048 (include/interp.h)
60 const auto thread_quanta = uint32_t{ 2048 };
61
62 _scheduler = std::make_unique<default_scheduler_t>(*this, system_thread_count, thread_quanta);
63 }
64 else
65 {
66 _scheduler = create_scheduler(*this);
67 }
68}
69
70vm_t::vm_t(uint32_t system_thread_count, uint32_t thread_quanta)
71{
72 // Initialize intrinsic type descriptors
73 runtime::intrinsic_type_desc::initialize();
74
75 // Initialize built-in modules.
76 builtin::initialize_builtin_modules();
77
78 _gc = std::make_unique<default_garbage_collector_t>(*this);
79 _scheduler = std::make_unique<default_scheduler_t>(*this, system_thread_count, thread_quanta);
80}
81
82vm_t::~vm_t()
83{
84 // Release the scheduler first since it could be using the gc instance.
85 _scheduler.reset();
86 _gc.reset();
87}
88
89namespace
90{
91 const runtime::vm_thread_t& _exec(runtime::vm_scheduler_t &s, std::unique_ptr<runtime::vm_module_ref_t> &entry_module_ref)
92 {
93 auto thread = std::make_unique<vm_thread_t>(*entry_module_ref, vm_t::root_vm_thread_id);
94
95 // Now that the thread has been created and has inherited ownership of the pointer, relinquish the smart pointer's ownership.
96 entry_module_ref->release(); // decrement the vm alloc ref count
97 entry_module_ref.release(); // release the smart pointer
98
99 return s.schedule_thread(std::move(thread));
100 }
101}
102
103const runtime::vm_thread_t& vm_t::exec(const char *path)
104{
105 assert(path != nullptr);
106 auto entry_module = load_module(path);
107
108 auto entry_module_ref = std::make_unique<vm_module_ref_t>(entry_module);
109 return _exec(*_scheduler, entry_module_ref);
110}
111
112const runtime::vm_thread_t& vm_t::exec(std::unique_ptr<runtime::vm_module_t> entry_module)
113{
114 assert(entry_module != nullptr);
115
116 auto entry_module_ref = std::make_unique<vm_module_ref_t>(std::move(entry_module));
117 return _exec(*_scheduler, entry_module_ref);
118}
119
120const runtime::vm_thread_t& vm_t::fork(
121 const runtime::vm_thread_t &parent,
122 runtime::vm_module_ref_t &module_ref,
123 const runtime::vm_frame_t &initial_frame,
124 runtime::vm_pc_t initial_pc)
125{
126 if (initial_pc < 0 || static_cast<vm_pc_t>(module_ref.code_section.size()) <= initial_pc)
127 throw vm_system_exception{ "Invalid entry program counter" };
128
129 auto thread = std::make_unique<vm_thread_t>(module_ref, initial_frame, initial_pc, parent.get_thread_id());
130 return _scheduler->schedule_thread(std::move(thread));
131}
132
133std::shared_ptr<const runtime::vm_module_t> vm_t::load_module(const char *path)
134{
135 if (path == nullptr)
136 throw vm_user_exception{ "Invalid module path" };
137
138 std::lock_guard<std::mutex> lock{ _modules_lock };
139
140 // Check if the module is already loaded.
141 auto iter = std::begin(_modules);
142 while (iter != std::end(_modules))
143 {
144 if (0 == ::strcmp(iter->origin->str(), path))
145 {
146 auto module = iter->module.lock();
147
148 // If an entry exists but is null, the module was loaded before. Read the module again and return.
149 if (module == nullptr)
150 {
151 module = std::shared_ptr<vm_module_t>{ std::move(read_module(path)) };
152 iter->module = module;
153
154 debug::log_msg(debug::component_trace_t::module, debug::log_level_t::debug, "reload: vm module: >>%s<<\n", path);
155 }
156
157 return module;
158 }
159
160 ++iter;
161 }
162
163 auto new_module = std::shared_ptr<vm_module_t>{};
164 if (path[0] == BUILTIN_MODULE_PREFIX_CHAR)
165 {
166 new_module = std::move(builtin::get_builtin_module(path));
167 }
168 else
169 {
170 // Read in the module
171 new_module = std::move(read_module(path));
172 }
173
174 auto path_local = std::make_unique<vm_string_t>(std::strlen(path), reinterpret_cast<const uint8_t *>(path));
175 _modules.push_front(std::move(loaded_module_t{ std::move(path_local), new_module }));
176
177 debug::log_msg(debug::component_trace_t::module, debug::log_level_t::debug, "load: vm module: >>%s<<\n", path);
178
179 return new_module;
180}
181
182runtime::vm_scheduler_control_t &vm_t::get_scheduler_control() const
183{
184 return _scheduler->get_controller();
185}
186
187runtime::vm_garbage_collector_t &vm_t::get_garbage_collector() const
188{
189 return *_gc;
190}
191
192void vm_t::spin_sleep_till_idle(std::chrono::milliseconds sleep_interval) const
193{
194 do
195 std::this_thread::sleep_for(sleep_interval);
196 while (!_scheduler->is_idle());
197}