History

Merge remote-tracking branch 'origin/master' into issue_11_fp

arr committed 9 years ago

Commit a50301e2 parents b3354b2 157f07717 files · +1482 −339Browse files

Unified · Split

17 files
  1. limbo/compiler/typecheck.b +3 −1
  2. readme.md +51 −0
  3. src/include/exceptions.h +9 −0
  4. src/include/utils.h +4 −4
  5. src/vm/address_decoding.inc +16 −4
  6. src/vm/disvm.gyp +3 −1
  7. src/vm/execution_table.cpp +77 −27
  8. src/vm/list.cpp +7 −5
  9. src/vm/math/Mathmod.cpp +209 −15
  10. src/vm/math/dgemm.c +411 −0
  11. src/vm/math/lsame.c +113 −0
  12. src/vm/sys/Sysmod.cpp +206 −175
  13. src/vm/sys/fd_manager.cpp +66 −47
  14. src/vm/sys/fd_types.cpp +217 −0
  15. src/vm/sys/fd_types.h +78 −0
  16. src/vm/sys/file_system.cpp +0 −46
  17. src/vm/sys/sys_utils.h +12 −14
limbo/compiler/typecheck.b+3−1
@@ -759,9 +759,11 @@ concheck(n: ref Node, isglobal: int) · 758 unmodified lines
759exname(d: ref Decl): string759exname(d: ref Decl): string
760{760{
761 s := "";761 s := "";
762 m := impmods.sym;762 m : ref Sym;
763 if(d.dot != nil)763 if(d.dot != nil)
764 m = d.dot.sym;764 m = d.dot.sym;
765 else if(impmods != nil)
766 m = impmods.sym;
765 if(m != nil)767 if(m != nil)
766 s += m.name+".";768 s += m.name+".";
767 if(fndec != nil)769 if(fndec != nil)
readme.md+51−0
@@ -116,6 +116,57 @@ The above copyright notice and this permission notice shall be included in all c · 115 unmodified lines
116 116
117THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.117THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
118 118
119### [LAPACK](http://www.netlib.org/lapack/#_licensing) ###
120
121Copyright (c) 1992-2013 The University of Tennessee and The University
122 of Tennessee Research Foundation. All rights
123 reserved.
124Copyright (c) 2000-2013 The University of California Berkeley. All
125 rights reserved.
126Copyright (c) 2006-2013 The University of Colorado Denver. All rights
127 reserved.
128
129$COPYRIGHT$
130
131Additional copyrights may follow
132
133$HEADER$
134
135Redistribution and use in source and binary forms, with or without
136modification, are permitted provided that the following conditions are
137met:
138
139- Redistributions of source code must retain the above copyright
140 notice, this list of conditions and the following disclaimer.
141
142- Redistributions in binary form must reproduce the above copyright
143 notice, this list of conditions and the following disclaimer listed
144 in this license in the documentation and/or other materials
145 provided with the distribution.
146
147- Neither the name of the copyright holders nor the names of its
148 contributors may be used to endorse or promote products derived from
149 this software without specific prior written permission.
150
151The copyright holders provide no reassurances that the source code
152provided does not infringe any patent, copyright, or any other
153intellectual property rights of third parties. The copyright holders
154disclaim any liability to any recipient for claims brought against
155recipient by any third party for infringement of that parties
156intellectual property rights.
157
158THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
159"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
160LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
161A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
162OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
163SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
164LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
165DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
166THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
167(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
168OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
169
119### Unless otherwise stated in a `license.txt` or above - [MIT License](https://opensource.org/licenses/MIT) ###170### Unless otherwise stated in a `license.txt` or above - [MIT License](https://opensource.org/licenses/MIT) ###
120 171
121Copyright (c) 2017 arr172Copyright (c) 2017 arr
src/include/exceptions.h+9−0
@@ -124,6 +124,15 @@ namespace disvm · 123 unmodified lines
124 const word_t invalid_value;124 const word_t invalid_value;
125 };125 };
126 126
127 // [TODO] Allow non-string exceptions to be marshalled.
128 class marshallable_user_exception final : public vm_user_exception
129 {
130 public:
131 explicit marshallable_user_exception(const char *message)
132 : vm_user_exception(message)
133 { }
134 };
135
127 class unhandled_user_exception final : public vm_user_exception136 class unhandled_user_exception final : public vm_user_exception
128 {137 {
129 public:138 public:
src/include/utils.h+4−4
@@ -76,12 +76,12 @@ namespace disvm · 75 unmodified lines
76 76
77// Adopted from 'winnt.h' in the Windows SDK77// Adopted from 'winnt.h' in the Windows SDK
78#define DEFINE_ENUM_FLAG_OPERATORS(TYPE) \78#define DEFINE_ENUM_FLAG_OPERATORS(TYPE) \
79inline TYPE operator | (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) | static_cast<std::underlying_type_t<TYPE>>(b)); } \79constexpr TYPE operator | (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) | static_cast<std::underlying_type_t<TYPE>>(b)); } \
80inline TYPE &operator |= (TYPE &a, TYPE b) { a = a | b; return a; } \80inline TYPE &operator |= (TYPE &a, TYPE b) { a = a | b; return a; } \
81inline TYPE operator & (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) & static_cast<std::underlying_type_t<TYPE>>(b)); } \81constexpr TYPE operator & (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) & static_cast<std::underlying_type_t<TYPE>>(b)); } \
82inline TYPE &operator &= (TYPE &a, TYPE b) { a = a & b; return a; } \82inline TYPE &operator &= (TYPE &a, TYPE b) { a = a & b; return a; } \
83inline TYPE operator ^ (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) ^ static_cast<std::underlying_type_t<TYPE>>(b)); } \83constexpr TYPE operator ^ (TYPE a, TYPE b) { return static_cast<TYPE>(static_cast<std::underlying_type_t<TYPE>>(a) ^ static_cast<std::underlying_type_t<TYPE>>(b)); } \
84inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \84inline TYPE &operator ^= (TYPE &a, TYPE b) { a = a ^ b; return a; } \
85inline TYPE operator ~ (TYPE a) { return static_cast<TYPE>(~static_cast<std::underlying_type_t<TYPE>>(a)); }85constexpr TYPE operator ~ (TYPE a) { return static_cast<TYPE>(~static_cast<std::underlying_type_t<TYPE>>(a)); }
86 86
87#endif // _DISVM_SRC_INCLUDE_UTILS_H_87#endif // _DISVM_SRC_INCLUDE_UTILS_H_
src/vm/address_decoding.inc+16−4
@@ -32,7 +32,10 @@ void dec_src<address_mode_t::offset_double_indirect_fp>(const vm_exec_op_t &inst · 31 unmodified lines
32{32{
33 assert(inst.source.mode == address_mode_t::offset_double_indirect_fp);33 assert(inst.source.mode == address_mode_t::offset_double_indirect_fp);
34 const auto frame_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.stack.peek_frame()->base()) + inst.source.register1);34 const auto frame_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.stack.peek_frame()->base()) + inst.source.register1);
35 reg.src = reinterpret_cast<pointer_t>(frame_offset + inst.source.register2);35 if (frame_offset != disvm::runtime::runtime_constants::nil)
36 reg.src = reinterpret_cast<pointer_t>(frame_offset + inst.source.register2);
37 else
38 reg.src = reinterpret_cast<pointer_t>(disvm::runtime::runtime_constants::nil);
36}39}
37 40
38template<>41template<>
@@ -40,7 +43,10 @@ void dec_src<address_mode_t::offset_double_indirect_mp>(const vm_exec_op_t &inst · 1 unmodified line
40{43{
41 assert(inst.source.mode == address_mode_t::offset_double_indirect_mp);44 assert(inst.source.mode == address_mode_t::offset_double_indirect_mp);
42 const auto mp_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.mp_base->get_allocation()) + inst.source.register1);45 const auto mp_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.mp_base->get_allocation()) + inst.source.register1);
43 reg.src = reinterpret_cast<pointer_t>(mp_offset + inst.source.register2);46 if (mp_offset != disvm::runtime::runtime_constants::nil)
47 reg.src = reinterpret_cast<pointer_t>(mp_offset + inst.source.register2);
48 else
49 reg.src = reinterpret_cast<pointer_t>(disvm::runtime::runtime_constants::nil);
44}50}
45 51
46template<>52template<>
@@ -85,7 +91,10 @@ void dec_dest<address_mode_t::offset_double_indirect_fp>(const vm_exec_op_t &ins · 38 unmodified lines
85{91{
86 assert(inst.destination.mode == address_mode_t::offset_double_indirect_fp);92 assert(inst.destination.mode == address_mode_t::offset_double_indirect_fp);
87 const auto frame_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.stack.peek_frame()->base()) + inst.destination.register1);93 const auto frame_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.stack.peek_frame()->base()) + inst.destination.register1);
88 reg.dest = reinterpret_cast<pointer_t>(frame_offset + inst.destination.register2);94 if (frame_offset != disvm::runtime::runtime_constants::nil)
95 reg.dest = reinterpret_cast<pointer_t>(frame_offset + inst.destination.register2);
96 else
97 reg.dest = reinterpret_cast<pointer_t>(disvm::runtime::runtime_constants::nil);
89}98}
90 99
91template<>100template<>
@@ -93,7 +102,10 @@ void dec_dest<address_mode_t::offset_double_indirect_mp>(const vm_exec_op_t &ins · 1 unmodified line
93{102{
94 assert(inst.destination.mode == address_mode_t::offset_double_indirect_mp);103 assert(inst.destination.mode == address_mode_t::offset_double_indirect_mp);
95 const auto mp_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.mp_base->get_allocation()) + inst.destination.register1);104 const auto mp_offset = *reinterpret_cast<std::size_t *>(reinterpret_cast<uint8_t *>(reg.mp_base->get_allocation()) + inst.destination.register1);
96 reg.dest = reinterpret_cast<pointer_t>(mp_offset + inst.destination.register2);105 if (mp_offset != disvm::runtime::runtime_constants::nil)
106 reg.dest = reinterpret_cast<pointer_t>(mp_offset + inst.destination.register2);
107 else
108 reg.dest = reinterpret_cast<pointer_t>(disvm::runtime::runtime_constants::nil);
97}109}
98 110
99template<>111template<>
src/vm/disvm.gyp+3−1
@@ -24,10 +24,12 @@ · 23 unmodified lines
24 'vm_memory.cpp',24 'vm_memory.cpp',
25 'vm_exception_handler.cpp',25 'vm_exception_handler.cpp',
26 'math/Mathmod.cpp',26 'math/Mathmod.cpp',
27 'math/dgemm.c',
28 'math/lsame.c',
27 'sys/print.cpp',29 'sys/print.cpp',
28 'sys/Sysmod.cpp',30 'sys/Sysmod.cpp',
29 'sys/file_system.cpp',
30 'sys/fd_manager.cpp',31 'sys/fd_manager.cpp',
32 'sys/fd_types.cpp',
31 ],33 ],
32 'include_dirs': [34 'include_dirs': [
33 '../include'35 '../include'
src/vm/execution_table.cpp+77−27
@@ -164,7 +164,7 @@ namespace · 163 unmodified lines
164 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));164 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));
165 165
166 auto str = at_val<vm_string_t>(r.src);166 auto str = at_val<vm_string_t>(r.src);
167 auto new_array = new vm_array_t(str);167 auto new_array = new vm_array_t{ str };
168 pt_ref(r.dest) = new_array->get_allocation();168 pt_ref(r.dest) = new_array->get_allocation();
169 }169 }
170 170
@@ -537,7 +537,7 @@ namespace · 366 unmodified lines
537 auto type_id = vt_ref<word_t>(r.mid);537 auto type_id = vt_ref<word_t>(r.mid);
538 const auto &types = r.module_ref->type_section;538 const auto &types = r.module_ref->type_section;
539 assert(0 <= type_id && type_id < static_cast<word_t>(types.size()));539 assert(0 <= type_id && type_id < static_cast<word_t>(types.size()));
540 auto type = types[type_id];540 const auto &type = types[type_id];
541 541
542 disvm::runtime::inc_ref_count_in_memory(*type, r.src);542 disvm::runtime::inc_ref_count_in_memory(*type, r.src);
543 destroy_memory(*type, r.dest);543 destroy_memory(*type, r.dest);
@@ -853,7 +853,7 @@ namespace · 309 unmodified lines
853 throw out_of_range_memory{};853 throw out_of_range_memory{};
854 }854 }
855 855
856 auto new_array = new vm_array_t(*arr, begin_index, length);856 auto new_array = new vm_array_t{ *arr, begin_index, length };
857 857
858 if (arr->alloc_type->map_in_bytes > 0)858 if (arr->alloc_type->map_in_bytes > 0)
859 vm.get_garbage_collector().track_allocation(new_array);859 vm.get_garbage_collector().track_allocation(new_array);
@@ -971,14 +971,15 @@ namespace · 111 unmodified lines
971 auto tail_maybe = at_val<vm_list_t>(r.dest);971 auto tail_maybe = at_val<vm_list_t>(r.dest);
972 972
973 // Create a new list973 // Create a new list
974 auto new_list = new vm_list_t{ type, tail_maybe };974 const auto type_size_in_bytes = type->size_in_bytes;
975 auto new_list = new vm_list_t{ std::move(type), tail_maybe };
975 if (tail_maybe != nullptr)976 if (tail_maybe != nullptr)
976 tail_maybe->release();977 tail_maybe->release();
977 978
978 auto destination = new_list->value();979 auto destination = new_list->value();
979 std::memmove(destination, r.src, type->size_in_bytes);980 std::memmove(destination, r.src, type_size_in_bytes);
980 981
981 if (type->map_in_bytes > 0)982 if (type_size_in_bytes > 0)
982 vm.get_garbage_collector().track_allocation(new_list);983 vm.get_garbage_collector().track_allocation(new_list);
983 984
984 // Return the list985 // Return the list
@@ -1329,9 +1330,10 @@ namespace · 344 unmodified lines
1329 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));1330 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));
1330 1331
1331 auto type_desc = types[type_id];1332 auto type_desc = types[type_id];
1332 auto new_alloc = vm_alloc_t::allocate(type_desc);1333 const auto track_object = type_desc->map_in_bytes > 0;
1334 auto new_alloc = vm_alloc_t::allocate(std::move(type_desc));
1333 1335
1334 if (type_desc->map_in_bytes > 0)1336 if (track_object)
1335 vm.get_garbage_collector().track_allocation(new_alloc);1337 vm.get_garbage_collector().track_allocation(new_alloc);
1336 1338
1337 pt_ref(r.dest) = new_alloc->get_allocation();1339 pt_ref(r.dest) = new_alloc->get_allocation();
@@ -1363,9 +1365,10 @@ namespace · 25 unmodified lines
1363 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));1365 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));
1364 1366
1365 auto type_desc = types[type_id];1367 auto type_desc = types[type_id];
1366 auto new_alloc = vm_alloc_t::allocate(type_desc);1368 const auto track_object = type_desc->map_in_bytes > 0;
1369 auto new_alloc = vm_alloc_t::allocate(std::move(type_desc));
1367 1370
1368 if (type_desc->map_in_bytes > 0)1371 if (track_object)
1369 vm.get_garbage_collector().track_allocation(new_alloc);1372 vm.get_garbage_collector().track_allocation(new_alloc);
1370 1373
1371 pt_ref(r.dest) = new_alloc->get_allocation();1374 pt_ref(r.dest) = new_alloc->get_allocation();
@@ -1385,9 +1388,10 @@ namespace · 13 unmodified lines
1385 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));1388 dec_ref_count_and_free(at_val<vm_alloc_t>(r.dest));
1386 1389
1387 const auto array_size = vt_ref<word_t>(r.src);1390 const auto array_size = vt_ref<word_t>(r.src);
1388 auto new_array = new vm_array_t(type_desc, array_size);1391 const auto track_object = type_desc->map_in_bytes > 0;
1392 auto new_array = new vm_array_t{ std::move(type_desc), array_size };
1389 1393
1390 if (type_desc->map_in_bytes > 0)1394 if (track_object)
1391 vm.get_garbage_collector().track_allocation(new_array);1395 vm.get_garbage_collector().track_allocation(new_array);
1392 1396
1393 pt_ref(r.dest) = new_array->get_allocation();1397 pt_ref(r.dest) = new_array->get_allocation();
@@ -1437,7 +1441,7 @@ namespace · 43 unmodified lines
1437 1441
1438 const auto frame_type_id = vt_ref<word_t>(r.src);1442 const auto frame_type_id = vt_ref<word_t>(r.src);
1439 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));1443 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));
1440 const auto frame_type = types[frame_type_id];1444 auto frame_type = types[frame_type_id];
1441 1445
1442 pt_ref(r.dest) = r.stack.alloc_frame(std::move(frame_type))->base();1446 pt_ref(r.dest) = r.stack.alloc_frame(std::move(frame_type))->base();
1443 }1447 }
@@ -1456,9 +1460,9 @@ namespace · 12 unmodified lines
1456 1460
1457 const auto frame_type_id = function_ref.frame_type;1461 const auto frame_type_id = function_ref.frame_type;
1458 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));1462 assert(0 <= frame_type_id && frame_type_id < static_cast<word_t>(types.size()));
1459 const auto frame_type = types[frame_type_id];1463 auto frame_type = types[frame_type_id];
1460 1464
1461 pt_ref(r.dest) = r.stack.alloc_frame(frame_type)->base();1465 pt_ref(r.dest) = r.stack.alloc_frame(std::move(frame_type))->base();
1462 }1466 }
1463 1467
1464 EXEC_DECL(ret)1468 EXEC_DECL(ret)
@@ -1503,6 +1507,9 @@ namespace · 38 unmodified lines
1503 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");
1504 }1508 }
1505 1509
1510 // Forward declaration
1511 EXEC_DECL(raise);
1512
1506 EXEC_DECL(mcall)1513 EXEC_DECL(mcall)
1507 {1514 {
1508 auto target_module = at_val<vm_module_ref_t>(r.dest);1515 auto target_module = at_val<vm_module_ref_t>(r.dest);
@@ -1547,22 +1554,52 @@ namespace · 38 unmodified lines
1547 r.mp_base = r.module_ref->mp_base;1554 r.mp_base = r.module_ref->mp_base;
1548 r.next_pc = function_pc;1555 r.next_pc = function_pc;
1549 1556
1550 if (r.module_ref->is_builtin_module())1557 // Non-built-in modules ref count and return
1558 if (!r.module_ref->is_builtin_module())
1551 {1559 {
1552 const auto &inst = r.module_ref->code_section[function_pc];1560 r.mp_base->add_ref();
1553 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.
1554 1570
1555 r.current_thread_state = vm_thread_state_t::release;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)");
1573
1574 vm_alloc_t *marshallable_err{};
1575 r.current_thread_state = vm_thread_state_t::release;
1576
1577 try
1578 {
1556 inst.native(r, vm);1579 inst.native(r, vm);
1557 ret(r, vm);
1558 1580
1559 // Only reset the thread if it is in the state set prior to native call.1581 // Handle callee clean-up semantics
1560 if (r.current_thread_state == vm_thread_state_t::release)1582 ret(r, vm);
1561 r.current_thread_state = vm_thread_state_t::running;
1562 }1583 }
1563 else1584 catch (const marshallable_user_exception &e)
1564 {1585 {
1565 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);
1566 }1603 }
1567 }1604 }
1568 1605
@@ -1706,10 +1743,23 @@ namespace · 137 unmodified lines
1706 1743
1707 if (target_frame != r.stack.peek_frame())1744 if (target_frame != r.stack.peek_frame())
1708 {1745 {
1709 while (target_frame != r.stack.pop_frame())1746 // Unwind stack to find target frame
1747 do
1710 {1748 {
1711 // 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 }
1712 }1761 }
1762 while (target_frame != r.stack.pop_frame());
1713 }1763 }
1714 1764
1715 // Re-initialize the current frame1765 // Re-initialize the current frame
src/vm/list.cpp+7−5
@@ -45,10 +45,6 @@ vm_list_t::vm_list_t(std::shared_ptr<const type_descriptor_t> td, vm_list_t *tai · 44 unmodified lines
45 45
46vm_list_t::~vm_list_t()46vm_list_t::~vm_list_t()
47{47{
48 // Remove tail
49 dec_ref_count_and_free(_tail);
50 debug::assign_debug_pointer(&_tail);
51
52 // Destroy and free the list element, if default element size was surpassed.48 // Destroy and free the list element, if default element size was surpassed.
53 if (_is_alloc)49 if (_is_alloc)
54 {50 {
@@ -61,7 +57,13 @@ vm_list_t::~vm_list_t() · 6 unmodified lines
61 }57 }
62 58
63 debug::assign_debug_pointer(&_mem.alloc);59 debug::assign_debug_pointer(&_mem.alloc);
64 disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "destroy: vm list");60
61 // Remove tail
62 dec_ref_count_and_free(_tail);
63 debug::assign_debug_pointer(&_tail);
64
65 if (disvm::debug::is_component_tracing_enabled<component_trace_t::memory>())
66 disvm::debug::log_msg(component_trace_t::memory, log_level_t::debug, "destroy: vm list");
65}67}
66 68
67std::shared_ptr<const type_descriptor_t> vm_list_t::get_element_type() const69std::shared_ptr<const type_descriptor_t> vm_list_t::get_element_type() const
src/vm/math/Mathmod.cpp+209−15
@@ -24,6 +24,7 @@ using disvm::debug::log_level_t; · 23 unmodified lines
24 24
25using disvm::runtime::dereference_nil;25using disvm::runtime::dereference_nil;
26using disvm::runtime::intrinsic_type_desc;26using disvm::runtime::intrinsic_type_desc;
27using disvm::runtime::out_of_range_memory;
27using disvm::runtime::real_t;28using disvm::runtime::real_t;
28using disvm::runtime::vm_alloc_t;29using disvm::runtime::vm_alloc_t;
29using disvm::runtime::vm_array_t;30using disvm::runtime::vm_array_t;
@@ -430,7 +431,28 @@ void · 400 unmodified lines
430Math_export_int(vm_registers_t &r, vm_t &vm)431Math_export_int(vm_registers_t &r, vm_t &vm)
431{432{
432 auto &fp = r.stack.peek_frame()->base<F_Math_export_int>();433 auto &fp = r.stack.peek_frame()->base<F_Math_export_int>();
433 throw vm_system_exception{ "Function not implemented" };434
435 auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.b);
436 assert(buffer->get_element_type()->is_equal(intrinsic_type_desc::type<byte_t>().get()));
437
438 auto values = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
439 assert(values->get_element_type()->is_equal(intrinsic_type_desc::type<word_t>().get()));
440 const auto values_len = values->get_length();
441
442 if (buffer->get_length() != (sizeof(word_t) * values_len))
443 throw vm_user_exception{ "Invalid buffer size based on conversion" };
444
445 // Insert as big endian
446 for (int i = 0; i < values_len; ++i)
447 {
448 auto x = values->at<word_t>(i);
449
450 auto base = reinterpret_cast<byte_t *>(buffer->at(i * sizeof(x)));
451 base[0] = static_cast<byte_t>(x >> 24);
452 base[1] = static_cast<byte_t>(x >> 16);
453 base[2] = static_cast<byte_t>(x >> 8);
454 base[3] = static_cast<byte_t>(x);
455 }
434}456}
435 457
436void458void
@@ -445,7 +467,7 @@ Math_export_real(vm_registers_t &r, vm_t &vm) · 8 unmodified lines
445 assert(values->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));467 assert(values->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
446 const auto values_len = values->get_length();468 const auto values_len = values->get_length();
447 469
448 if (buffer->get_length() != (8 * values_len))470 if (buffer->get_length() != (sizeof(real_t) * values_len))
449 throw vm_user_exception{ "Invalid buffer size based on conversion" };471 throw vm_user_exception{ "Invalid buffer size based on conversion" };
450 472
451 // Insert as big endian473 // Insert as big endian
@@ -472,7 +494,32 @@ void · 20 unmodified lines
472Math_export_real32(vm_registers_t &r, vm_t &vm)494Math_export_real32(vm_registers_t &r, vm_t &vm)
473{495{
474 auto &fp = r.stack.peek_frame()->base<F_Math_export_real32>();496 auto &fp = r.stack.peek_frame()->base<F_Math_export_real32>();
475 throw vm_system_exception{ "Function not implemented" };497
498 auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.b);
499 assert(buffer->get_element_type()->is_equal(intrinsic_type_desc::type<byte_t>().get()));
500
501 auto values = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
502 assert(values->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
503 const auto values_len = values->get_length();
504
505 if (buffer->get_length() != (sizeof(float) * values_len))
506 throw vm_user_exception{ "Invalid buffer size based on conversion" };
507
508 // Insert as big endian
509 for (int i = 0; i < values_len; ++i)
510 {
511 auto x_r = values->at<real_t>(i);
512 auto x = static_cast<float>(x_r);
513 uint32_t t;
514 std::memcpy(&t, &x, sizeof(x));
515 static_assert(sizeof(t) == sizeof(x), "Short-real should be 32-bits");
516
517 auto base = reinterpret_cast<byte_t *>(buffer->at(i * sizeof(x)));
518 base[0] = static_cast<byte_t>(t >> 24);
519 base[1] = static_cast<byte_t>(t >> 16);
520 base[2] = static_cast<byte_t>(t >> 8);
521 base[3] = static_cast<byte_t>(t);
522 }
476}523}
477 524
478void525void
@@ -524,11 +571,71 @@ Math_fmod(vm_registers_t &r, vm_t &vm) · 45 unmodified lines
524 *fp.ret = std::fmod(fp.x, fp.y);571 *fp.ret = std::fmod(fp.x, fp.y);
525}572}
526 573
574// Forward declaration
575extern "C" int dgemm_(
576 char *transa, char *transb,
577 int *m, int *n, int *k,
578 double *alpha,
579 double *a, int *lda,
580 double *b, int *ldb,
581 double *beta,
582 double *c, int *ldc,
583 int a_len, int b_len, int c_len);
584
527void585void
528Math_gemm(vm_registers_t &r, vm_t &vm)586Math_gemm(vm_registers_t &r, vm_t &vm)
529{587{
530 auto &fp = r.stack.peek_frame()->base<F_Math_gemm>();588 auto &fp = r.stack.peek_frame()->base<F_Math_gemm>();
531 throw vm_system_exception{ "Function not implemented" };589
590 char t_a[2] = {};
591 t_a[0] = static_cast<char>(fp.transa);
592
593 char t_b[2] = {};
594 t_b[0] = static_cast<char>(fp.transb);
595
596 auto m = fp.m;
597 auto n = fp.n;
598 auto k = fp.k;
599
600 auto alpha = fp.alpha;
601 auto beta = fp.beta;
602
603 auto lda = fp.lda;
604 auto a_v = vm_alloc_t::from_allocation<vm_array_t>(fp.a);
605 if (a_v == nullptr)
606 throw dereference_nil{ "gemm - a" };
607
608 auto ldb = fp.ldb;
609 auto b_v = vm_alloc_t::from_allocation<vm_array_t>(fp.b);
610 if (b_v == nullptr)
611 throw dereference_nil{ "gemm - b" };
612
613 auto ldc = fp.ldc;
614 auto c_v = vm_alloc_t::from_allocation<vm_array_t>(fp.c);
615 if (c_v == nullptr)
616 throw dereference_nil{ "gemm - c" };
617
618 assert(a_v->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
619 assert(b_v->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
620 assert(c_v->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
621
622 const auto a_len = a_v->get_length();
623 const auto b_len = b_v->get_length();
624 const auto c_len = c_v->get_length();
625
626 // Call BLAS version of function
627 const auto result = dgemm_(
628 t_a, t_b,
629 &m, &n, &k,
630 &alpha,
631 reinterpret_cast<double *>(a_v->at(0)), &lda,
632 reinterpret_cast<double *>(b_v->at(0)), &ldb,
633 &beta,
634 reinterpret_cast<double *>(c_v->at(0)), &ldc,
635 a_len, b_len, c_len);
636
637 if (result != 0)
638 throw vm_user_exception{ "gemm invalid argument" };
532}639}
533 640
534void641void
@@ -556,7 +663,34 @@ void · 21 unmodified lines
556Math_iamax(vm_registers_t &r, vm_t &vm)663Math_iamax(vm_registers_t &r, vm_t &vm)
557{664{
558 auto &fp = r.stack.peek_frame()->base<F_Math_iamax>();665 auto &fp = r.stack.peek_frame()->base<F_Math_iamax>();
559 throw vm_system_exception{ "Function not implemented" };666
667 // [SPEC] According to the Inferno implementation (libmath/blas.c), 0 is returned
668 // if the array is empty. This means there is no indication the supplied array was
669 // empty or the first index was max. The spec does not describe this condition,
670 // therefore this implementation will indicate with -1.
671 *fp.ret = -1;
672
673 auto result = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
674 assert(result->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
675 if (result->get_length() <= 0)
676 return;
677
678 auto r_raw = reinterpret_cast<real_t *>(result->at(0));
679
680 auto max_idx = 0;
681 auto r_len = result->get_length();
682 auto curr_max = std::fabs(r_raw[max_idx]);
683 for (auto i = word_t{ 1 }; i < r_len; ++i)
684 {
685 auto t = std::fabs(r_raw[i]);
686 if (curr_max < t)
687 {
688 max_idx = i;
689 curr_max = t;
690 }
691 }
692
693 *fp.ret = max_idx;
560}694}
561 695
562void696void
@@ -570,7 +704,27 @@ void · 7 unmodified lines
570Math_import_int(vm_registers_t &r, vm_t &vm)704Math_import_int(vm_registers_t &r, vm_t &vm)
571{705{
572 auto &fp = r.stack.peek_frame()->base<F_Math_import_int>();706 auto &fp = r.stack.peek_frame()->base<F_Math_import_int>();
573 throw vm_system_exception{ "Function not implemented" };707
708 auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.b);
709 assert(buffer->get_element_type()->is_equal(intrinsic_type_desc::type<byte_t>().get()));
710
711 auto result = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
712 assert(result->get_element_type()->is_equal(intrinsic_type_desc::type<word_t>().get()));
713 const auto result_len = result->get_length();
714
715 if (buffer->get_length() != (sizeof(word_t) * result_len))
716 throw vm_user_exception{ "Invalid buffer size based on conversion" };
717
718 // Process as big endian
719 for (int i = 0; i < result_len; ++i)
720 {
721 uint32_t t = buffer->at<byte_t>(0);
722 for (int j = 1; j < sizeof(word_t); ++j)
723 t = (t << 8) | buffer->at<byte_t>(j);
724
725 auto x = static_cast<word_t>(t);
726 result->at<word_t>(i) = x;
727 }
574}728}
575 729
576void730void
@@ -585,14 +739,14 @@ Math_import_real(vm_registers_t &r, vm_t &vm) · 8 unmodified lines
585 assert(result->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));739 assert(result->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
586 const auto result_len = result->get_length();740 const auto result_len = result->get_length();
587 741
588 if (buffer->get_length() != (8 * result_len))742 if (buffer->get_length() != (sizeof(real_t) * result_len))
589 throw vm_user_exception{ "Invalid buffer size based on conversion" };743 throw vm_user_exception{ "Invalid buffer size based on conversion" };
590 744
591 // Process as big endian745 // Process as big endian
592 for (int i = 0; i < result_len; ++i)746 for (int i = 0; i < result_len; ++i)
593 {747 {
594 uint64_t t = buffer->at<byte_t>(0);748 uint64_t t = buffer->at<byte_t>(0);
595 for (int j = 1; j < 8; ++j)749 for (int j = 1; j < sizeof(real_t); ++j)
596 t = (t << 8) | buffer->at<byte_t>(j);750 t = (t << 8) | buffer->at<byte_t>(j);
597 751
598 real_t x;752 real_t x;
@@ -607,7 +761,31 @@ void · 8 unmodified lines
607Math_import_real32(vm_registers_t &r, vm_t &vm)761Math_import_real32(vm_registers_t &r, vm_t &vm)
608{762{
609 auto &fp = r.stack.peek_frame()->base<F_Math_import_real32>();763 auto &fp = r.stack.peek_frame()->base<F_Math_import_real32>();
610 throw vm_system_exception{ "Function not implemented" };764
765 auto buffer = vm_alloc_t::from_allocation<vm_array_t>(fp.b);
766 assert(buffer->get_element_type()->is_equal(intrinsic_type_desc::type<byte_t>().get()));
767
768 auto result = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
769 assert(result->get_element_type()->is_equal(intrinsic_type_desc::type<real_t>().get()));
770 const auto result_len = result->get_length();
771
772 if (buffer->get_length() != (sizeof(float) * result_len))
773 throw vm_user_exception{ "Invalid buffer size based on conversion" };
774
775 // Process as big endian
776 for (int i = 0; i < result_len; ++i)
777 {
778 uint32_t t = buffer->at<byte_t>(0);
779 for (int j = 1; j < sizeof(float); ++j)
780 t = (t << 8) | buffer->at<byte_t>(j);
781
782 float x_f;
783 std::memcpy(&x_f, &t, sizeof(t));
784 static_assert(sizeof(t) == sizeof(x_f), "Short-real should be 32-bits");
785
786 auto x = real_t{ x_f };
787 result->at<real_t>(i) = x;
788 }
611}789}
612 790
613void791void
@@ -621,6 +799,8 @@ void · 7 unmodified lines
621Math_j0(vm_registers_t &r, vm_t &vm)799Math_j0(vm_registers_t &r, vm_t &vm)
622{800{
623 auto &fp = r.stack.peek_frame()->base<F_Math_j0>();801 auto &fp = r.stack.peek_frame()->base<F_Math_j0>();
802
803 // [PAL] Consume platform API
624 throw vm_system_exception{ "Function not implemented" };804 throw vm_system_exception{ "Function not implemented" };
625}805}
626 806
@@ -628,6 +808,8 @@ void · 1 unmodified line
628Math_j1(vm_registers_t &r, vm_t &vm)808Math_j1(vm_registers_t &r, vm_t &vm)
629{809{
630 auto &fp = r.stack.peek_frame()->base<F_Math_j1>();810 auto &fp = r.stack.peek_frame()->base<F_Math_j1>();
811
812 // [PAL] Consume platform API
631 throw vm_system_exception{ "Function not implemented" };813 throw vm_system_exception{ "Function not implemented" };
632}814}
633 815
@@ -635,6 +817,8 @@ void · 1 unmodified line
635Math_jn(vm_registers_t &r, vm_t &vm)817Math_jn(vm_registers_t &r, vm_t &vm)
636{818{
637 auto &fp = r.stack.peek_frame()->base<F_Math_jn>();819 auto &fp = r.stack.peek_frame()->base<F_Math_jn>();
820
821 // [PAL] Consume platform API
638 throw vm_system_exception{ "Function not implemented" };822 throw vm_system_exception{ "Function not implemented" };
639}823}
640 824
@@ -670,7 +854,13 @@ void · 29 unmodified lines
670Math_modf(vm_registers_t &r, vm_t &vm)854Math_modf(vm_registers_t &r, vm_t &vm)
671{855{
672 auto &fp = r.stack.peek_frame()->base<F_Math_modf>();856 auto &fp = r.stack.peek_frame()->base<F_Math_modf>();
673 throw vm_system_exception{ "Function not implemented" };857
858 real_t integral_out;
859 const auto fractional_part = std::modf(fp.x, &integral_out);
860 const auto integral_part = static_cast<word_t>(integral_out);
861
862 fp.ret->t0 = integral_part;
863 fp.ret->t1 = fractional_part;
674}864}
675 865
676void866void
@@ -705,9 +895,7 @@ Math_norm1(vm_registers_t &r, vm_t &vm) · 28 unmodified lines
705void895void
706Math_norm2(vm_registers_t &r, vm_t &vm)896Math_norm2(vm_registers_t &r, vm_t &vm)
707{897{
708 // [SPEC] This function is defined as: norm2(x) = sqrt(dot(x, x))898 // Defined as: norm2(x) = sqrt(dot(x, x))
709 // The Inferno implementation (libmath/blas.c) doesn't appear to take
710 // the square root of the resulting dot product.
711 auto &fp = r.stack.peek_frame()->base<F_Math_norm2>();899 auto &fp = r.stack.peek_frame()->base<F_Math_norm2>();
712 900
713 auto xs = vm_alloc_t::from_allocation<vm_array_t>(fp.x);901 auto xs = vm_alloc_t::from_allocation<vm_array_t>(fp.x);
@@ -740,7 +928,7 @@ void · 26 unmodified lines
740Math_pow10(vm_registers_t &r, vm_t &vm)928Math_pow10(vm_registers_t &r, vm_t &vm)
741{929{
742 auto &fp = r.stack.peek_frame()->base<F_Math_pow10>();930 auto &fp = r.stack.peek_frame()->base<F_Math_pow10>();
743 throw vm_system_exception{ "Function not implemented" };931 *fp.ret = std::pow(10., static_cast<real_t>(fp.p));
744}932}
745 933
746void934void
@@ -786,7 +974,7 @@ void · 39 unmodified lines
786Math_scalbn(vm_registers_t &r, vm_t &vm)974Math_scalbn(vm_registers_t &r, vm_t &vm)
787{975{
788 auto &fp = r.stack.peek_frame()->base<F_Math_scalbn>();976 auto &fp = r.stack.peek_frame()->base<F_Math_scalbn>();
789 throw vm_system_exception{ "Function not implemented" };977 *fp.ret = std::scalbln(fp.x, fp.n);
790}978}
791 979
792void980void
@@ -863,6 +1051,8 @@ void · 70 unmodified lines
863Math_y0(vm_registers_t &r, vm_t &vm)1051Math_y0(vm_registers_t &r, vm_t &vm)
864{1052{
865 auto &fp = r.stack.peek_frame()->base<F_Math_y0>();1053 auto &fp = r.stack.peek_frame()->base<F_Math_y0>();
1054
1055 // [PAL] Consume platform API
866 throw vm_system_exception{ "Function not implemented" };1056 throw vm_system_exception{ "Function not implemented" };
867}1057}
868 1058
@@ -870,6 +1060,8 @@ void · 1 unmodified line
870Math_y1(vm_registers_t &r, vm_t &vm)1060Math_y1(vm_registers_t &r, vm_t &vm)
871{1061{
872 auto &fp = r.stack.peek_frame()->base<F_Math_y1>();1062 auto &fp = r.stack.peek_frame()->base<F_Math_y1>();
1063
1064 // [PAL] Consume platform API
873 throw vm_system_exception{ "Function not implemented" };1065 throw vm_system_exception{ "Function not implemented" };
874}1066}
875 1067
@@ -877,5 +1069,7 @@ void · 1 unmodified line
877Math_yn(vm_registers_t &r, vm_t &vm)1069Math_yn(vm_registers_t &r, vm_t &vm)
878{1070{
879 auto &fp = r.stack.peek_frame()->base<F_Math_yn>();1071 auto &fp = r.stack.peek_frame()->base<F_Math_yn>();
1072
1073 // [PAL] Consume platform API
880 throw vm_system_exception{ "Function not implemented" };1074 throw vm_system_exception{ "Function not implemented" };
881}1075}
src/vm/math/dgemm.c+411−0
@@ -0,0 +1,411 @@
1
2/* -- translated by f2c (version 19940927).
3 You must link the resulting object file with the libraries:
4 -lf2c -lm (in that order)
5*/
6
7//#include "f2c.h"
8
9typedef int integer;
10typedef int logical;
11typedef double doublereal;
12
13#define max(a,b) ((a) > (b) ? (a) : (b))
14
15// Returns '1' based index of invalid argument, otherwise '0'
16/* Subroutine */ int dgemm_(char *transa, char *transb, integer *m, integer *
17 n, integer *k, doublereal *alpha, doublereal *a, integer *lda,
18 doublereal *b, integer *ldb, doublereal *beta, doublereal *c, integer
19 *ldc, int a_len, int b_len, int c_len)
20{
21
22
23 /* System generated locals */
24 integer /*a_dim1, a_offset, b_dim1, b_offset, c_dim1, c_offset, */ i__1, i__2,
25 i__3;
26
27 /* Local variables */
28 integer info;
29 logical nota, notb;
30 doublereal temp;
31 integer i, j, l, ncola, ncolb;
32 extern logical lsame_(char *, char *);
33 integer nrowa, nrowb;
34 //extern /* Subroutine */ int xerbla_(char *, integer *);
35
36
37/* Purpose
38 =======
39
40 DGEMM performs one of the matrix-matrix operations
41
42 C := alpha*op( A )*op( B ) + beta*C,
43
44 where op( X ) is one of
45
46 op( X ) = X or op( X ) = X',
47
48 alpha and beta are scalars, and A, B and C are matrices, with op( A )
49
50 an m by k matrix, op( B ) a k by n matrix and C an m by n matrix.
51
52
53 Parameters
54 ==========
55
56 TRANSA - CHARACTER*1.
57 On entry, TRANSA specifies the form of op( A ) to be used in
58
59 the matrix multiplication as follows:
60
61 TRANSA = 'N' or 'n', op( A ) = A.
62
63 TRANSA = 'T' or 't', op( A ) = A'.
64
65 TRANSA = 'C' or 'c', op( A ) = A'.
66
67 Unchanged on exit.
68
69 TRANSB - CHARACTER*1.
70 On entry, TRANSB specifies the form of op( B ) to be used in
71
72 the matrix multiplication as follows:
73
74 TRANSB = 'N' or 'n', op( B ) = B.
75
76 TRANSB = 'T' or 't', op( B ) = B'.
77
78 TRANSB = 'C' or 'c', op( B ) = B'.
79
80 Unchanged on exit.
81
82 M - INTEGER.
83 On entry, M specifies the number of rows of the matrix
84
85 op( A ) and of the matrix C. M must be at least zero.
86
87 Unchanged on exit.
88
89 N - INTEGER.
90 On entry, N specifies the number of columns of the matrix
91
92 op( B ) and the number of columns of the matrix C. N must be
93
94 at least zero.
95 Unchanged on exit.
96
97 K - INTEGER.
98 On entry, K specifies the number of columns of the matrix
99
100 op( A ) and the number of rows of the matrix op( B ). K must
101
102 be at least zero.
103 Unchanged on exit.
104
105 ALPHA - DOUBLE PRECISION.
106 On entry, ALPHA specifies the scalar alpha.
107 Unchanged on exit.
108
109 A - DOUBLE PRECISION array of DIMENSION ( LDA, ka ), where ka is
110
111 k when TRANSA = 'N' or 'n', and is m otherwise.
112 Before entry with TRANSA = 'N' or 'n', the leading m by k
113
114 part of the array A must contain the matrix A, otherwise
115
116 the leading k by m part of the array A must contain the
117
118 matrix A.
119 Unchanged on exit.
120
121 LDA - INTEGER.
122 On entry, LDA specifies the first dimension of A as declared
123
124 in the calling (sub) program. When TRANSA = 'N' or 'n' then
125
126 LDA must be at least max( 1, m ), otherwise LDA must be at
127
128 least max( 1, k ).
129 Unchanged on exit.
130
131 B - DOUBLE PRECISION array of DIMENSION ( LDB, kb ), where kb is
132
133 n when TRANSB = 'N' or 'n', and is k otherwise.
134 Before entry with TRANSB = 'N' or 'n', the leading k by n
135
136 part of the array B must contain the matrix B, otherwise
137
138 the leading n by k part of the array B must contain the
139
140 matrix B.
141 Unchanged on exit.
142
143 LDB - INTEGER.
144 On entry, LDB specifies the first dimension of B as declared
145
146 in the calling (sub) program. When TRANSB = 'N' or 'n' then
147
148 LDB must be at least max( 1, k ), otherwise LDB must be at
149
150 least max( 1, n ).
151 Unchanged on exit.
152
153 BETA - DOUBLE PRECISION.
154 On entry, BETA specifies the scalar beta. When BETA is
155
156 supplied as zero then C need not be set on input.
157 Unchanged on exit.
158
159 C - DOUBLE PRECISION array of DIMENSION ( LDC, n ).
160 Before entry, the leading m by n part of the array C must
161
162 contain the matrix C, except when beta is zero, in which
163
164 case C need not be set on entry.
165 On exit, the array C is overwritten by the m by n matrix
166
167 ( alpha*op( A )*op( B ) + beta*C ).
168
169 LDC - INTEGER.
170 On entry, LDC specifies the first dimension of C as declared
171
172 in the calling (sub) program. LDC must be at least
173
174 max( 1, m ).
175 Unchanged on exit.
176
177
178 Level 3 Blas routine.
179
180 -- Written on 8-February-1989.
181 Jack Dongarra, Argonne National Laboratory.
182 Iain Duff, AERE Harwell.
183 Jeremy Du Croz, Numerical Algorithms Group Ltd.
184 Sven Hammarling, Numerical Algorithms Group Ltd.
185
186
187
188 Set NOTA and NOTB as true if A and B respectively are not
189
190 transposed and set NROWA, NCOLA and NROWB as the number of rows
191
192 and columns of A and the number of rows of B respectively.
193
194
195
196 Parameter adjustments
197 Function Body */
198
199#define A(I,J) a[(I)-1 + ((J)-1)* ( *lda)]
200#define B(I,J) b[(I)-1 + ((J)-1)* ( *ldb)]
201#define C(I,J) c[(I)-1 + ((J)-1)* ( *ldc)]
202
203 nota = lsame_(transa, "N");
204 notb = lsame_(transb, "N");
205 if (nota) {
206 nrowa = *m;
207 ncola = *k;
208 } else {
209 nrowa = *k;
210 ncola = *m;
211 }
212 if (notb) {
213 nrowb = *k;
214 ncolb = *n;
215 } else {
216 nrowb = *n;
217 ncolb = *k;
218 }
219
220/* Test the input parameters. */
221
222 info = 0;
223 if (! nota && ! lsame_(transa, "C") && ! lsame_(transa, "T")) {
224 info = 1;
225 } else if (! notb && ! lsame_(transb, "C") && ! lsame_(transb,
226 "T")) {
227 info = 2;
228 } else if (*m < 0) {
229 info = 3;
230 } else if (*n < 0) {
231 info = 4;
232 } else if (*k < 0) {
233 info = 5;
234 } else if (((*lda) * (ncola - 1)) > a_len) {
235 info = 7; // A matrix
236 } else if (*lda < max(1,nrowa)) {
237 info = 8;
238 } else if (((*ldb) * (ncolb - 1)) > b_len) {
239 info = 9; // B matrix
240 } else if (*ldb < max(1,nrowb)) {
241 info = 10;
242 } else if (((*ldc) * (*n - 1)) > c_len) {
243 info = 12; // C matrix
244 } else if (*ldc < max(1,*m)) {
245 info = 13;
246 }
247
248 if (info != 0) {
249 //xerbla_("DGEMM ", &info);
250 return info;
251 }
252
253/* Quick return if possible. */
254
255 if (*m == 0 || *n == 0 || (*alpha == 0. || *k == 0) && *beta == 1.) {
256 return 0;
257 }
258
259/* And if alpha.eq.zero. */
260
261 if (*alpha == 0.) {
262 if (*beta == 0.) {
263 i__1 = *n;
264 for (j = 1; j <= *n; ++j) {
265 i__2 = *m;
266 for (i = 1; i <= *m; ++i) {
267 C(i,j) = 0.;
268/* L10: */
269 }
270/* L20: */
271 }
272 } else {
273 i__1 = *n;
274 for (j = 1; j <= *n; ++j) {
275 i__2 = *m;
276 for (i = 1; i <= *m; ++i) {
277 C(i,j) = *beta * C(i,j);
278/* L30: */
279 }
280/* L40: */
281 }
282 }
283 return 0;
284 }
285
286/* Start the operations. */
287
288 if (notb) {
289 if (nota) {
290
291/* Form C := alpha*A*B + beta*C. */
292
293 i__1 = *n;
294 for (j = 1; j <= *n; ++j) {
295 if (*beta == 0.) {
296 i__2 = *m;
297 for (i = 1; i <= *m; ++i) {
298 C(i,j) = 0.;
299/* L50: */
300 }
301 } else if (*beta != 1.) {
302 i__2 = *m;
303 for (i = 1; i <= *m; ++i) {
304 C(i,j) = *beta * C(i,j);
305/* L60: */
306 }
307 }
308 i__2 = *k;
309 for (l = 1; l <= *k; ++l) {
310 if (B(l,j) != 0.) {
311 temp = *alpha * B(l,j);
312 i__3 = *m;
313 for (i = 1; i <= *m; ++i) {
314 C(i,j) += temp * A(i,l);
315/* L70: */
316 }
317 }
318/* L80: */
319 }
320/* L90: */
321 }
322 } else {
323
324/* Form C := alpha*A'*B + beta*C */
325
326 i__1 = *n;
327 for (j = 1; j <= *n; ++j) {
328 i__2 = *m;
329 for (i = 1; i <= *m; ++i) {
330 temp = 0.;
331 i__3 = *k;
332 for (l = 1; l <= *k; ++l) {
333 temp += A(l,i) * B(l,j);
334/* L100: */
335 }
336 if (*beta == 0.) {
337 C(i,j) = *alpha * temp;
338 } else {
339 C(i,j) = *alpha * temp + *beta * C(i,j);
340 }
341/* L110: */
342 }
343/* L120: */
344 }
345 }
346 } else {
347 if (nota) {
348
349/* Form C := alpha*A*B' + beta*C */
350
351 i__1 = *n;
352 for (j = 1; j <= *n; ++j) {
353 if (*beta == 0.) {
354 i__2 = *m;
355 for (i = 1; i <= *m; ++i) {
356 C(i,j) = 0.;
357/* L130: */
358 }
359 } else if (*beta != 1.) {
360 i__2 = *m;
361 for (i = 1; i <= *m; ++i) {
362 C(i,j) = *beta * C(i,j);
363/* L140: */
364 }
365 }
366 i__2 = *k;
367 for (l = 1; l <= *k; ++l) {
368 if (B(j,l) != 0.) {
369 temp = *alpha * B(j,l);
370 i__3 = *m;
371 for (i = 1; i <= *m; ++i) {
372 C(i,j) += temp * A(i,l);
373/* L150: */
374 }
375 }
376/* L160: */
377 }
378/* L170: */
379 }
380 } else {
381
382/* Form C := alpha*A'*B' + beta*C */
383
384 i__1 = *n;
385 for (j = 1; j <= *n; ++j) {
386 i__2 = *m;
387 for (i = 1; i <= *m; ++i) {
388 temp = 0.;
389 i__3 = *k;
390 for (l = 1; l <= *k; ++l) {
391 temp += A(l,i) * B(j,l);
392/* L180: */
393 }
394 if (*beta == 0.) {
395 C(i,j) = *alpha * temp;
396 } else {
397 C(i,j) = *alpha * temp + *beta * C(i,j);
398 }
399/* L190: */
400 }
401/* L200: */
402 }
403 }
404 }
405
406 return 0;
407
408/* End of DGEMM . */
409
410} /* dgemm_ */
411
src/vm/math/lsame.c+113−0
@@ -0,0 +1,113 @@
1/* -- translated by f2c (version 19940927).
2 You must link the resulting object file with the libraries:
3 -lf2c -lm (in that order)
4*/
5
6//#include "f2c.h"
7
8typedef int integer;
9typedef int logical;
10
11logical lsame_(char *ca, char *cb)
12{
13
14
15 /* System generated locals */
16 logical ret_val;
17
18 /* Local variables */
19 integer inta, intb, zcode;
20
21
22/* -- LAPACK auxiliary routine (version 2.0) --
23 Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,
24 Courant Institute, Argonne National Lab, and Rice University
25 January 31, 1994
26
27
28 Purpose
29 =======
30
31 LSAME returns .TRUE. if CA is the same letter as CB regardless of
32 case.
33
34 Arguments
35 =========
36
37 CA (input) CHARACTER*1
38 CB (input) CHARACTER*1
39 CA and CB specify the single characters to be compared.
40
41 =====================================================================
42
43
44
45 Test if the characters are equal */
46
47 ret_val = *(unsigned char *)ca == *(unsigned char *)cb;
48 if (ret_val) {
49 return ret_val;
50 }
51
52/* Now test for equivalence if both characters are alphabetic. */
53
54 zcode = 'Z';
55
56/* Use 'Z' rather than 'A' so that ASCII can be detected on Prime
57 machines, on which ICHAR returns a value with bit 8 set.
58 ICHAR('A') on Prime machines returns 193 which is the same as
59 ICHAR('A') on an EBCDIC machine. */
60
61 inta = *(unsigned char *)ca;
62 intb = *(unsigned char *)cb;
63
64 if (zcode == 90 || zcode == 122) {
65
66/* ASCII is assumed - ZCODE is the ASCII code of either lower o
67r
68 upper case 'Z'. */
69
70 if (inta >= 97 && inta <= 122) {
71 inta += -32;
72 }
73 if (intb >= 97 && intb <= 122) {
74 intb += -32;
75 }
76
77 } else if (zcode == 233 || zcode == 169) {
78
79/* EBCDIC is assumed - ZCODE is the EBCDIC code of either lower
80 or
81 upper case 'Z'. */
82
83 if (inta >= 129 && inta <= 137 || inta >= 145 && inta <= 153 || inta
84 >= 162 && inta <= 169) {
85 inta += 64;
86 }
87 if (intb >= 129 && intb <= 137 || intb >= 145 && intb <= 153 || intb
88 >= 162 && intb <= 169) {
89 intb += 64;
90 }
91
92 } else if (zcode == 218 || zcode == 250) {
93
94/* ASCII is assumed, on Prime machines - ZCODE is the ASCII cod
95e
96 plus 128 of either lower or upper case 'Z'. */
97
98 if (inta >= 225 && inta <= 250) {
99 inta += -32;
100 }
101 if (intb >= 225 && intb <= 250) {
102 intb += -32;
103 }
104 }
105 ret_val = inta == intb;
106
107/* RETURN
108
109 End of LSAME */
110
111 return ret_val;
112} /* lsame_ */
113
src/vm/sys/Sysmod.cpp+206−175
@@ -17,15 +17,18 @@ · 16 unmodified lines
17#include <vm_memory.h>17#include <vm_memory.h>
18#include "Sysmod.h"18#include "Sysmod.h"
19#include "sys_utils.h"19#include "sys_utils.h"
20#include "fd_types.h"
20 21
21using disvm::vm_t;22using disvm::vm_t;
22 23
23using disvm::debug::component_trace_t;24using disvm::debug::component_trace_t;
24using disvm::debug::log_level_t;25using disvm::debug::log_level_t;
25 26
27using disvm::runtime::byte_t;
26using disvm::runtime::dereference_nil;28using disvm::runtime::dereference_nil;
27using disvm::runtime::intrinsic_type_desc;29using disvm::runtime::intrinsic_type_desc;
28using disvm::runtime::out_of_range_memory;30using disvm::runtime::out_of_range_memory;
31using disvm::runtime::pointer_t;
29using disvm::runtime::type_descriptor_t;32using disvm::runtime::type_descriptor_t;
30using disvm::runtime::vm_alloc_t;33using disvm::runtime::vm_alloc_t;
31using disvm::runtime::vm_array_t;34using disvm::runtime::vm_array_t;
@@ -34,8 +37,13 @@ using disvm::runtime::vm_string_t; · 2 unmodified lines
34using disvm::runtime::vm_syscall_exception;37using disvm::runtime::vm_syscall_exception;
35using disvm::runtime::vm_system_exception;38using disvm::runtime::vm_system_exception;
36using disvm::runtime::vm_user_exception;39using disvm::runtime::vm_user_exception;
40using disvm::runtime::marshallable_user_exception;
37using disvm::runtime::word_t;41using disvm::runtime::word_t;
38 42
43using disvm::runtime::sys::open_mode_t;
44using disvm::runtime::sys::seek_start_t;
45using disvm::runtime::sys::vm_fd_t;
46
39namespace47namespace
40{48{
41 disvm::runtime::builtin::vm_runtab_t Sysmodtab[] = {49 disvm::runtime::builtin::vm_runtab_t Sysmodtab[] = {
@@ -93,12 +101,14 @@ namespace · 51 unmodified lines
93 std::shared_ptr<const type_descriptor_t> T_Connection;101 std::shared_ptr<const type_descriptor_t> T_Connection;
94 std::shared_ptr<const type_descriptor_t> T_FileIO;102 std::shared_ptr<const type_descriptor_t> T_FileIO;
95 103
96 class vm_fd_t final : public Sys_FD104 class Sys_FD_Impl final : public Sys_FD
97 {105 {
98 public: // static106 public: // static
99 static void finalizer(vm_alloc_t *fileHandle)107 static void finalizer(vm_alloc_t *fileHandle)
100 {108 {
101 auto fd = fileHandle->get_allocation<vm_fd_t>();109 auto fd = fileHandle->get_allocation<Sys_FD_Impl>();
110
111 fd->~Sys_FD_Impl();
102 112
103 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())113 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())
104 {114 {
@@ -108,128 +118,64 @@ namespace · 3 unmodified lines
108 "sys: fd: finalize: %d",118 "sys: fd: finalize: %d",
109 fd->fd);119 fd->fd);
110 }120 }
111
112 disvm::runtime::sys::drop_fd_record(fd->fd);
113 fd->~vm_fd_t();
114 }
115
116 static std::tuple<word_t, vm_alloc_t *> create(std::unique_ptr<std::iostream> s, word_t fd_mode, vm_string_t *fd_path)
117 {
118 assert(s != nullptr);
119 auto alloc = vm_alloc_t::allocate(T_FD);
120 const auto fd = disvm::runtime::sys::create_fd_record(alloc);
121 auto vm_fd = ::new(alloc->get_allocation())vm_fd_t{ fd, std::move(s), fd_mode, fd_path };
122
123 return std::make_tuple(vm_fd->fd, alloc);
124 }
125
126 private:
127 vm_fd_t(const word_t fd, std::unique_ptr<std::iostream> s, const word_t fd_mode, vm_string_t *fd_path)
128 : Sys_FD{ fd }
129 , _fd_mode{ fd_mode }
130 , _fd_path{ fd_path }
131 , _istream{ s.get() }
132 , _ostream{ s.get() }
133 {
134 _stream = std::move(s);
135
136 if (_fd_path != nullptr)
137 _fd_path->add_ref();
138 }121 }
139 122
140 public:123 // The ref count of the supplied vm_fd_t instance is updated.
141 vm_fd_t(const word_t fd, std::istream &is)124 static vm_alloc_t * create_new(vm_fd_t *vm_fd)
142 : Sys_FD{ fd }
143 , _fd_mode{}
144 , _fd_path{ nullptr }
145 , _istream{ &is }
146 , _ostream{ nullptr }
147 {
148 }
149
150 vm_fd_t(const word_t fd, std::ostream &os)
151 : Sys_FD{ fd }
152 , _fd_mode{}
153 , _fd_path{ nullptr }
154 , _istream{ nullptr }
155 , _ostream{ &os }
156 {
157 }
158
159 ~vm_fd_t()
160 {125 {
161 disvm::debug::assign_debug_pointer(&_istream);126 assert(vm_fd != nullptr);
162 disvm::debug::assign_debug_pointer(&_ostream);127 assert(vm_fd->get_ref_count() == 1 && "Should be a new FD");
163 if (_stream != nullptr)
164 _stream.reset();
165 128
166 // Honor the close flag129 auto alloc = vm_alloc_t::allocate(T_FD);
167 if ((_fd_mode & Sys_ORCLOSE) && _fd_path != nullptr)130 auto fd_impl = ::new(alloc->get_allocation())Sys_FD_Impl{};
168 std::remove(_fd_path->str());
169 131
170 dec_ref_count_and_free(_fd_path);132 fd_impl->fd = disvm::runtime::sys::create_fd_record(vm_fd);
171 disvm::debug::assign_debug_pointer(&_fd_path);133 fd_impl->impl = vm_fd;
172 }134 vm_fd->add_ref();
173 135
174 word_t get_original_mode() const136 return alloc;
175 {
176 return _fd_mode;
177 }137 }
178 138
179 vm_string_t *get_original_path() const139 // The ref count of the supplied vm_fd_t instance is _not_ altered.
140 static vm_alloc_t * create_existing(word_t fd, vm_fd_t *vm_fd)
180 {141 {
181 return _fd_path;142 assert(vm_fd != nullptr);
182 }143 assert(fd >= 0);
183 144
184 word_t read(disvm::vm_t &vm, const word_t buffer_size_in_bytes, void *buffer)145 auto alloc = vm_alloc_t::allocate(T_FD);
185 {146 auto fd_impl = ::new(alloc->get_allocation())Sys_FD_Impl{};
186 if (_istream == nullptr)
187 throw vm_system_exception{ "File descriptor not open for read operation" };
188 147
189 _istream->read(static_cast<char *>(buffer), static_cast<const std::streamsize>(buffer_size_in_bytes));148 fd_impl->fd = fd;
190 if (_istream->bad())149 fd_impl->impl = vm_fd;
191 throw vm_syscall_exception{ vm, "Read operation error" };
192 150
193 return static_cast<word_t>(_istream->gcount());151 return alloc;
194 }152 }
195 153
196 void write(disvm::vm_t &vm, const word_t buffer_size_in_bytes, void *buffer)154 public:
155 ~Sys_FD_Impl()
197 {156 {
198 if (_ostream == nullptr)157 disvm::runtime::sys::drop_fd_record(fd);
199 throw vm_system_exception{ "File descriptor not open for write operation" };158 disvm::runtime::dec_ref_count_and_free(impl);
200 159 disvm::debug::assign_debug_pointer(&impl);
201 _ostream->write(static_cast<char *>(buffer), static_cast<const std::streamsize>(buffer_size_in_bytes));
202 if (_ostream->bad())
203 throw vm_syscall_exception{ vm, "Write operation error" };
204 }160 }
205 161
206 big_t seek(const std::ios::seekdir start, const big_t offset)162 vm_fd_t *impl;
207 {
208 if (_stream == nullptr)
209 throw vm_user_exception{ "Unable to seek on a fifo file descriptor (e.g. stdin, stdout, stderr)" };
210
211 auto new_offset = _stream->rdbuf()->pubseekoff(static_cast<std::streamoff>(offset), start, _fd_mode);
212 return static_cast<big_t>(new_offset);
213 }
214 163
215 private:164 private:
216 const word_t _fd_mode;165 Sys_FD_Impl() = default;
217 vm_string_t *_fd_path;
218 std::istream *_istream;
219 std::ostream *_ostream;
220 std::unique_ptr<std::ios> _stream;
221 };166 };
222 167
223 vm_fd_t *fd_stdin = nullptr;168 // File descriptors for std streams.
224 vm_fd_t *fd_stdout = nullptr;169 word_t fd_stdin = disvm::runtime::sys::vm_invalid_fd;
225 vm_fd_t *fd_stderr = nullptr;170 word_t fd_stdout = disvm::runtime::sys::vm_invalid_fd;
171 word_t fd_stderr = disvm::runtime::sys::vm_invalid_fd;
226 172
227 word_t printf_to_fd(173 word_t printf_to_fd(
228 disvm::vm_t &vm,174 disvm::vm_t &vm,
229 vm_fd_t &fd,175 vm_fd_t &fd,
230 const disvm::runtime::vm_string_t &msg_fmt,176 const vm_string_t &msg_fmt,
231 disvm::runtime::byte_t *msg_args,177 byte_t *msg_args,
232 disvm::runtime::pointer_t base)178 pointer_t base)
233 {179 {
234 auto static_buffer = std::array<char, 1024>{};180 auto static_buffer = std::array<char, 1024>{};
235 auto written = disvm::runtime::sys::printf_to_buffer(vm, msg_fmt, msg_args, base, static_buffer.size(), static_buffer.data());181 auto written = disvm::runtime::sys::printf_to_buffer(vm, msg_fmt, msg_args, base, static_buffer.size(), static_buffer.data());
@@ -247,35 +193,41 @@ namespace · 11 unmodified lines
247 return written;193 return written;
248 }194 }
249 195
250 std::ios::openmode convert_to_openmode(const word_t mode)196 open_mode_t convert_to_openmode(const word_t mode)
251 {197 {
252 auto om = std::ios::openmode{};198 auto om = open_mode_t{};
253 199
254 // Lowest bit is for read/write.200 // Lowest bit is for read/write.
255 if (mode & Sys_OWRITE)201 if (mode & Sys_OWRITE)
256 om |= std::ios::out;202 om |= open_mode_t::write;
257 else203 else
258 om |= std::ios::in; // Sys_OREAD204 om |= open_mode_t::read; // Sys_OREAD
259 205
260 if (mode & Sys_ORDWR)206 if (mode & Sys_ORDWR)
261 om |= (std::ios::in | std::ios::out);207 om |= (open_mode_t::write | open_mode_t::read);
262 208
263 if (mode & Sys_OTRUNC)209 if (mode & Sys_OTRUNC)
264 om |= std::ios::trunc;210 om |= open_mode_t::truncate;
211
212 if (mode & Sys_OEXCL)
213 om |= open_mode_t::atomic;
214
215 if (mode & Sys_ORCLOSE)
216 om |= open_mode_t::delete_on_close;
265 217
266 return om;218 return om;
267 }219 }
268 220
269 std::ios::seekdir convert_to_seekdir(const word_t start)221 seek_start_t convert_to_seekdir(const word_t start)
270 {222 {
271 switch (start)223 switch (start)
272 {224 {
273 case Sys_SEEKSTART:225 case Sys_SEEKSTART:
274 return std::ios::beg;226 return seek_start_t::start;
275 case Sys_SEEKRELA:227 case Sys_SEEKRELA:
276 return std::ios::cur;228 return seek_start_t::relative;
277 case Sys_SEEKEND:229 case Sys_SEEKEND:
278 return std::ios::end;230 return seek_start_t::end;
279 default:231 default:
280 throw vm_user_exception{ "Invalid seek mode" };232 throw vm_user_exception{ "Invalid seek mode" };
281 }233 }
@@ -288,49 +240,55 @@ Sysmodinit(void) · 6 unmodified lines
288 disvm::runtime::builtin::register_module_exports(Sys_PATH, Sysmodlen, Sysmodtab);240 disvm::runtime::builtin::register_module_exports(Sys_PATH, Sysmodlen, Sysmodtab);
289 T_Qid = type_descriptor_t::create(sizeof(Sys_Qid), sizeof(Sys_Qid_map), Sys_Qid_map);241 T_Qid = type_descriptor_t::create(sizeof(Sys_Qid), sizeof(Sys_Qid_map), Sys_Qid_map);
290 T_Dir = type_descriptor_t::create(sizeof(Sys_Dir), sizeof(Sys_Dir_map), Sys_Dir_map);242 T_Dir = type_descriptor_t::create(sizeof(Sys_Dir), sizeof(Sys_Dir_map), Sys_Dir_map);
291 T_FD = type_descriptor_t::create(sizeof(vm_fd_t), sizeof(Sys_FD_map), Sys_FD_map, vm_fd_t::finalizer);243 T_FD = type_descriptor_t::create(sizeof(Sys_FD_Impl), sizeof(Sys_FD_map), Sys_FD_map, Sys_FD_Impl::finalizer);
292 T_Connection = type_descriptor_t::create(sizeof(Sys_Connection), sizeof(Sys_Connection_map), Sys_Connection_map);244 T_Connection = type_descriptor_t::create(sizeof(Sys_Connection), sizeof(Sys_Connection_map), Sys_Connection_map);
293 T_FileIO = type_descriptor_t::create(sizeof(Sys_FileIO), sizeof(Sys_FileIO_map), Sys_FileIO_map);245 T_FileIO = type_descriptor_t::create(sizeof(Sys_FileIO), sizeof(Sys_FileIO_map), Sys_FileIO_map);
294 246
295 // Initialize default file descriptors247 // Initialize default file descriptors
248 auto std_streams = disvm::runtime::sys::get_std_streams();
296 249
297 {250 // Initialize in this order to assign POSIX defined values for the 'standard' streams.
298 auto vm_stdin = vm_alloc_t::allocate(T_FD);251 // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html
299 const auto fd = disvm::runtime::sys::create_fd_record(vm_stdin);
300 fd_stdin = ::new(vm_stdin->get_allocation())vm_fd_t{ fd, std::cin };
301 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stdin: %d", fd);
302 }
303 252
304 {253 fd_stdin = disvm::runtime::sys::create_fd_record(std_streams.input);
305 auto vm_stdout = vm_alloc_t::allocate(T_FD);254 assert(fd_stdin == 0);
306 const auto fd = disvm::runtime::sys::create_fd_record(vm_stdout);255 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stdin: %d", fd_stdin);
307 fd_stdout = ::new(vm_stdout->get_allocation())vm_fd_t{ fd, std::cout };
308 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stdout: %d", fd);
309 }
310 256
311 {257 fd_stdout = disvm::runtime::sys::create_fd_record(std_streams.output);
312 auto vm_stderr = vm_alloc_t::allocate(T_FD);258 assert(fd_stdout == 1);
313 const auto fd = disvm::runtime::sys::create_fd_record(vm_stderr);259 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stdout: %d", fd_stdout);
314 fd_stderr = ::new(vm_stderr->get_allocation())vm_fd_t{ fd, std::cerr };260
315 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stderr: %d", fd);261 fd_stderr = disvm::runtime::sys::create_fd_record(std_streams.error);
316 }262 assert(fd_stderr == 2);
263 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: stderr: %d", fd_stderr);
317}264}
318 265
319void266void
320Sys_announce(vm_registers_t &r, vm_t &vm)267Sys_announce(vm_registers_t &r, vm_t &vm)
321{268{
322 auto &fp = r.stack.peek_frame()->base<F_Sys_announce>();269 auto &fp = r.stack.peek_frame()->base<F_Sys_announce>();
270
271 // [PAL] Consume platform API
323 throw vm_system_exception{ "Function not implemented" };272 throw vm_system_exception{ "Function not implemented" };
324}273}
325 274
326void275void
327Sys_aprint(vm_registers_t &r, vm_t &vm)276Sys_aprint(vm_registers_t &r, vm_t &vm)
328{277{
278 auto fp_base = r.stack.peek_frame()->base();
329 auto &fp = r.stack.peek_frame()->base<F_Sys_aprint>();279 auto &fp = r.stack.peek_frame()->base<F_Sys_aprint>();
280 auto str = vm_alloc_t::from_allocation<vm_string_t>(fp.s);
281 if (str == nullptr)
282 throw dereference_nil{ "Print string to array" };
330 283
331 //disvm::runtime::dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));284 auto buffer = std::vector<char>(128);
332 //*fp.ret = nullptr;285 auto msg_args = &fp.vargs;
333 throw vm_system_exception{ "Function not implemented" };286 auto written = disvm::runtime::sys::printf_to_dynamic_buffer(vm, *str, msg_args, fp_base, buffer);
287 auto new_array = new vm_array_t{ intrinsic_type_desc::type<byte_t>(), written };
288 std::memcpy(new_array->at(0), buffer.data(), written);
289
290 disvm::runtime::dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));
291 *fp.ret = new_array->get_allocation();
334}292}
335 293
336void294void
@@ -421,6 +379,8 @@ void · 84 unmodified lines
421Sys_chdir(vm_registers_t &r, vm_t &vm)379Sys_chdir(vm_registers_t &r, vm_t &vm)
422{380{
423 auto &fp = r.stack.peek_frame()->base<F_Sys_chdir>();381 auto &fp = r.stack.peek_frame()->base<F_Sys_chdir>();
382
383 // [PAL] Consume platform API
424 throw vm_system_exception{ "Function not implemented" };384 throw vm_system_exception{ "Function not implemented" };
425}385}
426 386
@@ -429,46 +389,42 @@ Sys_create(vm_registers_t &r, vm_t &vm) · 2 unmodified lines
429{389{
430 auto &fp = r.stack.peek_frame()->base<F_Sys_create>();390 auto &fp = r.stack.peek_frame()->base<F_Sys_create>();
431 391
392 dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));
393 *fp.ret = nullptr;
394
432 auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s);395 auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s);
433 const auto open_mode = convert_to_openmode(fp.mode);396 const auto open_mode = convert_to_openmode(fp.mode);
434 397
435 auto cfs_flag = disvm::runtime::sys::cfs_flags_t::none;398 // [TODO] Apply the requested permissions to the file - fp.perm
436 if (fp.mode & Sys_OEXCL)399 auto vm_fd = disvm::runtime::sys::create_from_file_path(path, open_mode);
437 cfs_flag = (disvm::runtime::sys::cfs_flags_t::atomic | disvm::runtime::sys::cfs_flags_t::ensure_create);
438
439 // [TODO] Apply the requested permissions to the file.
440 auto file_stream = disvm::runtime::sys::create_file_stream(path->str(), (open_mode | std::ios::binary), cfs_flag);
441 400
442 // Return null if file stream is not open.401 // Return null if file is not open.
443 if (file_stream == nullptr)402 if (vm_fd == nullptr)
444 {
445 *fp.ret = nullptr;
446 return;403 return;
447 }
448 404
449 vm_alloc_t *fd_alloc;405 auto fd_alloc = Sys_FD_Impl::create_new(vm_fd);
450 auto fd = word_t{};406 *fp.ret = fd_alloc->get_allocation();
451 std::tie(fd, fd_alloc) = vm_fd_t::create(std::move(file_stream), fp.mode, path);
452 407
453 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())408 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())
454 {409 {
410 auto fd_impl = fd_alloc->get_allocation<Sys_FD_Impl>();
455 disvm::debug::log_msg(411 disvm::debug::log_msg(
456 component_trace_t::builtin,412 component_trace_t::builtin,
457 log_level_t::debug,413 log_level_t::debug,
458 "sys: create: %d >>%s<< %#x %#x",414 "sys: create: %d >>%s<< %#x %#x",
459 fd,415 fd_impl->fd,
460 path->str(),416 path->str(),
461 fp.mode,417 fp.mode,
462 fp.perm);418 fp.perm);
463 }419 }
464
465 *fp.ret = fd_alloc->get_allocation();
466}420}
467 421
468void422void
469Sys_dial(vm_registers_t &r, vm_t &vm)423Sys_dial(vm_registers_t &r, vm_t &vm)
470{424{
471 auto &fp = r.stack.peek_frame()->base<F_Sys_dial>();425 auto &fp = r.stack.peek_frame()->base<F_Sys_dial>();
426
427 // [PAL] Consume platform API
472 throw vm_system_exception{ "Function not implemented" };428 throw vm_system_exception{ "Function not implemented" };
473}429}
474 430
@@ -476,14 +432,42 @@ void · 1 unmodified line
476Sys_dirread(vm_registers_t &r, vm_t &vm)432Sys_dirread(vm_registers_t &r, vm_t &vm)
477{433{
478 auto &fp = r.stack.peek_frame()->base<F_Sys_dirread>();434 auto &fp = r.stack.peek_frame()->base<F_Sys_dirread>();
435
436 // [PAL] Consume platform API
479 throw vm_system_exception{ "Function not implemented" };437 throw vm_system_exception{ "Function not implemented" };
480}438}
481 439
440namespace
441{
442 // [SPEC] In the Inferno OS, this error is represented by
443 // Ebadfd - 'fd out of range or not open' (emu/port/error.c).
444 auto invalid_fd_error = "Invalid FD value";
445}
446
482void447void
483Sys_dup(vm_registers_t &r, vm_t &vm)448Sys_dup(vm_registers_t &r, vm_t &vm)
484{449{
485 auto &fp = r.stack.peek_frame()->base<F_Sys_dup>();450 auto &fp = r.stack.peek_frame()->base<F_Sys_dup>();
486 throw vm_system_exception{ "Function not implemented" };451
452 const auto old_fd = fp.old;
453 auto fd_maybe = disvm::runtime::sys::fetch_fd_record(old_fd);
454 if (fd_maybe == nullptr)
455 throw marshallable_user_exception{ invalid_fd_error };
456
457 auto new_fd_maybe = fp.new_;
458 if (new_fd_maybe == disvm::runtime::sys::vm_invalid_fd)
459 {
460 new_fd_maybe = disvm::runtime::sys::create_fd_record(fd_maybe);
461 }
462 else if (!disvm::runtime::sys::try_update_fd_record(new_fd_maybe, fd_maybe))
463 {
464 throw marshallable_user_exception{ invalid_fd_error };
465 }
466
467 *fp.ret = new_fd_maybe;
468
469 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())
470 disvm::debug::log_msg(component_trace_t::builtin, log_level_t::debug, "sys: fd: dup %d %d", old_fd, new_fd_maybe);
487}471}
488 472
489void473void
@@ -521,11 +505,11 @@ Sys_fildes(vm_registers_t &r, vm_t &vm) · 31 unmodified lines
521 dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));505 dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));
522 *fp.ret = nullptr;506 *fp.ret = nullptr;
523 507
524 auto fd = disvm::runtime::sys::fetch_fd_record(fp.fd);508 auto vm_fd = disvm::runtime::sys::fetch_fd_record(fp.fd);
525 if (fd != nullptr)509 if (vm_fd != nullptr)
526 {510 {
527 fd->add_ref();511 auto fd_alloc = Sys_FD_Impl::create_existing(fp.fd, vm_fd);
528 *fp.ret = fd->get_allocation();512 *fp.ret = fd_alloc->get_allocation();
529 }513 }
530}514}
531 515
@@ -546,18 +530,20 @@ Sys_fprint(vm_registers_t &r, vm_t &vm) · 14 unmodified lines
546 auto &fp = r.stack.peek_frame()->base<F_Sys_fprint>();530 auto &fp = r.stack.peek_frame()->base<F_Sys_fprint>();
547 auto fd_alloc = vm_alloc_t::from_allocation(fp.fd);531 auto fd_alloc = vm_alloc_t::from_allocation(fp.fd);
548 assert(fd_alloc->alloc_type == T_FD);532 assert(fd_alloc->alloc_type == T_FD);
549 auto fd = fd_alloc->get_allocation<vm_fd_t>();533 auto fd = fd_alloc->get_allocation<Sys_FD_Impl>();
550 auto str = vm_alloc_t::from_allocation<vm_string_t>(fp.s);534 auto str = vm_alloc_t::from_allocation<vm_string_t>(fp.s);
551 if (str == nullptr)535 if (str == nullptr)
552 throw dereference_nil{ "Print string to FD" };536 throw dereference_nil{ "Print string to FD" };
553 537
554 *fp.ret = printf_to_fd(vm, *fd, *str, &fp.vargs, fp_base);538 *fp.ret = printf_to_fd(vm, *fd->impl, *str, &fp.vargs, fp_base);
555}539}
556 540
557void541void
558Sys_fstat(vm_registers_t &r, vm_t &vm)542Sys_fstat(vm_registers_t &r, vm_t &vm)
559{543{
560 auto &fp = r.stack.peek_frame()->base<F_Sys_fstat>();544 auto &fp = r.stack.peek_frame()->base<F_Sys_fstat>();
545
546 // [PAL] Consume platform API
561 throw vm_system_exception{ "Function not implemented" };547 throw vm_system_exception{ "Function not implemented" };
562}548}
563 549
@@ -572,6 +558,8 @@ void · 8 unmodified lines
572Sys_fwstat(vm_registers_t &r, vm_t &vm)558Sys_fwstat(vm_registers_t &r, vm_t &vm)
573{559{
574 auto &fp = r.stack.peek_frame()->base<F_Sys_fwstat>();560 auto &fp = r.stack.peek_frame()->base<F_Sys_fwstat>();
561
562 // [PAL] Consume platform API
575 throw vm_system_exception{ "Function not implemented" };563 throw vm_system_exception{ "Function not implemented" };
576}564}
577 565
@@ -586,6 +574,8 @@ void · 8 unmodified lines
586Sys_listen(vm_registers_t &r, vm_t &vm)574Sys_listen(vm_registers_t &r, vm_t &vm)
587{575{
588 auto &fp = r.stack.peek_frame()->base<F_Sys_listen>();576 auto &fp = r.stack.peek_frame()->base<F_Sys_listen>();
577
578 // [PAL] Consume platform API
589 throw vm_system_exception{ "Function not implemented" };579 throw vm_system_exception{ "Function not implemented" };
590}580}
591 581
@@ -611,41 +601,41 @@ Sys_open(vm_registers_t &r, vm_t &vm) · 19 unmodified lines
611{601{
612 auto &fp = r.stack.peek_frame()->base<F_Sys_open>();602 auto &fp = r.stack.peek_frame()->base<F_Sys_open>();
613 603
604 dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));
605 *fp.ret = nullptr;
606
614 auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s);607 auto path = vm_alloc_t::from_allocation<vm_string_t>(fp.s);
615 const auto open_mode = convert_to_openmode(fp.mode);608 const auto open_mode = convert_to_openmode(fp.mode);
616 609
617 // [TODO] Handle opening devices - not just files (i.e. /dev/random, /dev/source, /proc/1234)610 // [TODO] Handle opening devices - not just files (i.e. /dev/random, /dev/source, /proc/1234)
618 auto file_stream = disvm::runtime::sys::create_file_stream(path->str(), (open_mode | std::ios::binary));611 auto vm_fd = disvm::runtime::sys::create_from_file_path(path, open_mode | open_mode_t::ensure_exists);
619 612
620 // Return null if file stream is not open.613 // Return null if file is not open.
621 if (file_stream == nullptr)614 if (vm_fd == nullptr)
622 {
623 *fp.ret = nullptr;
624 return;615 return;
625 }
626 616
627 vm_alloc_t *fd_alloc;617 auto fd_alloc = Sys_FD_Impl::create_new(vm_fd);
628 auto fd = word_t{};618 *fp.ret = fd_alloc->get_allocation();
629 std::tie(fd, fd_alloc) = vm_fd_t::create(std::move(file_stream), fp.mode, path);
630 619
631 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())620 if (disvm::debug::is_component_tracing_enabled<component_trace_t::builtin>())
632 {621 {
622 auto fd_impl = fd_alloc->get_allocation<Sys_FD_Impl>();
633 disvm::debug::log_msg(623 disvm::debug::log_msg(
634 component_trace_t::builtin,624 component_trace_t::builtin,
635 log_level_t::debug,625 log_level_t::debug,
636 "sys: open: %d >>%s<< %#x",626 "sys: open: %d >>%s<< %#x",
637 fd,627 fd_impl->fd,
638 path->str(),628 path->str(),
639 fp.mode);629 fp.mode);
640 }630 }
641
642 *fp.ret = fd_alloc->get_allocation();
643}631}
644 632
645void633void
646Sys_pctl(vm_registers_t &r, vm_t &vm)634Sys_pctl(vm_registers_t &r, vm_t &vm)
647{635{
648 auto &fp = r.stack.peek_frame()->base<F_Sys_pctl>();636 auto &fp = r.stack.peek_frame()->base<F_Sys_pctl>();
637
638 // [PAL] Consume platform API
649 throw vm_system_exception{ "Function not implemented" };639 throw vm_system_exception{ "Function not implemented" };
650}640}
651 641
@@ -653,6 +643,8 @@ void · 1 unmodified line
653Sys_pipe(vm_registers_t &r, vm_t &vm)643Sys_pipe(vm_registers_t &r, vm_t &vm)
654{644{
655 auto &fp = r.stack.peek_frame()->base<F_Sys_pipe>();645 auto &fp = r.stack.peek_frame()->base<F_Sys_pipe>();
646
647 // [PAL] Consume platform API
656 throw vm_system_exception{ "Function not implemented" };648 throw vm_system_exception{ "Function not implemented" };
657}649}
658 650
@@ -672,7 +664,12 @@ Sys_print(vm_registers_t &r, vm_t &vm) · 13 unmodified lines
672 if (str == nullptr)664 if (str == nullptr)
673 throw dereference_nil{ "Print string" };665 throw dereference_nil{ "Print string" };
674 666
675 *fp.ret = printf_to_fd(vm, *fd_stdout, *str, &fp.vargs, fp_base);667 auto std_output = disvm::runtime::sys::fetch_fd_record(fd_stdout);
668 if (std_output == nullptr)
669 throw vm_system_exception{ "stdout not available" };
670
671 *fp.ret = printf_to_fd(vm, *std_output, *str, &fp.vargs, fp_base);
672 disvm::runtime::dec_ref_count_and_free(std_output);
676}673}
677 674
678void675void
@@ -708,8 +705,8 @@ Sys_read(vm_registers_t &r, vm_t &vm) · 29 unmodified lines
708 705
709 assert(fd_alloc->alloc_type == T_FD);706 assert(fd_alloc->alloc_type == T_FD);
710 707
711 auto fd = fd_alloc->get_allocation<vm_fd_t>();708 auto fd = fd_alloc->get_allocation<Sys_FD_Impl>();
712 *fp.ret = fd->read(vm, n, buffer->at(0));709 *fp.ret = fd->impl->read(vm, n, buffer->at(0));
713}710}
714 711
715void712void
@@ -742,10 +739,10 @@ Sys_seek(vm_registers_t &r, vm_t &vm) · 26 unmodified lines
742 throw dereference_nil{ "Seek in file descriptor" };739 throw dereference_nil{ "Seek in file descriptor" };
743 740
744 assert(fd_alloc->alloc_type == T_FD);741 assert(fd_alloc->alloc_type == T_FD);
745 auto fd = fd_alloc->get_allocation<vm_fd_t>();742 auto fd = fd_alloc->get_allocation<Sys_FD_Impl>();
746 743
747 const auto start = convert_to_seekdir(fp.start);744 const auto start = convert_to_seekdir(fp.start);
748 *fp.ret = fd->seek(start, fp.off);745 *fp.ret = fd->impl->seek(vm, start, fp.off);
749}746}
750 747
751void748void
@@ -785,6 +782,7 @@ Sys_sprint(vm_registers_t &r, vm_t &vm) · 33 unmodified lines
785 new_string = new vm_string_t{ static_cast<std::size_t>(written), reinterpret_cast<uint8_t *>(dynamic_buffer.data()) };782 new_string = new vm_string_t{ static_cast<std::size_t>(written), reinterpret_cast<uint8_t *>(dynamic_buffer.data()) };
786 }783 }
787 784
785 disvm::runtime::dec_ref_count_and_free(vm_alloc_t::from_allocation(*fp.ret));
788 *fp.ret = new_string->get_allocation();786 *fp.ret = new_string->get_allocation();
789}787}
790 788
@@ -792,6 +790,8 @@ void · 1 unmodified line
792Sys_stat(vm_registers_t &r, vm_t &vm)790Sys_stat(vm_registers_t &r, vm_t &vm)
793{791{
794 auto &fp = r.stack.peek_frame()->base<F_Sys_stat>();792 auto &fp = r.stack.peek_frame()->base<F_Sys_stat>();
793
794 // [PAL] Consume platform API
795 throw vm_system_exception{ "Function not implemented" };795 throw vm_system_exception{ "Function not implemented" };
796}796}
797 797
@@ -799,7 +799,36 @@ void · 1 unmodified line
799Sys_stream(vm_registers_t &r, vm_t &vm)799Sys_stream(vm_registers_t &r, vm_t &vm)
800{800{
801 auto &fp = r.stack.peek_frame()->base<F_Sys_stream>();801 auto &fp = r.stack.peek_frame()->base<F_Sys_stream>();
802 throw vm_system_exception{ "Function not implemented" };802
803 auto alloc_s = vm_alloc_t::from_allocation(fp.src);
804 if (alloc_s == nullptr)
805 throw dereference_nil{ "Source in stream" };
806
807 auto alloc_d = vm_alloc_t::from_allocation(fp.dst);
808 if (alloc_d == nullptr)
809 throw dereference_nil{ "Destination in stream" };
810
811 assert(alloc_s->alloc_type->is_equal(T_FD.get()) && alloc_d->alloc_type->is_equal(T_FD.get()));
812 auto src = alloc_s->get_allocation<Sys_FD_Impl>()->impl;
813 auto dst = alloc_d->get_allocation<Sys_FD_Impl>()->impl;
814
815 const auto buffer_size = fp.bufsiz;
816 if (buffer_size <= 0)
817 throw out_of_range_memory{};
818
819 std::unique_ptr<void, decltype(&disvm::runtime::free_memory)> buffer{ disvm::runtime::alloc_memory(buffer_size), disvm::runtime::free_memory };
820 auto written = word_t{};
821 for (;;)
822 {
823 auto bytes_read = src->read(vm, buffer_size, buffer.get());
824 if (bytes_read == 0)
825 break;
826
827 dst->write(vm, bytes_read, buffer.get());
828 written += bytes_read;
829 }
830
831 *fp.ret = written;
803}832}
804 833
805namespace834namespace
@@ -993,8 +1022,8 @@ Sys_write(vm_registers_t &r, vm_t &vm) · 187 unmodified lines
993 1022
994 assert(fd_alloc->alloc_type == T_FD);1023 assert(fd_alloc->alloc_type == T_FD);
995 1024
996 auto fd = fd_alloc->get_allocation<vm_fd_t>();1025 auto fd = fd_alloc->get_allocation<Sys_FD_Impl>();
997 fd->write(vm, n, buffer->at(0));1026 fd->impl->write(vm, n, buffer->at(0));
998 1027
999 *fp.ret = n;1028 *fp.ret = n;
1000}1029}
@@ -1003,5 +1032,7 @@ void · 2 unmodified lines
1003Sys_wstat(vm_registers_t &r, vm_t &vm)1032Sys_wstat(vm_registers_t &r, vm_t &vm)
1004{1033{
1005 auto &fp = r.stack.peek_frame()->base<F_Sys_wstat>();1034 auto &fp = r.stack.peek_frame()->base<F_Sys_wstat>();
1035
1036 // [PAL] Consume platform API
1006 throw vm_system_exception{ "Function not implemented" };1037 throw vm_system_exception{ "Function not implemented" };
1007}1038}
src/vm/sys/fd_manager.cpp+66−47
@@ -6,7 +6,8 @@ · 5 unmodified lines
6 6
7#include <array>7#include <array>
8#include <mutex>8#include <mutex>
9#include <unordered_map>9#include <vector>
10#include <queue>
10#include <exceptions.h>11#include <exceptions.h>
11#include <vm_memory.h>12#include <vm_memory.h>
12#include "sys_utils.h"13#include "sys_utils.h"
@@ -14,72 +15,90 @@ · 1 unmodified line
14using disvm::runtime::vm_alloc_t;15using disvm::runtime::vm_alloc_t;
15using disvm::runtime::word_t;16using disvm::runtime::word_t;
16 17
18using disvm::runtime::sys::vm_fd_t;
19
17namespace20namespace
18{21{
19 using fd_map_t = std::unordered_map<word_t, vm_alloc_t *>;22 std::mutex fd_map_lock;
23 auto fd_map = std::vector<vm_fd_t *>{};
24 auto fd_available = std::priority_queue<word_t, std::vector<word_t>, std::greater<word_t>>{};
25}
26
27word_t disvm::runtime::sys::create_fd_record(vm_fd_t * vm_fd)
28{
29 assert(vm_fd != nullptr);
20 30
21 auto std_fd = std::array<vm_alloc_t * , 3>31 std::lock_guard<std::mutex> lock{ fd_map_lock };
32
33 word_t new_fd;
34 if (fd_available.empty())
35 {
36 new_fd = fd_map.size();
37 fd_map.push_back(vm_fd);
38 }
39 else
22 {40 {
23 nullptr, // stdin41 new_fd = fd_available.top();
24 nullptr, // stdout42 fd_available.pop();
25 nullptr, // stderr
26 };
27 43
28 auto next_fd = word_t{ 0 };44 assert(fd_map[new_fd] == nullptr && "Reused FD should be null");
45 fd_map[new_fd] = vm_fd;
46 }
29 47
30 std::mutex fd_map_lock;48 return new_fd;
31 auto fd_map = fd_map_t{};
32}49}
33 50
34word_t disvm::runtime::sys::create_fd_record(vm_alloc_t * fd_alloc)51bool disvm::runtime::sys::try_update_fd_record(word_t fd, vm_fd_t *vm_fd)
35{52{
36 assert(fd_alloc != nullptr);53 assert(fd != sys::vm_invalid_fd);
54 assert(vm_fd != nullptr);
37 55
38 {56 std::lock_guard<std::mutex> lock{ fd_map_lock };
39 std::lock_guard<std::mutex> lock{ fd_map_lock };57 if (fd < 0 || static_cast<word_t>(fd_map.size()) <= fd)
40 58 return false;
41 auto new_fd = next_fd;59
42 next_fd++;60 auto vm_fd_curr = fd_map[fd];
43 if (new_fd < static_cast<word_t>(std_fd.size()))61 auto current_ref = vm_fd_curr->release();
44 {62 if (current_ref == 0)
45 std_fd[new_fd] = fd_alloc;63 delete vm_fd_curr;
46 }64
47 else65 fd_map[fd] = vm_fd;
48 {66 return true;
49 assert(fd_map.cend() == fd_map.find(new_fd));
50 fd_map[new_fd] = fd_alloc;
51 }
52
53 return new_fd;
54 }
55}67}
56 68
57vm_alloc_t * disvm::runtime::sys::fetch_fd_record(word_t fd)69vm_fd_t * disvm::runtime::sys::fetch_fd_record(word_t fd)
58{70{
59 assert(fd != sys::vm_invalid_fd && "Invalid FD value");71 assert(fd != sys::vm_invalid_fd);
60 72
61 if (0 <= fd && fd < static_cast<word_t>(std_fd.size()))73 std::lock_guard<std::mutex> lock{ fd_map_lock };
62 return std_fd[fd];74 if (fd < 0 || static_cast<word_t>(fd_map.size()) <= fd)
75 return nullptr;
63 76
64 {77 auto vm_fd = fd_map[fd];
65 std::lock_guard<std::mutex> lock{ fd_map_lock };78 if (vm_fd != nullptr)
66 auto iter = fd_map.find(fd);79 vm_fd->add_ref();
67 if (iter == fd_map.cend())
68 return nullptr;
69 80
70 return iter->second;81 return vm_fd;
71 }
72}82}
73 83
74void disvm::runtime::sys::drop_fd_record(word_t fd)84void disvm::runtime::sys::drop_fd_record(word_t fd)
75{85{
76 assert(fd != sys::vm_invalid_fd && "Invalid FD value");86 assert(fd != sys::vm_invalid_fd);
77 assert(fd >= static_cast<word_t>(std_fd.size()) && "Request to drop std file?");87
88 std::lock_guard<std::mutex> lock{ fd_map_lock };
89 if (fd < 0 || static_cast<word_t>(fd_map.size()) <= fd)
90 return;
78 91
92 assert(fd_map[fd] != nullptr);
93
94 // Manual management of file descriptors, since there is an inherent life time
95 // race amoung the enclosing ADT instances that can have a reference.
96 auto vm_fd = fd_map[fd];
97 auto current_ref = vm_fd->release();
98 if (current_ref == 0)
79 {99 {
80 std::lock_guard<std::mutex> lock{ fd_map_lock };100 delete vm_fd;
81 auto iter = fd_map.find(fd);101 fd_map[fd] = nullptr;
82 if (iter != fd_map.cend())102 fd_available.push(fd);
83 fd_map.erase(iter);
84 }103 }
85}104}
src/vm/sys/fd_types.cpp+217−0
@@ -0,0 +1,217 @@
1//
2// Dis VM
3// File: fd_types.cpp
4// Author: arr
5//
6
7#include <cstdio>
8#include <algorithm>
9#include <streambuf>
10
11#include <debug.h>
12#include <exceptions.h>
13#include <vm_memory.h>
14#include "fd_types.h"
15
16using disvm::vm_t;
17
18using disvm::debug::component_trace_t;
19using disvm::debug::log_level_t;
20
21using disvm::runtime::big_t;
22using disvm::runtime::byte_t;
23using disvm::runtime::type_descriptor_t;
24using disvm::runtime::vm_string_t;
25using disvm::runtime::word_t;
26using disvm::runtime::vm_system_exception;
27using disvm::runtime::vm_syscall_exception;
28using disvm::runtime::vm_user_exception;
29
30using disvm::runtime::sys::open_mode_t;
31using disvm::runtime::sys::seek_start_t;
32using disvm::runtime::sys::std_streams;
33using disvm::runtime::sys::vm_fd_t;
34
35vm_fd_t::vm_fd_t(std::shared_ptr<const type_descriptor_t> td)
36 : vm_alloc_t(std::move(td))
37{ }
38
39namespace
40{
41 namespace hidden_type_desc
42 {
43 const type_descriptor_t vm_fd_t{ 0, 0, nullptr, type_descriptor_t::no_finalizer, "vm_fd_t" };
44
45 struct
46 {
47 void operator()(const type_descriptor_t *)
48 {
49 // Not allocated on heap
50 }
51 } deleter;
52 }
53}
54
55std::shared_ptr<const type_descriptor_t> vm_fd_t::type_desc()
56{
57 static std::shared_ptr<const type_descriptor_t> t = { &hidden_type_desc::vm_fd_t, hidden_type_desc::deleter };
58 return t;
59}
60
61namespace
62{
63 int seek_to_int(const seek_start_t m)
64 {
65 switch (m)
66 {
67 default:
68 assert(false && "Unknown seek start type");
69 case seek_start_t::start:
70 return SEEK_SET;
71 case seek_start_t::relative:
72 return SEEK_CUR;
73 case seek_start_t::end:
74 return SEEK_END;
75 }
76 }
77
78 class sys_fd_t final : public vm_fd_t
79 {
80 public:
81 sys_fd_t(std::FILE *sys_fd, vm_string_t *fd_path, const open_mode_t fd_mode)
82 : vm_fd_t(type_desc())
83 , _fd_mode{ fd_mode }
84 , _fd_path{ fd_path }
85 , _sys_fd{ sys_fd }
86 {
87 assert(sys_fd != nullptr);
88
89 if (_fd_path != nullptr)
90 _fd_path->add_ref();
91 }
92
93 ~sys_fd_t()
94 {
95 std::fclose(_sys_fd);
96 disvm::debug::assign_debug_pointer(&_sys_fd);
97
98 // Honor the close flag
99 if (disvm::util::has_flag(_fd_mode, open_mode_t::delete_on_close) && _fd_path != nullptr)
100 std::remove(_fd_path->str());
101
102 disvm::runtime::dec_ref_count_and_free(_fd_path);
103 disvm::debug::assign_debug_pointer(&_fd_path);
104 }
105
106 word_t read(vm_t &vm, const word_t buffer_size_in_bytes, void *buffer) override
107 {
108 if (!disvm::util::has_flag(_fd_mode, open_mode_t::read))
109 throw vm_system_exception{ "File descriptor not open for read operation" };
110
111 auto read = std::fread(buffer, sizeof(byte_t), buffer_size_in_bytes, _sys_fd);
112 if (std::ferror(_sys_fd) != 0)
113 throw vm_syscall_exception{ vm, "Read operation error" };
114
115 return static_cast<word_t>(read);
116 }
117
118 void write(vm_t &vm, const word_t buffer_size_in_bytes, void *buffer) override
119 {
120 if (!disvm::util::has_flag(_fd_mode, open_mode_t::write))
121 throw vm_system_exception{ "File descriptor not open for write operation" };
122
123 std::fwrite(buffer, sizeof(byte_t), buffer_size_in_bytes, _sys_fd);
124 if (std::ferror(_sys_fd) != 0)
125 throw vm_syscall_exception{ vm, "Write operation error" };
126 }
127
128 big_t seek(vm_t &vm, const seek_start_t seek_start, const big_t offset) override
129 {
130 if (disvm::util::has_flag(_fd_mode, open_mode_t::disable_seek))
131 throw vm_user_exception{ "Unable to seek on a fifo file descriptor (e.g. stdin, stdout, stderr)" };
132
133 auto result = std::fseek(_sys_fd, static_cast<long>(offset), seek_to_int(seek_start));
134 if (result != 0)
135 throw vm_syscall_exception{ vm, "Seek operation error" };
136
137 return static_cast<big_t>(std::ftell(_sys_fd));
138 }
139
140 private:
141 const open_mode_t _fd_mode;
142 vm_string_t *_fd_path;
143 std::FILE *_sys_fd;
144 };
145}
146
147namespace
148{
149 std::mutex _create_file_path_mutex;
150
151 const std::array<char *, 8> fopen_mode_strings =
152 {
153 // R W T
154 nullptr, // 0 0 0
155 "rb", // 1 0 0
156 "wb", // 0 1 0
157 "rwb", // 1 1 0
158 nullptr, // 0 0 1
159 "rb+", // 1 0 1
160 "wb+", // 0 1 1
161 "wb+", // 1 1 1
162 };
163
164 const auto fopen_modes = (open_mode_t::read | open_mode_t::write | open_mode_t::truncate);
165
166 constexpr const char *mode_for_fopen(const open_mode_t o)
167 {
168 return fopen_mode_strings[static_cast<std::size_t>(fopen_modes & o)];
169 }
170}
171
172vm_fd_t *disvm::runtime::sys::create_from_file_path(vm_string_t *path, open_mode_t mode)
173{
174 std::unique_lock<std::mutex> lock{ _create_file_path_mutex, std::defer_lock };
175
176 if ((mode & ~fopen_modes) != open_mode_t::none)
177 {
178 if (util::has_flag(mode, open_mode_t::atomic))
179 lock.lock();
180
181 if (util::has_flag(mode, (open_mode_t::ensure_create | open_mode_t::ensure_exists)))
182 {
183 assert(util::has_flag(mode, open_mode_t::ensure_create) != util::has_flag(mode, open_mode_t::ensure_exists) && "Create/Exists flags are mutually exclusive");
184 // Check if the file already exists/permission to read
185 auto tmp = std::fopen(path->str(), mode_for_fopen(open_mode_t::read));
186 const auto exists = (tmp != nullptr);
187
188 if (exists)
189 std::fclose(tmp);
190
191 if (exists && util::has_flag(mode, open_mode_t::ensure_create)
192 || !exists && util::has_flag(mode, open_mode_t::ensure_exists))
193 {
194 return{};
195 }
196 }
197 }
198
199 auto fopen_mode = mode_for_fopen(mode);
200 assert(fopen_mode != nullptr);
201
202 std::FILE *file = std::fopen(path->str(), fopen_mode);
203 if (file == nullptr)
204 return{}; // [TODO] Report system error?
205
206 return new sys_fd_t{ file, path, mode };
207}
208
209std_streams disvm::runtime::sys::get_std_streams()
210{
211 return
212 {
213 new sys_fd_t{ stdin, nullptr, (open_mode_t::read | open_mode_t::disable_seek) },
214 new sys_fd_t{ stdout, nullptr, (open_mode_t::write | open_mode_t::disable_seek) },
215 new sys_fd_t{ stderr, nullptr, (open_mode_t::write | open_mode_t::disable_seek) },
216 };
217}
src/vm/sys/fd_types.h+78−0
@@ -0,0 +1,78 @@
1//
2// Dis VM
3// File: fd_types.h
4// Author: arr
5//
6
7#ifndef _DISVM_SRC_VM_SYS_FD_TYPES_H_
8#define _DISVM_SRC_VM_SYS_FD_TYPES_H_
9
10#include <memory>
11
12#include <runtime.h>
13#include <utils.h>
14
15namespace disvm
16{
17 namespace runtime
18 {
19 namespace sys
20 {
21 enum class seek_start_t
22 {
23 start,
24 relative,
25 end,
26 };
27
28 enum class open_mode_t
29 {
30 none = 0,
31 read = (1 << 0),
32 write = (1 << 1),
33 truncate = (1 << 2),
34 atomic = (1 << 3),
35 ensure_create = (1 << 4), // Mutually exclusive with 'ensure_exists'
36 ensure_exists = (1 << 5), // Mutually exclusive with 'ensure_create'
37 delete_on_close = (1 << 6),
38 disable_seek = (1 << 7),
39 };
40
41 DEFINE_ENUM_FLAG_OPERATORS(open_mode_t);
42
43 // VM file descriptor
44 class vm_fd_t : public vm_alloc_t
45 {
46 public: // static
47 static std::shared_ptr<const type_descriptor_t> type_desc();
48
49 public:
50 // Read from the file descriptor into the supplied buffer
51 virtual word_t read(vm_t &vm, const word_t buffer_size_in_bytes, void *buffer) = 0;
52
53 // Write to the file descriptor from the supplied buffer
54 virtual void write(vm_t &vm, const word_t buffer_size_in_bytes, void *buffer) = 0;
55
56 // Seek to the supplied offset in the file descriptor
57 virtual big_t seek(vm_t &vm, const seek_start_t seek_start, const big_t offset) = 0;
58
59 protected:
60 vm_fd_t(std::shared_ptr<const type_descriptor_t> td);
61 };
62
63 // Create a file descriptor based on a file system path
64 vm_fd_t *create_from_file_path(vm_string_t *path, open_mode_t mode);
65
66 struct std_streams final
67 {
68 vm_fd_t *input;
69 vm_fd_t *output;
70 vm_fd_t *error;
71 };
72
73 std_streams get_std_streams();
74 }
75 }
76}
77
78#endif // _DISVM_SRC_VM_SYS_FD_TYPES_H_
src/vm/sys/file_system.cpp+0−46
@@ -1,46 +0,0 @@
1//
2// Dis VM
3// File: file_system.cpp
4// Author: arr
5//
6
7#include <iostream>
8#include <fstream>
9#include <mutex>
10#include <utils.h>
11#include "sys_utils.h"
12
13namespace
14{
15 std::mutex _create_file_stream_mutex;
16}
17
18std::unique_ptr<std::fstream> disvm::runtime::sys::create_file_stream(const char *path, std::ios::openmode mode, cfs_flags_t flags)
19{
20 auto file = std::unique_ptr<std::fstream>{};
21 if (flags == cfs_flags_t::none)
22 {
23 file = std::make_unique<std::fstream>(path, mode);
24 }
25 else
26 {
27 std::unique_lock<std::mutex> lock{ _create_file_stream_mutex, std::defer_lock };
28 if (util::has_flag(flags, cfs_flags_t::atomic))
29 lock.lock();
30
31 if (util::has_flag(flags, cfs_flags_t::ensure_create))
32 {
33 std::fstream file_exists{ path };
34 if (file_exists)
35 return{};
36 }
37
38 file = std::make_unique<std::fstream>(path, mode);
39 }
40
41 // Return null if file stream is not open.
42 if (!file->is_open())
43 return{};
44
45 return file;
46}
src/vm/sys/sys_utils.h+12−14
@@ -12,6 +12,7 @@ · 11 unmodified lines
12#include <memory>12#include <memory>
13#include <disvm.h>13#include <disvm.h>
14#include <utils.h>14#include <utils.h>
15#include "fd_types.h"
15 16
16namespace disvm17namespace disvm
17{18{
@@ -38,25 +39,22 @@ namespace disvm · 20 unmodified lines
38 pointer_t base,39 pointer_t base,
39 std::vector<char> &buffer);40 std::vector<char> &buffer);
40 41
41 enum class cfs_flags_t
42 {
43 none = 0,
44 atomic = 1 << 0,
45 ensure_create = 1 << 1,
46 };
47
48 DEFINE_ENUM_FLAG_OPERATORS(cfs_flags_t);
49
50 std::unique_ptr<std::fstream> create_file_stream(const char *path, std::ios::openmode mode, cfs_flags_t flags = sys::cfs_flags_t::none);
51
52 const word_t vm_invalid_fd = -1;42 const word_t vm_invalid_fd = -1;
53 43
54 // The first three FD records are optimized for lock-less access.44 // No reference count updates are performed on supplied vm_fd_t instance.
55 word_t create_fd_record(vm_alloc_t *fd_alloc);45 word_t create_fd_record(vm_fd_t *vm_fd);
46
47 // Returns 'false' if the supplied file descriptor is invalid, otherwise 'true'.
48 // No reference count updates are performed on supplied vm_fd_t instance.
49 bool try_update_fd_record(word_t fd, vm_fd_t *vm_fd);
56 50
57 // Returns null if the record does not exist.51 // Returns null if the record does not exist.
58 vm_alloc_t * fetch_fd_record(word_t fd);52 // If the record does exist, the reference count is incremented prior
53 // to the instance being returned.
54 vm_fd_t * fetch_fd_record(word_t fd);
59 55
56 // The associated vm_fd_t instance reference count is decremented
57 // and will be deleted once all references are released.
60 void drop_fd_record(word_t fd);58 void drop_fd_record(word_t fd);
61 }59 }
62 }60 }