History

Create specific exception when index is out of range. Update thread class to print out exception details. Throw exception when an invalid op-code is detected. Enforce mspawn instruction cannot start from a built-in module.

arr committed 10 years ago

Commit 266fad61 parent 9af409310 files · +63 −40Browse files

Unified · Split

10 files
  1. src/exec/main.cpp +9 −5
  2. src/include/builtin_module.h +12 −3
  3. src/include/exceptions.h +9 −12
  4. src/include/runtime.h +1 −1
  5. src/vm/array.cpp +1 −1
  6. src/vm/execution_table.cpp +6 −2
  7. src/vm/scheduler.h +1 −1
  8. src/vm/stack.cpp +2 −2
  9. src/vm/string.cpp +4 −4
  10. src/vm/thread.cpp +18 −9
src/exec/main.cpp+9−5
@@ -93,13 +93,17 @@ namespace · 92 unmodified lines
9393 if (args != nullptr)
9494 mp_base[2] = args->get_allocation();
9595
96+ // Define the frame offsets for the two arguments
97+ const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset;
98+ const auto second_arg_offset = first_arg_offset + vm_frame_constants::register_size_in_bytes;
99+
96100 e.code_section =
97101 {
98102 { vm_exec_op_t
99103 {
100104 opcode_t::load,
101105 { address_mode_t::offset_indirect_mp, 0, 0 }, // command module path
102− { address_mode_middle_t::small_immediate, 0 },
106+ { address_mode_middle_t::small_immediate, 0 }, // import table index
103107 { address_mode_t::offset_indirect_fp, 20, 0 } // module reference
104108 }
105109 },
@@ -107,7 +111,7 @@ namespace · 1 unmodified line
107111 {
108112 opcode_t::mframe,
109113 { address_mode_t::offset_indirect_fp, 20, 0 }, // module reference
110− { address_mode_middle_t::small_immediate, 0 },
114+ { address_mode_middle_t::small_immediate, 0 }, // function index into module
111115 { address_mode_t::offset_indirect_fp, 24, 0 } // module call frame
112116 }
113117 },
@@ -116,7 +120,7 @@ namespace · 2 unmodified lines
116120 opcode_t::movp,
117121 { address_mode_t::offset_indirect_mp, 4, 0 }, // UI context
118122 { address_mode_middle_t::none },
119− { address_mode_t::offset_double_indirect_fp, 24, 32 } // module call frame -> UI context offset
123+ { address_mode_t::offset_double_indirect_fp, 24, first_arg_offset } // module call frame -> UI context offset
120124 }
121125 },
122126 { vm_exec_op_t
@@ -124,14 +128,14 @@ namespace · 1 unmodified line
124128 opcode_t::movp,
125129 { address_mode_t::offset_indirect_mp, 8, 0 }, // Argument list
126130 { address_mode_middle_t::none },
127− { address_mode_t::offset_double_indirect_fp, 24, 36 } // module call frame -> argument list offset
131+ { address_mode_t::offset_double_indirect_fp, 24, second_arg_offset } // module call frame -> argument list offset
128132 }
129133 },
130134 { vm_exec_op_t
131135 {
132136 opcode_t::mcall,
133137 { address_mode_t::offset_indirect_fp, 24, 0 }, // module call frame
134− { address_mode_middle_t::small_immediate, 0 },
138+ { address_mode_middle_t::small_immediate, 0 }, // function index into module
135139 { address_mode_t::offset_indirect_fp, 20, 0 } // module reference
136140 }
137141 },
src/include/builtin_module.h+12−3
@@ -66,9 +66,18 @@ namespace disvm · 65 unmodified lines
6666 // Includes registers on base frame plus the implied return register
6767 static const auto default_register_count = (sizeof(vm_frame_base_alloc_t) / register_size_in_bytes) + 1;
6868
69− // See VM frame definition
70− static const auto fixed_point_register_1_frame_offset = default_register_count * register_size_in_bytes;
71− static const auto fixed_point_register_2_frame_offset = fixed_point_register_1_frame_offset + (2 * register_size_in_bytes);
69+ // [SPEC] The fixed point registers are defined by their usage in the
70+ // Inferno implementation. They rely on the 'temp' registers defined below.
71+ // See fixed point op-codes in Inferno (libinterp/xec.c).
72+ static const auto fixed_point_register_1_offset = default_register_count * register_size_in_bytes;
73+ static const auto fixed_point_register_2_offset = fixed_point_register_1_offset + (2 * register_size_in_bytes);
74+
75+ // [SPEC] The official Limbo compiler allocates additional 'temp' registers on all call frames.
76+ // See 'STemp', 'RTemp', and 'DTemp' in Inferno (limbo/limbo.h)
77+ static const auto limbo_temp_register_count = 3;
78+
79+ // Define the first argument offset in a Limbo compiler generated call frame.
80+ static const auto limbo_first_arg_register_offset = (default_register_count + limbo_temp_register_count) * register_size_in_bytes;
7281 };
7382
7483 //
src/include/exceptions.h+9−12
@@ -60,7 +60,7 @@ namespace disvm · 59 unmodified lines
6060 { }
6161 };
6262
63− class invalid_utf8 : public vm_user_exception
63+ class invalid_utf8 final : public vm_user_exception
6464 {
6565 public:
6666 explicit invalid_utf8()
@@ -84,7 +84,7 @@ namespace disvm · 17 unmodified lines
8484 const char *operation;
8585 };
8686
87− class type_violation : public vm_user_exception
87+ class type_violation final : public vm_user_exception
8888 {
8989 public:
9090 explicit type_violation()
@@ -92,26 +92,23 @@ namespace disvm · 1 unmodified line
9292 { }
9393 };
9494
95− class out_of_range_memory final : public vm_user_exception
95+ class out_of_range_memory : public vm_user_exception
9696 {
9797 public:
9898 explicit out_of_range_memory()
9999 : vm_user_exception("Out of range access")
100− , invalid_value{ 0 }
101− , range_defined{ false }
102− , valid_max{ 0 }
103− , valid_min{ 0 }
104100 { }
101+ };
105102
106− explicit out_of_range_memory(word_t valid_min, word_t valid_max, word_t invalid_valid)
107− : vm_user_exception("Out of range access")
108− , invalid_value{ invalid_valid }
109− , range_defined{ true }
103+ class index_out_of_range_memory final : public out_of_range_memory
104+ {
105+ public:
106+ explicit index_out_of_range_memory(word_t valid_min, word_t valid_max, word_t invalid_value)
107+ : invalid_value{ invalid_value }
110108 , valid_max{ valid_max }
111109 , valid_min{ valid_min }
112110 { }
113111
114− const bool range_defined;
115112 const word_t valid_min;
116113 const word_t valid_max;
117114 const word_t invalid_value;
src/include/runtime.h+1−1
@@ -759,7 +759,7 @@ namespace disvm · 758 unmodified lines
759759
760760 ~vm_thread_t();
761761
762− vm_thread_state_t execute(vm_t &virtual_machine, uint32_t quanta);
762+ vm_thread_state_t execute(vm_t &virtual_machine, const uint32_t quanta);
763763
764764 vm_thread_state_t get_state() const;
765765
src/vm/array.cpp+1−1
@@ -156,7 +156,7 @@ word_t vm_array_t::get_length() const · 155 unmodified lines
156156 pointer_t vm_array_t::at(word_t index) const
157157 {
158158 if (index < 0 || _length <= index)
159− throw out_of_range_memory{ 0, _length - 1, index };
159+ throw index_out_of_range_memory{ 0, _length - 1, index };
160160
161161 return reinterpret_cast<pointer_t>(_arr + (index * _element_type->size_in_bytes));
162162 }
src/vm/execution_table.cpp+6−2
@@ -846,7 +846,7 @@ namespace · 845 unmodified lines
846846
847847 auto index = vt_ref<word_t>(r.dest);
848848 if (index < 0 || arr->get_length() <= index)
849− throw out_of_range_memory{ 0, arr->get_length(), index };
849+ throw index_out_of_range_memory{ 0, arr->get_length(), index };
850850
851851 // Return the address, not the value
852852 pt_ref(r.mid) = arr->at(index);
@@ -1577,6 +1577,10 @@ namespace · 724 unmodified lines
15771577
15781578 const auto &function_ref = target_module_ref->get_function_ref(import_function_id);
15791579
1580+ // Spawning a built-in module is not permitted
1581+ if (target_module_ref->is_builtin_module())
1582+ throw vm_user_exception{ "Spawning a built-in module is not permitted" };
1583+
15801584 vm.fork(r.thread, *target_module_ref, *spawned_frame, function_ref.entry_pc);
15811585
15821586 // After the new thread is forked pop off the argument passing frame.
@@ -1685,7 +1689,7 @@ namespace · 102 unmodified lines
16851689 auto imported_module = std::shared_ptr<const vm_module_t>{};
16861690
16871691 // Handle self loading module optimization.
1688− if (::strcmp(str->str(), "$self") == 0)
1692+ if (std::strcmp(str->str(), "$self") == 0)
16891693 {
16901694 imported_module = r.module_ref->module;
16911695 }
src/vm/scheduler.h+1−1
@@ -46,7 +46,7 @@ namespace disvm · 45 unmodified lines
4646 std::vector<std::shared_ptr<const vm_thread_t>> get_all_threads() const override final;
4747
4848 private:
49− struct thread_instance_t
49+ struct thread_instance_t final
5050 {
5151 thread_instance_t(std::unique_ptr<vm_thread_t> t)
5252 : vm_thread{ std::move(t) }
src/vm/stack.cpp+2−2
@@ -161,7 +161,7 @@ vm_module_ref_t *&vm_frame_t::prev_module_ref() const · 160 unmodified lines
161161
162162 pointer_t vm_frame_t::fixed_point_register_1() const
163163 {
164− const auto offset = vm_frame_constants::fixed_point_register_1_frame_offset;
164+ const auto offset = vm_frame_constants::fixed_point_register_1_offset;
165165 assert(offset < frame_type->size_in_bytes);
166166
167167 auto p = reinterpret_cast<uint8_t *>(base()) + offset;
@@ -170,7 +170,7 @@ pointer_t vm_frame_t::fixed_point_register_1() const · 2 unmodified lines
170170
171171 pointer_t vm_frame_t::fixed_point_register_2() const
172172 {
173− const auto offset = vm_frame_constants::fixed_point_register_2_frame_offset;
173+ const auto offset = vm_frame_constants::fixed_point_register_2_offset;
174174 assert(offset < frame_type->size_in_bytes);
175175
176176 auto p = reinterpret_cast<uint8_t *>(base()) + offset;
src/vm/string.cpp+4−4
@@ -264,10 +264,10 @@ vm_string_t::vm_string_t(const vm_string_t &other, word_t begin_index, word_t en · 263 unmodified lines
264264 throw out_of_range_memory{};
265265
266266 if (begin_index < 0)
267− throw out_of_range_memory{ 0, other._length, begin_index };
267+ throw index_out_of_range_memory{ 0, other._length, begin_index };
268268
269269 if (other._length < end_index)
270− throw out_of_range_memory{ 0, other._length, end_index };
270+ throw index_out_of_range_memory{ 0, other._length, end_index };
271271
272272 // Allocate memory based on character count and size
273273 auto src = other._mem.local;
@@ -384,7 +384,7 @@ word_t vm_string_t::get_length() const · 110 unmodified lines
384384 rune_t vm_string_t::get_rune(word_t index) const
385385 {
386386 if (index < 0 && _length <= index)
387− throw out_of_range_memory{ 0, _length - 1, index };
387+ throw index_out_of_range_memory{ 0, _length - 1, index };
388388
389389 // Determine if local or allocated memory
390390 auto source = reinterpret_cast<const char *>(_mem.local);
@@ -410,7 +410,7 @@ void vm_string_t::set_rune(word_t index, rune_t value) · 19 unmodified lines
410410
411411 // Index equal to length is allowed to grow the string
412412 if (index < 0 && _length <= index)
413− throw out_of_range_memory{ 0, _length, index };
413+ throw index_out_of_range_memory{ 0, _length, index };
414414
415415 // Determine if local or allocated memory
416416 auto source = static_cast<uint8_t *>(_mem.local);
src/vm/thread.cpp+18−9
@@ -117,10 +117,9 @@ namespace · 116 unmodified lines
117117 #endif
118118 }
119119
120− std::atomic<uint32_t> thread_id_counter(1);
121−
122120 uint32_t get_unique_thread_id()
123121 {
122+ static std::atomic<uint32_t> thread_id_counter{ 1 };
124123 return thread_id_counter.fetch_add(1);
125124 }
126125 }
@@ -206,15 +205,17 @@ vm_thread_t::vm_thread_t( · 79 unmodified lines
206205 // Copy over the frame into this thread - pass arguments to the thread
207206 current_frame->copy_frame_contents(initial_frame);
208207
209− debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "init: vm thread: %d %d\n", _thread_id, _parent_thread_id);
208+ if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>())
209+ debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "init: vm thread: %d %d\n", _thread_id, _parent_thread_id);
210210 }
211211
212212 vm_thread_t::~vm_thread_t()
213213 {
214− debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);
214+ if (debug::is_component_tracing_enabled<debug::component_trace_t::thread>())
215+ debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "destroy: vm thread: %d %d\n", _thread_id, _parent_thread_id);
215216 }
216217
217−vm_thread_state_t vm_thread_t::execute(vm_t &virtual_machine, uint32_t quanta)
218+vm_thread_state_t vm_thread_t::execute(vm_t &virtual_machine, const uint32_t quanta)
218219 {
219220 _registers.current_thread_state = vm_thread_state_t::running;
220221 assert(_registers.pc != runtime_constants::invalid_program_counter);
@@ -236,9 +237,13 @@ vm_thread_state_t vm_thread_t::execute(vm_t &virtual_machine, uint32_t quanta) · 15 unmodified lines
236237 assert(static_cast<std::size_t>(_registers.pc) < code_section.size());
237238
238239 const auto &inst = code_section[_registers.pc].op;
240+ const auto op_code = static_cast<std::size_t>(inst.opcode);
241+ if (static_cast<std::size_t>(opcode_t::last_opcode) < op_code)
242+ throw vm_system_exception{ "Unknown op-code" };
243+
239244 decode_address(inst, _registers);
240245 _registers.pc++;
241− vm_exec_table[static_cast<std::size_t>(inst.opcode)](_registers, virtual_machine);
246+ vm_exec_table[op_code](_registers, virtual_machine);
242247
243248 if (_registers.current_thread_state != vm_thread_state_t::running)
244249 break;
@@ -247,13 +252,17 @@ vm_thread_state_t vm_thread_t::execute(vm_t &virtual_machine, uint32_t quanta) · 2 unmodified lines
247252 catch (const unhandled_user_exception &uue)
248253 {
249254 // [TODO] Store the exception
250− debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "broken: vm thread: unhandled: >>%s<< %d >>%s<<\n", uue.exception_id, uue.program_counter, uue.module_name);
255+ std::printf("%s - %s in %s at %d\n", uue.what(), uue.exception_id, uue.module_name, uue.program_counter);
256+ _registers.current_thread_state = vm_thread_state_t::broken;
257+ }
258+ catch (const index_out_of_range_memory &ioor)
259+ {
260+ std::printf("%s - %d [%d,%d]\n", ioor.what(), ioor.invalid_value, ioor.valid_min, ioor.valid_max);
251261 _registers.current_thread_state = vm_thread_state_t::broken;
252262 }
253263 catch (const vm_user_exception &ue)
254264 {
255− // [TODO] Store the exception
256− debug::log_msg(debug::component_trace_t::thread, debug::log_level_t::debug, "broken: vm thread: >>%s<<\n", ue.what());
265+ std::printf("%s\n", ue.what());
257266 _registers.current_thread_state = vm_thread_state_t::broken;
258267 }
259268