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+
18+using namespace disvm;
19+using namespace disvm::runtime;
20+
21+vm_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+
28+vm_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+
34+vm_t::loaded_module_t::~loaded_module_t()
35+{
36+ if (origin != nullptr)
37+ origin->release();
38+}
39+
40+vm_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+
70+vm_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+
82+vm_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+
89+namespace
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+
103+const 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+
112+const 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+
120+const 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+
133+std::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+
182+runtime::vm_scheduler_control_t &vm_t::get_scheduler_control() const
183+{
184+ return _scheduler->get_controller();
185+}
186+
187+runtime::vm_garbage_collector_t &vm_t::get_garbage_collector() const
188+{
189+ return *_gc;
190+}
191+
192+void 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+}