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
1507 disvm::debug::log_msg(debug::component_trace_t::stack, debug::log_level_t::debug, "enter: function");1507 disvm::debug::log_msg(debug::component_trace_t::stack, debug::log_level_t::debug, "enter: function");
1508 }1508 }
1509 1509
1510 // Forward declaration
1511 EXEC_DECL(raise);
1512
1510 EXEC_DECL(mcall)1513 EXEC_DECL(mcall)
1511 {1514 {
1512 auto target_module = at_val<vm_module_ref_t>(r.dest);1515 auto target_module = at_val<vm_module_ref_t>(r.dest);
@@ -1551,22 +1554,52 @@ namespace · 38 unmodified lines
1551 r.mp_base = r.module_ref->mp_base;1554 r.mp_base = r.module_ref->mp_base;
1552 r.next_pc = function_pc;1555 r.next_pc = function_pc;
1553 1556
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())
1555 {1559 {
1556 const auto &inst = r.module_ref->code_section[function_pc];1560 r.mp_base->add_ref();
1557 assert(r.mp_base == nullptr && "Built-in modules shouldn't have module data (MP register)");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)");
1558 1573
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 {
1560 inst.native(r, vm);1579 inst.native(r, vm);
1561 ret(r, vm);
1562 1580
1563 // Only reset the thread if it is in the state set prior to native call.1581 // Handle callee clean-up semantics
1564 if (r.current_thread_state == vm_thread_state_t::release)1582 ret(r, vm);
1565 r.current_thread_state = vm_thread_state_t::running;
1566 }1583 }
1567 else1584 catch (const marshallable_user_exception &e)
1568 {1585 {
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);
1570 }1603 }
1571 }1604 }
1572 1605
@@ -1710,10 +1743,23 @@ namespace · 137 unmodified lines
1710 1743
1711 if (target_frame != r.stack.peek_frame())1744 if (target_frame != r.stack.peek_frame())
1712 {1745 {
1713 while (target_frame != r.stack.pop_frame())1746 // Unwind stack to find target frame
1747 do
1714 {1748 {
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 }
1716 }1761 }
1762 while (target_frame != r.stack.pop_frame());
1717 }1763 }
1718 1764
1719 // Re-initialize the current frame1765 // Re-initialize the current frame