History

Create C++ exceptions that can be marshalled into DisVM exceptions. Fix bug in exception raising where the module reference was not being updated during stack unwinding.

arr committed 9 years ago

Commit 558c6ea1 parent 02c7a613 files · +71 −14Browse files

Showing the changes to src/vm/execution_table.cpp (1 of 3 files). Show all

Unified · Split

src/vm/execution_table.cpp+58−12
@@ -1507,6 +1507,9 @@ namespace · 1506 unmodified lines
15071507 disvm::debug::log_msg(debug::component_trace_t::stack, debug::log_level_t::debug, "enter: function");
15081508 }
15091509
1510+ // Forward declaration
1511+ EXEC_DECL(raise);
1512+
15101513 EXEC_DECL(mcall)
15111514 {
15121515 auto target_module = at_val<vm_module_ref_t>(r.dest);
@@ -1551,22 +1554,52 @@ namespace · 38 unmodified lines
15511554 r.mp_base = r.module_ref->mp_base;
15521555 r.next_pc = function_pc;
15531556
1554− if (r.module_ref->is_builtin_module())
1557+ // Non-built-in modules ref count and return
1558+ if (!r.module_ref->is_builtin_module())
15551559 {
1556− const auto &inst = r.module_ref->code_section[function_pc];
1557− assert(r.mp_base == nullptr && "Built-in modules shouldn't have module data (MP register)");
1560+ r.mp_base->add_ref();
1561+ return;
1562+ }
1563+
1564+ // Calling into a built-in module is a bit complicated since control leaves the VM and thus
1565+ // the callee clean-up semantics of DisVM are difficult to enforced. The solution here is
1566+ // to release VM control of the thread and clean-up the stack on behalf of the callee when
1567+ // control returns to the VM.
1568+ // Built-in modules are also permitted to throw marshallable exceptions which requires
1569+ // raising the exception manually.
1570+
1571+ const auto &inst = r.module_ref->code_section[function_pc];
1572+ assert(r.mp_base == nullptr && "Built-in modules shouldn't have module data (MP register)");
15581573
1559− r.current_thread_state = vm_thread_state_t::release;
1574+ vm_alloc_t *marshallable_err{};
1575+ r.current_thread_state = vm_thread_state_t::release;
1576+
1577+ try
1578+ {
15601579 inst.native(r, vm);
1561− ret(r, vm);
15621580
1563− // Only reset the thread if it is in the state set prior to native call.
1564− if (r.current_thread_state == vm_thread_state_t::release)
1565− r.current_thread_state = vm_thread_state_t::running;
1581+ // Handle callee clean-up semantics
1582+ ret(r, vm);
15661583 }
1567− else
1584+ catch (const marshallable_user_exception &e)
15681585 {
1569− r.mp_base->add_ref();
1586+ auto msg = e.what();
1587+ marshallable_err = new vm_string_t{ std::strlen(msg), reinterpret_cast<const uint8_t*>(msg) };
1588+ }
1589+
1590+ // Only reset the thread if it is in the state set prior to native call.
1591+ if (r.current_thread_state == vm_thread_state_t::release)
1592+ r.current_thread_state = vm_thread_state_t::running;
1593+
1594+ // Raise marshallable exception
1595+ if (marshallable_err != nullptr)
1596+ {
1597+ assert(r.current_thread_state == vm_thread_state_t::running && "Throwing a marshallable error should not result in an altered VM thread state");
1598+ auto err = marshallable_err->get_allocation();
1599+ r.src = reinterpret_cast<pointer_t>(&err);
1600+ raise(r, vm);
1601+
1602+ disvm::runtime::dec_ref_count_and_free(marshallable_err);
15701603 }
15711604 }
15721605
@@ -1710,10 +1743,23 @@ namespace · 137 unmodified lines
17101743
17111744 if (target_frame != r.stack.peek_frame())
17121745 {
1713− while (target_frame != r.stack.pop_frame())
1746+ // Unwind stack to find target frame
1747+ do
17141748 {
1715− // Remove frames from the stack until the target frame is found.
1749+ auto curr_frame = r.stack.peek_frame();
1750+
1751+ // Update the module reference register during the stack unwind
1752+ if (curr_frame->prev_module_ref() != nullptr)
1753+ {
1754+ dec_ref_count_and_free(r.module_ref);
1755+ r.module_ref = curr_frame->prev_module_ref();
1756+ curr_frame->prev_module_ref() = nullptr;
1757+
1758+ dec_ref_count_and_free(r.mp_base);
1759+ r.mp_base = r.module_ref->mp_base;
1760+ }
17161761 }
1762+ while (target_frame != r.stack.pop_frame());
17171763 }
17181764
17191765 // Re-initialize the current frame