203 lines · 6.6 KB · C++
RawDownload
//// Dis VM - exec program// File: main.cpp// Author: arr// #include <iostream>#include <cassert>#include <array>#include <memory>#include <builtin_module.h>#include <debug.h>#include <exceptions.h>#include "exec.h" using namespace disvm;using namespace disvm::runtime; namespace{    // Entry frame layout    struct vm_entry_frame_t final : public vm_frame_base_alloc_t    {        word_t noret;        pointer_t command_module_ref;        pointer_t command_stack_frame;    };     const auto entry_frame_pointer_map = std::vector<byte_t>{ 0x06 };     std::shared_ptr<const vm_module_t> command_module;     std::unique_ptr<vm_module_t> create_entry_module(vm_t &vm, int argc, char* argv[])    {        // First argument is the module to load        auto command_module_path = new vm_string_t{ std::strlen(argv[0]), reinterpret_cast<uint8_t *>(argv[0]) };         // Pre-load the command module in the VM.        command_module = vm.load_module(command_module_path->str());         // Convert arguments to a list        vm_list_t *args = nullptr;        vm_list_t *last = nullptr;        for (auto i = 1; i < argc; ++i)        {            auto tmp = argv[i];            auto arg = new vm_string_t{ std::strlen(tmp), reinterpret_cast<uint8_t *>(tmp) };            if (args == nullptr)            {                assert(last == nullptr);                args = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() };                last = args;            }            else            {                auto new_tail = new vm_list_t{ intrinsic_type_desc::type<vm_string_t>() };                last->set_tail(new_tail);                new_tail->release();                 last = new_tail;            }             pt_ref(last->value()) = arg->get_allocation();        }         // Create the module        auto entry_module = std::make_unique<vm_module_t>();        auto &e = *entry_module;         // Header details        e.header.entry_pc = 0;        e.header.entry_type = 0;        e.header.runtime_flag = (runtime_flags_t::has_import);         std::array<uint8_t, 8> mod_name = { "_entry_" };        e.module_name = std::make_unique<vm_string_t>(mod_name.size() - 1, mod_name.data());         // Inherit the stack extent from the command module and add the entry frame size.        e.header.stack_extent = command_module->header.stack_extent + sizeof(vm_entry_frame_t);         e.type_section =        {            type_descriptor_t::create(sizeof(vm_entry_frame_t), entry_frame_pointer_map)        };         // Initialize the module base register        const auto mp_type = type_descriptor_t::create(12, { 0xe0 });        e.original_mp.reset(vm_alloc_t::allocate(mp_type, vm_alloc_t::zero_memory));        auto mp_base = e.original_mp->get_allocation<pointer_t>();        mp_base[0] = command_module_path->get_allocation();         // [TODO] Implement the UI context for the command        mp_base[1] = nullptr;         if (args != nullptr)            mp_base[2] = args->get_allocation();         // Define the frame offsets for the two arguments        const auto first_arg_offset = vm_frame_constants::limbo_first_arg_register_offset;        const auto second_arg_offset = first_arg_offset + vm_frame_constants::register_size_in_bytes;         e.code_section =        {            { vm_exec_op_t                {                    opcode_t::load,                    { address_mode_t::offset_indirect_mp, 0, 0 }, // command module path                    { address_mode_middle_t::small_immediate, 0 }, // import table index                    { address_mode_t::offset_indirect_fp, 20, 0 } // module reference                }            },            { vm_exec_op_t                {                    opcode_t::mframe,                    { address_mode_t::offset_indirect_fp, 20, 0 }, // module reference                    { address_mode_middle_t::small_immediate, 0 }, // function index into module                    { address_mode_t::offset_indirect_fp, 24, 0 } // module call frame                }            },            { vm_exec_op_t                {                    opcode_t::movp,                    { address_mode_t::offset_indirect_mp, 4, 0 }, // UI context                    { address_mode_middle_t::none },                    { address_mode_t::offset_double_indirect_fp, 24, first_arg_offset } // module call frame -> UI context offset                }            },            { vm_exec_op_t                {                    opcode_t::movp,                    { address_mode_t::offset_indirect_mp, 8, 0 }, // Argument list                    { address_mode_middle_t::none },                    { address_mode_t::offset_double_indirect_fp, 24, second_arg_offset } // module call frame -> argument list offset                }            },            { vm_exec_op_t                {                    opcode_t::mcall,                    { address_mode_t::offset_indirect_fp, 24, 0 }, // module call frame                    { address_mode_middle_t::small_immediate, 0 }, // function index into module                    { address_mode_t::offset_indirect_fp, 20, 0 } // module reference                }            },            { vm_exec_op_t{ opcode_t::ret,{ address_mode_t::none },{ address_mode_middle_t::none },{ address_mode_t::none } } },        };         // Create import section for Command        // See limbo/Command.m for type details        {            import_function_t func{};             // [TODO] Create mechanism to generated type signatures            func.sig = 0x4244b354;             std::array<uint8_t, 5> func_name = { "init" };            func.name = std::make_unique<vm_string_t>(func_name.size() - 1, func_name.data());             import_vm_module_t import{};            import.functions.push_back(std::move(func));             e.import_section.push_back(std::move(import));        }         return entry_module;    }} int main(int argc, char* argv[]){    // [TODO] Handle command line arguments    assert(argc > 1);     vm_t vm;     //vm.load_tool(std::make_shared<debugger>());     try    {        // Ignore the process name        auto entry = create_entry_module(vm, argc - 1, argv + 1);         vm.exec(std::move(entry));         vm.spin_sleep_till_idle(std::chrono::milliseconds(100));    }    catch (vm_user_exception &ue)    {        std::cout << ue.what() << std::endl;         return EXIT_FAILURE;    }    catch (vm_system_exception &se)    {        std::cout            << "Internal exception:\n\t"            << se.what()            << std::endl;         return EXIT_FAILURE;    }     return 0;}