voidSys_millisec(vm_registers_t &r, vm_t &vm){ const auto current_time = std::chrono::steady_clock::now(); const auto current_time_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time.time_since_epoch()); auto &fp = r.stack.peek_frame()->base<F_Sys_millisec>(); *fp.ret = static_cast<word_t>(current_time_in_ms.count());} voidSys_mount(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_mount>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_open(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_open>(); auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s); const auto open_mode = convert_to_openmode(fp.mode); // [TODO] Handle opening devices - not just files (i.e. /dev/random, /dev/source, /proc/1234) auto file_stream = sys::create_file_stream(path->str(), (open_mode | std::ios::binary)); // Return null if file stream is not open. if (file_stream == nullptr) { *fp.ret = nullptr; return; } vm_alloc_t *fd_alloc; auto fd = word_t{}; std::tie(fd, fd_alloc) = vm_fd_t::create(std::move(file_stream), fp.mode, path); if (debug::is_component_tracing_enabled<debug::component_trace_t::builtin>()) { debug::log_msg( debug::component_trace_t::builtin, debug::log_level_t::debug, "sys: open: %d >>%s<< %#x\n", fd, path->str(), fp.mode); } *fp.ret = fd_alloc->get_allocation();} voidSys_pctl(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_pctl>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_pipe(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_pipe>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_pread(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_pread>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_print(vm_registers_t &r, vm_t &vm){ auto fp_base = r.stack.peek_frame()->base(); auto &fp = r.stack.peek_frame()->base<F_Sys_print>(); auto str = vm_alloc_t::from_allocation<vm_string_t>(fp.s); if (str == nullptr) throw dereference_nil{ "Print string" }; auto static_buffer = std::array<char, 1024>{}; auto msg_args = &fp.vargs; auto written = sys::printf_to_buffer(*str, msg_args, fp_base, static_buffer.size(), static_buffer.data()); if (written >= 0) { fd_stdout->write(written, static_buffer.data()); } else { auto dynamic_buffer = std::vector<char>(static_buffer.size() * 2); written = sys::printf_to_dynamic_buffer(*str, msg_args, fp_base, dynamic_buffer); fd_stdout->write(written, dynamic_buffer.data()); } *fp.ret = written;} voidSys_pwrite(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_pwrite>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_read(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_read>(); const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); auto n = fp.n; if (buffer == nullptr || n <= 0) { *fp.ret = 0; return; } // [SPEC] Supplying a size greater than the buffer length is // equivalent to indicating the entire buffer should be filled. n = std::min(n, buffer->get_length()); auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); assert(fd_alloc->alloc_type == T_FD); auto fd = fd_alloc->get_allocation<vm_fd_t>(); *fp.ret = fd->read(n, buffer->at(0));} voidSys_readn(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_readn>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_remove(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_remove>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_seek(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_seek>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_sleep(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_sleep>(); const auto period_ms = fp.period; // [TODO] Thread should yield to another according to the sleep() specification. std::this_thread::sleep_for(std::chrono::milliseconds(period_ms)); *fp.ret = 0;} voidSys_sprint(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_sprint>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_stat(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_stat>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_stream(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_stream>(); throw vm_system_exception{ "Instruction not implemented" };} namespace{ bool is_delim(const rune_t c, const vm_string_t &delim) { const auto max = delim.get_length(); assert(max > 0); // Optimization for 3 or less delimiters switch (max) { default: break; case 1: return (delim.get_rune(0) == c); case 2: return (delim.get_rune(0) == c) || (delim.get_rune(1) == c); case 3: return (delim.get_rune(0) == c) || (delim.get_rune(1) == c) || (delim.get_rune(2) == c); } for (auto i = word_t{ 0 }; i < max; ++i) { if (delim.get_rune(i) == c) return true; } return false; }} voidSys_tokenize(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_tokenize>(); // Initialize for failure. fp.ret->t0 = 0; dec_ref_count_and_free(vm_alloc_t::from_allocation(fp.ret->t1)); fp.ret->t1 = nullptr; auto s = vm_alloc_t::from_allocation<vm_string_t>(fp.s); if (s == nullptr || s->get_length() == 0) return; auto curr_node = new vm_list_t{ intrinsic_type_desc::type<pointer_t>() }; // Set the head of the list fp.ret->t1 = curr_node->get_allocation(); auto delim = vm_alloc_t::from_allocation<vm_string_t>(fp.delim); if (delim == nullptr || delim->get_length() == 0) { // Add supplied string to list pt_ref(curr_node->value()) = s->get_allocation(); s->add_ref(); fp.ret->t0 = 1; return; } // Tokenize the string vm_list_t *prev_node = nullptr; auto n = word_t{ 0 }; auto begin = word_t{ 0 }; auto end = word_t{ 0 }; const auto len = s->get_length(); while (begin < len) { // Consume delimiters while (begin < len) { const auto rune = s->get_rune(begin); if (!is_delim(rune, *delim)) break; ++begin; } end = begin; // Consume non-delimiters while (end < len) { const auto rune = s->get_rune(end); if (is_delim(rune, *delim)) break; ++end; } // No progress - It is and isn't a delimiter (i.e. no more characters). if (begin == end) break; // Current node is initially non-null if (curr_node == nullptr) curr_node = new vm_list_t{ intrinsic_type_desc::type<pointer_t>() }; const auto token = new vm_string_t{ *s, begin, end }; pt_ref(curr_node->value()) = token->get_allocation(); // Previous node is initially null if (prev_node != nullptr) { prev_node->set_tail(curr_node); curr_node->release(); } prev_node = curr_node; curr_node = nullptr; begin = end; ++n; } fp.ret->t0 = n;} voidSys_unmount(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_unmount>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_utfbytes(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_utfbytes>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_werrstr(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_werrstr>(); throw vm_system_exception{ "Instruction not implemented" };} voidSys_write(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_write>(); const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); auto n = fp.n; if (buffer == nullptr || n <= 0) { *fp.ret = 0; return; } // [SPEC] Supplying a size greater than the buffer length is // equivalent to indicating the entire buffer should be written. n = std::min(n, buffer->get_length()); auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); assert(fd_alloc->alloc_type == T_FD); auto fd = fd_alloc->get_allocation<vm_fd_t>(); fd->write(n, buffer->at(0)); *fp.ret = n;} voidSys_wstat(vm_registers_t &r, vm_t &vm){ auto &fp = r.stack.peek_frame()->base<F_Sys_wstat>(); throw vm_system_exception{ "Instruction not implemented" };}Lines 501–860 of 860. Previous lines
void Sys_millisec(vm_registers_t &r, vm_t &vm) { const auto current_time = std::chrono::steady_clock::now(); const auto current_time_in_ms = std::chrono::duration_cast<std::chrono::milliseconds>(current_time.time_since_epoch()); auto &fp = r.stack.peek_frame()->base<F_Sys_millisec>(); *fp.ret = static_cast<word_t>(current_time_in_ms.count()); } void Sys_mount(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_mount>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_open(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_open>(); auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s); const auto open_mode = convert_to_openmode(fp.mode); // [TODO] Handle opening devices - not just files (i.e. /dev/random, /dev/source, /proc/1234) auto file_stream = sys::create_file_stream(path->str(), (open_mode | std::ios::binary)); // Return null if file stream is not open. if (file_stream == nullptr) { *fp.ret = nullptr; return; } vm_alloc_t *fd_alloc; auto fd = word_t{}; std::tie(fd, fd_alloc) = vm_fd_t::create(std::move(file_stream), fp.mode, path); if (debug::is_component_tracing_enabled<debug::component_trace_t::builtin>()) { debug::log_msg( debug::component_trace_t::builtin, debug::log_level_t::debug, "sys: open: %d >>%s<< %#x\n", fd, path->str(), fp.mode); } *fp.ret = fd_alloc->get_allocation(); } void Sys_pctl(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_pctl>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_pipe(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_pipe>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_pread(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_pread>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_print(vm_registers_t &r, vm_t &vm) { auto fp_base = r.stack.peek_frame()->base(); auto &fp = r.stack.peek_frame()->base<F_Sys_print>(); auto str = vm_alloc_t::from_allocation<vm_string_t>(fp.s); if (str == nullptr) throw dereference_nil{ "Print string" }; auto static_buffer = std::array<char, 1024>{}; auto msg_args = &fp.vargs; auto written = sys::printf_to_buffer(*str, msg_args, fp_base, static_buffer.size(), static_buffer.data()); if (written >= 0) { fd_stdout->write(written, static_buffer.data()); } else { auto dynamic_buffer = std::vector<char>(static_buffer.size() * 2); written = sys::printf_to_dynamic_buffer(*str, msg_args, fp_base, dynamic_buffer); fd_stdout->write(written, dynamic_buffer.data()); } *fp.ret = written; } void Sys_pwrite(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_pwrite>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_read(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_read>(); const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); auto n = fp.n; if (buffer == nullptr || n <= 0) { *fp.ret = 0; return; } // [SPEC] Supplying a size greater than the buffer length is // equivalent to indicating the entire buffer should be filled. n = std::min(n, buffer->get_length()); auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); assert(fd_alloc->alloc_type == T_FD); auto fd = fd_alloc->get_allocation<vm_fd_t>(); *fp.ret = fd->read(n, buffer->at(0)); } void Sys_readn(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_readn>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_remove(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_remove>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_seek(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_seek>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_sleep(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_sleep>(); const auto period_ms = fp.period; // [TODO] Thread should yield to another according to the sleep() specification. std::this_thread::sleep_for(std::chrono::milliseconds(period_ms)); *fp.ret = 0; } void Sys_sprint(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_sprint>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_stat(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_stat>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_stream(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_stream>(); throw vm_system_exception{ "Instruction not implemented" }; } namespace { bool is_delim(const rune_t c, const vm_string_t &delim) { const auto max = delim.get_length(); assert(max > 0); // Optimization for 3 or less delimiters switch (max) { default: break; case 1: return (delim.get_rune(0) == c); case 2: return (delim.get_rune(0) == c) || (delim.get_rune(1) == c); case 3: return (delim.get_rune(0) == c) || (delim.get_rune(1) == c) || (delim.get_rune(2) == c); } for (auto i = word_t{ 0 }; i < max; ++i) { if (delim.get_rune(i) == c) return true; } return false; } } void Sys_tokenize(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_tokenize>(); // Initialize for failure. fp.ret->t0 = 0; dec_ref_count_and_free(vm_alloc_t::from_allocation(fp.ret->t1)); fp.ret->t1 = nullptr; auto s = vm_alloc_t::from_allocation<vm_string_t>(fp.s); if (s == nullptr || s->get_length() == 0) return; auto curr_node = new vm_list_t{ intrinsic_type_desc::type<pointer_t>() }; // Set the head of the list fp.ret->t1 = curr_node->get_allocation(); auto delim = vm_alloc_t::from_allocation<vm_string_t>(fp.delim); if (delim == nullptr || delim->get_length() == 0) { // Add supplied string to list pt_ref(curr_node->value()) = s->get_allocation(); s->add_ref(); fp.ret->t0 = 1; return; } // Tokenize the string vm_list_t *prev_node = nullptr; auto n = word_t{ 0 }; auto begin = word_t{ 0 }; auto end = word_t{ 0 }; const auto len = s->get_length(); while (begin < len) { // Consume delimiters while (begin < len) { const auto rune = s->get_rune(begin); if (!is_delim(rune, *delim)) break; ++begin; } end = begin; // Consume non-delimiters while (end < len) { const auto rune = s->get_rune(end); if (is_delim(rune, *delim)) break; ++end; } // No progress - It is and isn't a delimiter (i.e. no more characters). if (begin == end) break; // Current node is initially non-null if (curr_node == nullptr) curr_node = new vm_list_t{ intrinsic_type_desc::type<pointer_t>() }; const auto token = new vm_string_t{ *s, begin, end }; pt_ref(curr_node->value()) = token->get_allocation(); // Previous node is initially null if (prev_node != nullptr) { prev_node->set_tail(curr_node); curr_node->release(); } prev_node = curr_node; curr_node = nullptr; begin = end; ++n; } fp.ret->t0 = n; } void Sys_unmount(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_unmount>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_utfbytes(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_utfbytes>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_werrstr(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_werrstr>(); throw vm_system_exception{ "Instruction not implemented" }; } void Sys_write(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_write>(); const auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.buf); assert(buffer->get_element_type()->size_in_bytes == intrinsic_type_desc::type<byte_t>()->size_in_bytes); auto n = fp.n; if (buffer == nullptr || n <= 0) { *fp.ret = 0; return; } // [SPEC] Supplying a size greater than the buffer length is // equivalent to indicating the entire buffer should be written. n = std::min(n, buffer->get_length()); auto fd_alloc = vm_alloc_t::from_allocation(fp.fd); assert(fd_alloc->alloc_type == T_FD); auto fd = fd_alloc->get_allocation<vm_fd_t>(); fd->write(n, buffer->at(0)); *fp.ret = n; } void Sys_wstat(vm_registers_t &r, vm_t &vm) { auto &fp = r.stack.peek_frame()->base<F_Sys_wstat>(); throw vm_system_exception{ "Instruction not implemented" }; }