mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
220 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79fe30321a | |||
| 35ee7f3cba | |||
| 4c2e86b063 | |||
| d52a9b61af | |||
| 8a5b39f734 | |||
| 775c9648f9 | |||
| f65bdf5733 | |||
| 213d930f8c | |||
| fae025aac8 | |||
| 97477ee51c | |||
| 99894686cf | |||
| 1162e30768 | |||
| cd910b1512 | |||
| efa86ddf46 | |||
| d8f60cd7f2 | |||
| c4d19dfa92 | |||
| 35e70f4be1 | |||
| eb6c388f13 | |||
| 42144d957b | |||
| d1c778680b | |||
| 0fe006157e | |||
| 4d208dc092 | |||
| 162e86663f | |||
| 83ffb68bb7 | |||
| 4705321988 | |||
| 37a2356485 | |||
| a7484f16cb | |||
| 6c8aad0afb | |||
| 12cc7388e7 | |||
| 2ff61bdfc7 | |||
| eb0d7465e2 | |||
| 07d798c61a | |||
| b426e8577b | |||
| 532133d648 | |||
| c056a0d108 | |||
| 6fe1825db9 | |||
| b15968f140 | |||
| 0ddf1bf660 | |||
| dade5b5ef2 | |||
| 3aea9a7c20 | |||
| 0dce7769f4 | |||
| 4b73438833 | |||
| 8c3f01fbfa | |||
| b7abacfa7e | |||
| 3383e9c556 | |||
| 0380601bb4 | |||
| 4b4c2a2abd | |||
| b1542d4e98 | |||
| d469c2da48 | |||
| 29c5e390aa | |||
| 3455e5690c | |||
| 0ca8a5e186 | |||
| cb85d00e9e | |||
| 8ce1ce85ad | |||
| a6d3cbe824 | |||
| 9b9aa9c353 | |||
| 831620bfc4 | |||
| 4f50988799 | |||
| ff97a73152 | |||
| 769d8dd038 | |||
| 1d793ea338 | |||
| 5337413c56 | |||
| 380905618a | |||
| 3ff56e4405 | |||
| 58297774f7 | |||
| 5e9ff85fa8 | |||
| eb7a9c55b0 | |||
| 6157af56e9 | |||
| d6f84887ff | |||
| 729ffeee09 | |||
| 0092995f9d | |||
| 3fb69d59bb | |||
| cb207afdf3 | |||
| 756c1b7bcb | |||
| cd484979a8 | |||
| 9e3ea92829 | |||
| c37de9459e | |||
| 4d512c2cf6 | |||
| 81f10f53ad | |||
| fbf036a654 | |||
| 40bcfc7c8d | |||
| bfe0ffd6e6 | |||
| 8ee6bb5d4b | |||
| 0ebc2add03 | |||
| 7840c1b89f | |||
| 0428d5ae2e | |||
| b967ae2739 | |||
| c462496bd5 | |||
| a903e5024c | |||
| 7cce55e2fc | |||
| 99a1a10286 | |||
| 9640b49319 | |||
| 1bc0e66ed1 | |||
| 117d32dfc4 | |||
| 320b84df4f | |||
| 98eaf5c6c0 | |||
| 9842019205 | |||
| 479278be4e | |||
| 4767311a22 | |||
| f50fc33749 | |||
| 8aba92da9b | |||
| 59f3e10f0a | |||
| 8b82bcef7d | |||
| 1e595f2e26 | |||
| 28ad4f8623 | |||
| a3c04db828 | |||
| 3ea7af4c9c | |||
| 190c3ab0cd | |||
| 53c7cf895c | |||
| db1b7b2d21 | |||
| 7cd7886111 | |||
| 164ba944ac | |||
| e7fb2cf73b | |||
| 023cc8b572 | |||
| 0ff5ff6ff2 | |||
| a35d6a6f8d | |||
| 663b62e45f | |||
| 6910182011 | |||
| bba47b6f54 | |||
| ef372bd861 | |||
| fbbfe438dc | |||
| 7e495a5fe5 | |||
| 0f036eebc0 | |||
| e008eeac6a | |||
| 25e330500f | |||
| fa20988f51 | |||
| 99f4cc3006 | |||
| a1487e4814 | |||
| 183a02c584 | |||
| 913e8b2e02 | |||
| 5800e085e8 | |||
| 623d687192 | |||
| fcb668663b | |||
| ad98efe1fd | |||
| 3fae8b49db | |||
| 8fb9db3deb | |||
| 0859ccc5c0 | |||
| 0c9ddd51a4 | |||
| f77709e67e | |||
| 81e3b64ecd | |||
| 39728b8bfb | |||
| 3b5998af12 | |||
| eea19f8112 | |||
| 268fb22bca | |||
| 37e23a19b5 | |||
| 7d55bfc120 | |||
| ab1741ab38 | |||
| af76d26771 | |||
| d2097e9fdd | |||
| d325c36eb8 | |||
| 79b55d5e2b | |||
| 0c9aaed9f7 | |||
| 82d5f48fa7 | |||
| 2239e43faf | |||
| 70b0ade8c3 | |||
| 86b6d01242 | |||
| 826a3b3012 | |||
| 35d622c131 | |||
| 4bdd2ff93c | |||
| 6fffed179b | |||
| e6b91d3d7c | |||
| 99a7bf9faa | |||
| 44eb478437 | |||
| fc2cd3e1d5 | |||
| a5a9347308 | |||
| b6ed117726 | |||
| 4b23decb08 | |||
| a70ea6579d | |||
| cade30b117 | |||
| 1ca641f718 | |||
| 6222e7be78 | |||
| c7deff4d2e | |||
| 590615ba52 | |||
| b1dafcfe6d | |||
| 4998cf80c1 | |||
| 37e23133e9 | |||
| 91fd9c1ef2 | |||
| 12687a63f4 | |||
| d699d872d9 | |||
| fb2cbe471b | |||
| 17894add95 | |||
| 23d93f6846 | |||
| 2e3dd8dd0b | |||
| 426f02906b | |||
| 2d12ba3ac0 | |||
| 21335e6459 | |||
| 8421cb6d21 | |||
| cac72a9423 | |||
| 9266b81aff | |||
| 52475b1761 | |||
| 2f6347b924 | |||
| eb5456f9c7 | |||
| f914fd0219 | |||
| c94ca4c0cb | |||
| 31a192454c | |||
| 4b2246ba9f | |||
| 0ffffb12da | |||
| 4c857bf031 | |||
| 3f3f4fafff | |||
| 4367ae4acf | |||
| 4eafb0ce7f | |||
| 7a4891b6b9 | |||
| 0171c276f0 | |||
| 0743dd195d | |||
| d1a204a784 | |||
| c2809c2948 | |||
| 99e5a14703 | |||
| 0efc79bcb9 | |||
| 57dea0e4d8 | |||
| 706d0c3a91 | |||
| 1637de3ebb | |||
| 45691a4622 | |||
| 9e47c72b98 | |||
| f5d13dc568 | |||
| a36c1cd54a | |||
| 01e8668357 | |||
| 0f3cebd2b7 | |||
| 7479ac48e8 | |||
| d5f94d73ad | |||
| 87094ef96c |
@@ -38,11 +38,6 @@ jobs:
|
||||
cd tests/vendor
|
||||
make
|
||||
timeout-minutes: 10
|
||||
- name: Odin issues tests
|
||||
run: |
|
||||
cd tests/issues
|
||||
./run.sh
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Linux i386
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||
timeout-minutes: 10
|
||||
|
||||
@@ -50,6 +50,7 @@ jobs:
|
||||
run: |
|
||||
mkdir dist
|
||||
cp odin dist
|
||||
cp libLLVM* dist
|
||||
cp -r shared dist
|
||||
cp -r core dist
|
||||
cp -r vendor dist
|
||||
|
||||
@@ -271,6 +271,7 @@ odin
|
||||
odin.dSYM
|
||||
*.bin
|
||||
demo.bin
|
||||
libLLVM*.so*
|
||||
|
||||
# shared collection
|
||||
shared/
|
||||
@@ -283,3 +284,4 @@ shared/
|
||||
*.sublime-workspace
|
||||
examples/bug/
|
||||
build.sh
|
||||
!core/debug/
|
||||
+19
-2
@@ -50,7 +50,19 @@ config_darwin() {
|
||||
}
|
||||
|
||||
config_freebsd() {
|
||||
: ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
|
||||
: ${LLVM_CONFIG=}
|
||||
|
||||
if [ ! "$LLVM_CONFIG" ]; then
|
||||
if which llvm-config11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config11
|
||||
elif which llvm-config12 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config12
|
||||
elif which llvm-config13 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config13
|
||||
else
|
||||
panic "Unable to find LLVM-config"
|
||||
fi
|
||||
fi
|
||||
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
@@ -87,7 +99,12 @@ config_linux() {
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs --libfiles) -Wl,-rpath=\$ORIGIN"
|
||||
|
||||
# Creates a copy of the llvm library in the build dir, this is meant to support compiler explorer.
|
||||
# The annoyance is that this copy can be cluttering the development folder. TODO: split staging folders
|
||||
# for development and compiler explorer builds
|
||||
cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
|
||||
}
|
||||
|
||||
build_odin() {
|
||||
|
||||
@@ -15,20 +15,16 @@ read_writer_init :: proc(rw: ^Read_Writer, r: ^Reader, w: ^Writer) {
|
||||
|
||||
read_writer_to_stream :: proc(rw: ^Read_Writer) -> (s: io.Stream) {
|
||||
s.stream_data = rw
|
||||
s.stream_vtable = _read_writer_vtable
|
||||
s.stream_vtable = &_read_writer_vtable
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_read_writer_vtable := &io.Stream_VTable{
|
||||
_read_writer_vtable := io.Stream_VTable{
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read(b, p)
|
||||
},
|
||||
impl_read_byte = proc(s: io.Stream) -> (c: byte, err: io.Error) {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_read_byte(b)
|
||||
},
|
||||
impl_unread_byte = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Read_Writer)(s.stream_data).r
|
||||
return reader_unread_byte(b)
|
||||
|
||||
@@ -353,14 +353,14 @@ reader_write_to :: proc(b: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
// reader_to_stream converts a Reader into an io.Stream
|
||||
reader_to_stream :: proc(b: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _reader_vtable
|
||||
s.stream_vtable = &_reader_vtable
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := &io.Stream_VTable{
|
||||
_reader_vtable := io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Reader)(s.stream_data)
|
||||
reader_destroy(b)
|
||||
|
||||
@@ -223,14 +223,14 @@ writer_read_from :: proc(b: ^Writer, r: io.Reader) -> (n: i64, err: io.Error) {
|
||||
// writer_to_stream converts a Writer into an io.Stream
|
||||
writer_to_stream :: proc(b: ^Writer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _writer_vtable
|
||||
s.stream_vtable = &_writer_vtable
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
_writer_vtable := &io.Stream_VTable{
|
||||
_writer_vtable := io.Stream_VTable{
|
||||
impl_destroy = proc(s: io.Stream) -> io.Error {
|
||||
b := (^Writer)(s.stream_data)
|
||||
writer_destroy(b)
|
||||
|
||||
@@ -240,14 +240,11 @@ buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.
|
||||
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
|
||||
b.last_read = .Invalid
|
||||
|
||||
if offset < 0 || offset >= len(b.buf) {
|
||||
if uint(offset) >= len(b.buf) {
|
||||
err = .Invalid_Offset
|
||||
return
|
||||
}
|
||||
|
||||
if 0 <= offset && offset < len(b.buf) {
|
||||
n = copy(p, b.buf[offset:])
|
||||
}
|
||||
n = copy(p, b.buf[offset:])
|
||||
if n > 0 {
|
||||
b.last_read = .Read
|
||||
}
|
||||
@@ -374,12 +371,12 @@ buffer_read_from :: proc(b: ^Buffer, r: io.Reader) -> (n: i64, err: io.Error) #n
|
||||
|
||||
buffer_to_stream :: proc(b: ^Buffer) -> (s: io.Stream) {
|
||||
s.stream_data = b
|
||||
s.stream_vtable = _buffer_vtable
|
||||
s.stream_vtable = &_buffer_vtable
|
||||
return
|
||||
}
|
||||
|
||||
@(private)
|
||||
_buffer_vtable := &io.Stream_VTable{
|
||||
_buffer_vtable := io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
b := (^Buffer)(s.stream_data)
|
||||
return i64(buffer_capacity(b))
|
||||
|
||||
@@ -638,7 +638,7 @@ trim_left_proc :: proc(s: []byte, p: proc(rune) -> bool) -> []byte {
|
||||
|
||||
index_rune :: proc(s: []byte, r: rune) -> int {
|
||||
switch {
|
||||
case 0 <= r && r < utf8.RUNE_SELF:
|
||||
case u32(r) < utf8.RUNE_SELF:
|
||||
return index_byte(s, byte(r))
|
||||
|
||||
case r == utf8.RUNE_ERROR:
|
||||
|
||||
@@ -17,7 +17,7 @@ reader_init :: proc(r: ^Reader, s: []byte) {
|
||||
|
||||
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = r
|
||||
s.stream_vtable = _reader_vtable
|
||||
s.stream_vtable = &_reader_vtable
|
||||
return
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
|
||||
|
||||
@(private)
|
||||
_reader_vtable := &io.Stream_VTable{
|
||||
_reader_vtable := io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_size(r)
|
||||
|
||||
@@ -49,8 +49,8 @@ foreign libc {
|
||||
// 7.3.8 Power and absolute-value functions
|
||||
cabs :: proc(z: complex_double) -> complex_double ---
|
||||
cabsf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(z: complex_double) -> complex_double ---
|
||||
cpowf :: proc(z: complex_float) -> complex_float ---
|
||||
cpow :: proc(x, y: complex_double) -> complex_double ---
|
||||
cpowf :: proc(x, y: complex_float) -> complex_float ---
|
||||
csqrt :: proc(z: complex_double) -> complex_double ---
|
||||
csqrtf :: proc(z: complex_float) -> complex_float ---
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package libc
|
||||
|
||||
when ODIN_OS == .Windows {
|
||||
foreign import libc "system:libucrt.lib"
|
||||
foreign import libc {
|
||||
"system:libucrt.lib",
|
||||
"system:legacy_stdio_definitions.lib",
|
||||
}
|
||||
} else when ODIN_OS == .Darwin {
|
||||
foreign import libc "system:System.framework"
|
||||
} else {
|
||||
|
||||
+27
-1
@@ -88,7 +88,6 @@ foreign libc {
|
||||
srand :: proc(seed: uint) ---
|
||||
|
||||
// 7.22.3 Memory management functions
|
||||
aligned_alloc :: proc(aligment, size: size_t) -> rawptr ---
|
||||
calloc :: proc(nmemb, size: size_t) -> rawptr ---
|
||||
free :: proc(ptr: rawptr) ---
|
||||
malloc :: proc(size: size_t) -> rawptr ---
|
||||
@@ -125,3 +124,30 @@ foreign libc {
|
||||
mbstowcs :: proc(pwcs: ^wchar_t, s: cstring, n: size_t) -> size_t ---
|
||||
wcstombs :: proc(s: [^]char, pwcs: ^wchar_t, n: size_t) -> size_t ---
|
||||
}
|
||||
|
||||
|
||||
aligned_alloc :: #force_inline proc "c" (alignment, size: size_t) -> rawptr {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_malloc :: proc(size, alignment: size_t) -> rawptr ---
|
||||
}
|
||||
return _aligned_malloc(size=size, alignment=alignment)
|
||||
} else {
|
||||
foreign libc {
|
||||
aligned_alloc :: proc(alignment, size: size_t) -> rawptr ---
|
||||
}
|
||||
return aligned_alloc(alignment=alignment, size=size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
aligned_free :: #force_inline proc "c" (ptr: rawptr) {
|
||||
when ODIN_OS == .Windows {
|
||||
foreign libc {
|
||||
_aligned_free :: proc(ptr: rawptr) ---
|
||||
}
|
||||
_aligned_free(ptr)
|
||||
} else {
|
||||
free(ptr)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package debug_pe
|
||||
|
||||
PE_SIGNATURE_OFFSET_INDEX_POS :: 0x3c
|
||||
PE_SIGNATURE :: u32le(0x0000_4550) // "PE\x00\x00"
|
||||
PE_SIGNATURE_STRING :: "PE\x00\x00"
|
||||
|
||||
OPTIONAL_HEADER_MAGIC :: enum u16le {
|
||||
PE32 = 0x010b,
|
||||
PE32_PLUS = 0x020b,
|
||||
}
|
||||
|
||||
Optional_Header_Base :: struct #packed {
|
||||
magic: OPTIONAL_HEADER_MAGIC,
|
||||
major_linker_version: u8,
|
||||
minor_linker_version: u8,
|
||||
size_of_code: u32le,
|
||||
size_of_initialized_data: u32le,
|
||||
size_of_uninitialized_data: u32le,
|
||||
address_of_entry_point: u32le,
|
||||
base_of_code: u32le,
|
||||
}
|
||||
|
||||
File_Header :: struct #packed {
|
||||
machine: IMAGE_FILE_MACHINE,
|
||||
number_of_sections: u16le,
|
||||
time_date_stamp: u32le,
|
||||
pointer_to_symbol_table: u32le,
|
||||
number_of_symbols: u32le,
|
||||
size_of_optional_header: u16le,
|
||||
characteristics: IMAGE_FILE_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Data_Directory :: struct #packed {
|
||||
virtual_address: u32le,
|
||||
size: u32le,
|
||||
}
|
||||
|
||||
Optional_Header32 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
base_of_data: u32le,
|
||||
image_base: u32le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u32le,
|
||||
size_of_stack_commit: u32le,
|
||||
size_of_heap_reserve: u32le,
|
||||
size_of_heap_commit: u32le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
Optional_Header64 :: struct #packed {
|
||||
using base: Optional_Header_Base,
|
||||
image_base: u64le,
|
||||
section_alignment: u32le,
|
||||
file_alignment: u32le,
|
||||
major_operating_system_version: u16le,
|
||||
minor_operating_system_version: u16le,
|
||||
major_image_version: u16le,
|
||||
minor_image_version: u16le,
|
||||
major_subsystem_version: u16le,
|
||||
minor_subsystem_version: u16le,
|
||||
win32_version_value: u32le,
|
||||
size_of_image: u32le,
|
||||
size_of_headers: u32le,
|
||||
check_sum: u32le,
|
||||
subsystem: IMAGE_SUBSYSTEM,
|
||||
dll_characteristics: IMAGE_DLLCHARACTERISTICS,
|
||||
size_of_stack_reserve: u64le,
|
||||
size_of_stack_commit: u64le,
|
||||
size_of_heap_reserve: u64le,
|
||||
size_of_heap_commit: u64le,
|
||||
loader_flags: u32le,
|
||||
number_of_rva_and_sizes: u32le,
|
||||
data_directory: [16]Data_Directory,
|
||||
}
|
||||
|
||||
// .debug section
|
||||
Debug_Directory_Entry :: struct {
|
||||
characteristics: u32le,
|
||||
time_date_stamp: u32le,
|
||||
major_version: u16le,
|
||||
minor_version: u16le,
|
||||
type: IMAGE_DEBUG_TYPE,
|
||||
size_of_data: u32le,
|
||||
address_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
}
|
||||
|
||||
|
||||
IMAGE_FILE_MACHINE :: enum u16le {
|
||||
UNKNOWN = 0x0,
|
||||
AM33 = 0x1d3,
|
||||
AMD64 = 0x8664,
|
||||
ARM = 0x1c0,
|
||||
ARMNT = 0x1c4,
|
||||
ARM64 = 0xaa64,
|
||||
EBC = 0xebc,
|
||||
I386 = 0x14c,
|
||||
IA64 = 0x200,
|
||||
LOONGARCH32 = 0x6232,
|
||||
LOONGARCH64 = 0x6264,
|
||||
M32R = 0x9041,
|
||||
MIPS16 = 0x266,
|
||||
MIPSFPU = 0x366,
|
||||
MIPSFPU16 = 0x466,
|
||||
POWERPC = 0x1f0,
|
||||
POWERPCFP = 0x1f1,
|
||||
R4000 = 0x166,
|
||||
SH3 = 0x1a2,
|
||||
SH3DSP = 0x1a3,
|
||||
SH4 = 0x1a6,
|
||||
SH5 = 0x1a8,
|
||||
THUMB = 0x1c2,
|
||||
WCEMIPSV2 = 0x169,
|
||||
}
|
||||
|
||||
// IMAGE_DIRECTORY_ENTRY constants
|
||||
IMAGE_DIRECTORY_ENTRY :: enum u8 {
|
||||
EXPORT = 0,
|
||||
IMPORT = 1,
|
||||
RESOURCE = 2,
|
||||
EXCEPTION = 3,
|
||||
SECURITY = 4,
|
||||
BASERELOC = 5,
|
||||
DEBUG = 6,
|
||||
ARCHITECTURE = 7, // reserved
|
||||
GLOBALPTR = 8,
|
||||
TLS = 9,
|
||||
LOAD_CONFIG = 10,
|
||||
BOUND_IMPORT = 11,
|
||||
IAT = 12,
|
||||
DELAY_IMPORT = 13,
|
||||
COM_DESCRIPTOR = 14, // DLR Runtime headers
|
||||
_RESERVED = 15,
|
||||
}
|
||||
#assert(len(IMAGE_DIRECTORY_ENTRY) == 16)
|
||||
|
||||
|
||||
IMAGE_FILE_CHARACTERISTICS :: distinct bit_set[IMAGE_FILE_CHARACTERISTIC; u16le]
|
||||
IMAGE_FILE_CHARACTERISTIC :: enum u16le {
|
||||
RELOCS_STRIPPED = 0,
|
||||
EXECUTABLE_IMAGE = 1,
|
||||
LINE_NUMS_STRIPPED = 2,
|
||||
LOCAL_SYMS_STRIPPED = 3,
|
||||
AGGRESIVE_WS_TRIM = 4,
|
||||
LARGE_ADDRESS_AWARE = 5,
|
||||
|
||||
BYTES_REVERSED_LO = 7,
|
||||
MACHINE_32BIT = 8, // IMAGE_FILE_32BIT_MACHINE originally
|
||||
DEBUG_STRIPPED = 9,
|
||||
REMOVABLE_RUN_FROM_SWAP = 10,
|
||||
NET_RUN_FROM_SWAP = 11,
|
||||
SYSTEM = 12,
|
||||
DLL = 13,
|
||||
UP_SYSTEM_ONLY = 14,
|
||||
BYTES_REVERSED_HI = 15,
|
||||
}
|
||||
|
||||
IMAGE_SUBSYSTEM :: enum u16le {
|
||||
UNKNOWN = 0,
|
||||
NATIVE = 1,
|
||||
WINDOWS_GUI = 2,
|
||||
WINDOWS_CUI = 3,
|
||||
OS2_CUI = 5,
|
||||
POSIX_CUI = 7,
|
||||
NATIVE_WINDOWS = 8,
|
||||
WINDOWS_CE_GUI = 9,
|
||||
EFI_APPLICATION = 10,
|
||||
EFI_BOOT_SERVICE_DRIVER = 11,
|
||||
EFI_RUNTIME_DRIVER = 12,
|
||||
EFI_ROM = 13,
|
||||
XBOX = 14,
|
||||
WINDOWS_BOOT_APPLICATION = 16,
|
||||
}
|
||||
|
||||
IMAGE_DLLCHARACTERISTICS :: distinct bit_set[IMAGE_DLLCHARACTERISTIC; u16le]
|
||||
IMAGE_DLLCHARACTERISTIC :: enum u16le {
|
||||
HIGH_ENTROPY_VA = 5,
|
||||
DYNAMIC_BASE = 6,
|
||||
FORCE_INTEGRITY = 7,
|
||||
NX_COMPAT = 8,
|
||||
NO_ISOLATION = 9,
|
||||
NO_SEH = 10,
|
||||
NO_BIND = 11,
|
||||
APPCONTAINER = 12,
|
||||
WDM_DRIVER = 13,
|
||||
GUARD_CF = 14,
|
||||
TERMINAL_SERVER_AWARE = 15,
|
||||
}
|
||||
|
||||
IMAGE_DEBUG_TYPE :: enum u32le {
|
||||
UNKNOWN = 0, // An unknown value that is ignored by all tools.
|
||||
COFF = 1, // The COFF debug information (line numbers, symbol table, and string table). This type of debug information is also pointed to by fields in the file headers.
|
||||
CODEVIEW = 2, // The Visual C++ debug information.
|
||||
FPO = 3, // The frame pointer omission (FPO) information. This information tells the debugger how to interpret nonstandard stack frames, which use the EBP register for a purpose other than as a frame pointer.
|
||||
MISC = 4, // The location of DBG file.
|
||||
EXCEPTION = 5, // A copy of .pdata section.
|
||||
FIXUP = 6, // Reserved.
|
||||
OMAP_TO_SRC = 7, // The mapping from an RVA in image to an RVA in source image.
|
||||
OMAP_FROM_SRC = 8, // The mapping from an RVA in source image to an RVA in image.
|
||||
BORLAND = 9, // Reserved for Borland.
|
||||
RESERVED10 = 10, // Reserved.
|
||||
CLSID = 11, // Reserved.
|
||||
REPRO = 16, // PE determinism or reproducibility.
|
||||
EX_DLLCHARACTERISTICS = 20, // Extended DLL characteristics bits.
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package debug_pe
|
||||
|
||||
import "core:runtime"
|
||||
import "core:io"
|
||||
|
||||
Section_Header32 :: struct {
|
||||
name: [8]u8,
|
||||
virtual_size: u32le,
|
||||
virtual_address: u32le,
|
||||
size_of_raw_data: u32le,
|
||||
pointer_to_raw_data: u32le,
|
||||
pointer_to_relocations: u32le,
|
||||
pointer_to_line_numbers: u32le,
|
||||
number_of_relocations: u16le,
|
||||
number_of_line_numbers: u16le,
|
||||
characteristics: IMAGE_SCN_CHARACTERISTICS,
|
||||
}
|
||||
|
||||
Reloc :: struct {
|
||||
virtual_address: u32le,
|
||||
symbol_table_index: u32le,
|
||||
type: IMAGE_REL,
|
||||
}
|
||||
|
||||
IMAGE_SCN_CHARACTERISTICS :: enum u32le {
|
||||
TYPE_NO_PAD = 0x00000008, // The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. = 0x00000010, // Reserved for future use.
|
||||
CNT_CODE = 0x00000020, // The section contains executable code.
|
||||
CNT_INITIALIZED_DATA = 0x00000040, // The section contains initialized data.
|
||||
CNT_UNINITIALIZED_DATA = 0x00000080, // The section contains uninitialized data.
|
||||
LNK_OTHER = 0x00000100, // Reserved for future use.
|
||||
LNK_INFO = 0x00000200, // The section contains comments or other information. The .drectve section has this type. This is valid for object files only. = 0x00000400, // Reserved for future use.
|
||||
LNK_REMOVE = 0x00000800, // The section will not become part of the image. This is valid only for object files.
|
||||
LNK_COMDAT = 0x00001000, // The section contains COMDAT data. For more information, see COMDAT Sections (Object Only). This is valid only for object files.
|
||||
GPREL = 0x00008000, // The section contains data referenced through the global pointer (GP).
|
||||
MEM_PURGEABLE = 0x00020000, // Reserved for future use.
|
||||
MEM_16BIT = 0x00020000, // Reserved for future use.
|
||||
MEM_LOCKED = 0x00040000, // Reserved for future use.
|
||||
MEM_PRELOAD = 0x00080000, // Reserved for future use.
|
||||
ALIGN_1BYTES = 0x00100000, // Align data on a 1-byte boundary. Valid only for object files.
|
||||
ALIGN_2BYTES = 0x00200000, // Align data on a 2-byte boundary. Valid only for object files.
|
||||
ALIGN_4BYTES = 0x00300000, // Align data on a 4-byte boundary. Valid only for object files.
|
||||
ALIGN_8BYTES = 0x00400000, // Align data on an 8-byte boundary. Valid only for object files.
|
||||
ALIGN_16BYTES = 0x00500000, // Align data on a 16-byte boundary. Valid only for object files.
|
||||
ALIGN_32BYTES = 0x00600000, // Align data on a 32-byte boundary. Valid only for object files.
|
||||
ALIGN_64BYTES = 0x00700000, // Align data on a 64-byte boundary. Valid only for object files.
|
||||
ALIGN_128BYTES = 0x00800000, // Align data on a 128-byte boundary. Valid only for object files.
|
||||
ALIGN_256BYTES = 0x00900000, // Align data on a 256-byte boundary. Valid only for object files.
|
||||
ALIGN_512BYTES = 0x00A00000, // Align data on a 512-byte boundary. Valid only for object files.
|
||||
ALIGN_1024BYTES = 0x00B00000, // Align data on a 1024-byte boundary. Valid only for object files.
|
||||
ALIGN_2048BYTES = 0x00C00000, // Align data on a 2048-byte boundary. Valid only for object files.
|
||||
ALIGN_4096BYTES = 0x00D00000, // Align data on a 4096-byte boundary. Valid only for object files.
|
||||
ALIGN_8192BYTES = 0x00E00000, // Align data on an 8192-byte boundary. Valid only for object files.
|
||||
LNK_NRELOC_OVFL = 0x01000000, // The section contains extended relocations.
|
||||
MEM_DISCARDABLE = 0x02000000, // The section can be discarded as needed.
|
||||
MEM_NOT_CACHED = 0x04000000, // The section cannot be cached.
|
||||
MEM_NOT_PAGED = 0x08000000, // The section is not pageable.
|
||||
MEM_SHARED = 0x10000000, // The section can be shared in memory.
|
||||
MEM_EXECUTE = 0x20000000, // The section can be executed as code.
|
||||
MEM_READ = 0x40000000, // The section can be read.
|
||||
MEM_WRITE = 0x80000000, // The section can be written to.
|
||||
}
|
||||
|
||||
|
||||
IMAGE_REL :: enum u16le {
|
||||
I386_ABSOLUTE = 0x0000,
|
||||
I386_DIR16 = 0x0001,
|
||||
I386_REL16 = 0x0002,
|
||||
I386_DIR32 = 0x0006,
|
||||
I386_DIR32NB = 0x0007,
|
||||
I386_SEG12 = 0x0009,
|
||||
I386_SECTION = 0x000A,
|
||||
I386_SECREL = 0x000B,
|
||||
I386_TOKEN = 0x000C,
|
||||
I386_SECREL7 = 0x000D,
|
||||
I386_REL32 = 0x0014,
|
||||
|
||||
AMD64_ABSOLUTE = 0x0000,
|
||||
AMD64_ADDR64 = 0x0001,
|
||||
AMD64_ADDR32 = 0x0002,
|
||||
AMD64_ADDR32NB = 0x0003,
|
||||
AMD64_REL32 = 0x0004,
|
||||
AMD64_REL32_1 = 0x0005,
|
||||
AMD64_REL32_2 = 0x0006,
|
||||
AMD64_REL32_3 = 0x0007,
|
||||
AMD64_REL32_4 = 0x0008,
|
||||
AMD64_REL32_5 = 0x0009,
|
||||
AMD64_SECTION = 0x000A,
|
||||
AMD64_SECREL = 0x000B,
|
||||
AMD64_SECREL7 = 0x000C,
|
||||
AMD64_TOKEN = 0x000D,
|
||||
AMD64_SREL32 = 0x000E,
|
||||
AMD64_PAIR = 0x000F,
|
||||
AMD64_SSPAN32 = 0x0010,
|
||||
|
||||
ARM_ABSOLUTE = 0x0000,
|
||||
ARM_ADDR32 = 0x0001,
|
||||
ARM_ADDR32NB = 0x0002,
|
||||
ARM_BRANCH24 = 0x0003,
|
||||
ARM_BRANCH11 = 0x0004,
|
||||
ARM_SECTION = 0x000E,
|
||||
ARM_SECREL = 0x000F,
|
||||
ARM_MOV32 = 0x0010,
|
||||
|
||||
THUMB_MOV32 = 0x0011,
|
||||
THUMB_BRANCH20 = 0x0012,
|
||||
THUMB_BRANCH24 = 0x0014,
|
||||
THUMB_BLX23 = 0x0015,
|
||||
|
||||
ARM_PAIR = 0x0016,
|
||||
|
||||
ARM64_ABSOLUTE = 0x0000,
|
||||
ARM64_ADDR32 = 0x0001,
|
||||
ARM64_ADDR32NB = 0x0002,
|
||||
ARM64_BRANCH26 = 0x0003,
|
||||
ARM64_PAGEBASE_REL21 = 0x0004,
|
||||
ARM64_REL21 = 0x0005,
|
||||
ARM64_PAGEOFFSET_12A = 0x0006,
|
||||
ARM64_PAGEOFFSET_12L = 0x0007,
|
||||
ARM64_SECREL = 0x0008,
|
||||
ARM64_SECREL_LOW12A = 0x0009,
|
||||
ARM64_SECREL_HIGH12A = 0x000A,
|
||||
ARM64_SECREL_LOW12L = 0x000B,
|
||||
ARM64_TOKEN = 0x000C,
|
||||
ARM64_SECTION = 0x000D,
|
||||
ARM64_ADDR64 = 0x000E,
|
||||
ARM64_BRANCH19 = 0x000F,
|
||||
ARM64_BRANCH14 = 0x0010,
|
||||
ARM64_REL32 = 0x0011,
|
||||
}
|
||||
|
||||
PE_CODE_VIEW_SIGNATURE_RSDS :: u32le(0x5344_5352)
|
||||
@@ -0,0 +1,108 @@
|
||||
package debug_pe
|
||||
|
||||
COFF_SYMBOL_SIZE :: 18
|
||||
|
||||
COFF_Symbol :: struct {
|
||||
name: [8]u8,
|
||||
value: u32le,
|
||||
section_number: i16le,
|
||||
type: IMAGE_SYM_TYPE,
|
||||
storage_class: IMAGE_SYM_CLASS,
|
||||
number_of_aux_symbols: u8,
|
||||
}
|
||||
|
||||
// COFF_Symbol_Aux_Format5 describes the expected form of an aux symbol
|
||||
// attached to a section definition symbol. The PE format defines a
|
||||
// number of different aux symbol formats: format 1 for function
|
||||
// definitions, format 2 for .be and .ef symbols, and so on. Format 5
|
||||
// holds extra info associated with a section definition, including
|
||||
// number of relocations + line numbers, as well as COMDAT info. See
|
||||
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#auxiliary-format-5-section-definitions
|
||||
// for more on what's going on here.
|
||||
COFF_Symbol_Aux_Format5 :: struct {
|
||||
size: u32le,
|
||||
num_relocs: u16le,
|
||||
num_line_numbers: u16le,
|
||||
checksum: u32le,
|
||||
sec_num: u16le,
|
||||
selection: IMAGE_COMDAT_SELECT,
|
||||
_: [3]u8, // padding
|
||||
}
|
||||
|
||||
IMAGE_COMDAT_SELECT :: enum u8 {
|
||||
NODUPLICATES = 1,
|
||||
ANY = 2,
|
||||
SAME_SIZE = 3,
|
||||
EXACT_MATCH = 4,
|
||||
ASSOCIATIVE = 5,
|
||||
LARGEST = 6,
|
||||
}
|
||||
|
||||
|
||||
// The symbol record is not yet assigned a section. A value of zero indicates
|
||||
// that a reference to an external symbol is defined elsewhere. A value of
|
||||
// non-zero is a common symbol with a size that is specified by the value.
|
||||
IMAGE_SYM_UNDEFINED :: 0
|
||||
// The symbol has an absolute (non-relocatable) value and is not an address.
|
||||
IMAGE_SYM_ABSOLUTE :: -1
|
||||
// The symbol provides general type or debugging information but does not
|
||||
// correspond to a section. Microsoft tools use this setting along
|
||||
// with .file records (storage class FILE).
|
||||
IMAGE_SYM_DEBUG :: -2
|
||||
|
||||
IMAGE_SYM_TYPE :: enum u16le {
|
||||
NULL = 0,
|
||||
VOID = 1,
|
||||
CHAR = 2,
|
||||
SHORT = 3,
|
||||
INT = 4,
|
||||
LONG = 5,
|
||||
FLOAT = 6,
|
||||
DOUBLE = 7,
|
||||
STRUCT = 8,
|
||||
UNION = 9,
|
||||
ENUM = 10,
|
||||
MOE = 11,
|
||||
BYTE = 12,
|
||||
WORD = 13,
|
||||
UINT = 14,
|
||||
DWORD = 15,
|
||||
PCODE = 32768,
|
||||
|
||||
DTYPE_NULL = 0,
|
||||
DTYPE_POINTER = 0x10,
|
||||
DTYPE_FUNCTION = 0x20,
|
||||
DTYPE_ARRAY = 0x30,
|
||||
}
|
||||
|
||||
IMAGE_SYM_CLASS :: enum u8 {
|
||||
NULL = 0,
|
||||
AUTOMATIC = 1,
|
||||
EXTERNAL = 2,
|
||||
STATIC = 3,
|
||||
REGISTER = 4,
|
||||
EXTERNAL_DEF = 5,
|
||||
LABEL = 6,
|
||||
UNDEFINED_LABEL = 7,
|
||||
MEMBER_OF_STRUCT = 8,
|
||||
ARGUMENT = 9,
|
||||
STRUCT_TAG = 10,
|
||||
MEMBER_OF_UNION = 11,
|
||||
UNION_TAG = 12,
|
||||
TYPE_DEFINITION = 13,
|
||||
UNDEFINED_STATIC = 14,
|
||||
ENUM_TAG = 15,
|
||||
MEMBER_OF_ENUM = 16,
|
||||
REGISTER_PARAM = 17,
|
||||
BIT_FIELD = 18,
|
||||
FAR_EXTERNAL = 68, // Not in PECOFF v8 spec
|
||||
BLOCK = 100,
|
||||
FUNCTION = 101,
|
||||
END_OF_STRUCT = 102,
|
||||
FILE = 103,
|
||||
SECTION = 104,
|
||||
WEAK_EXTERNAL = 105,
|
||||
CLR_TOKEN = 107,
|
||||
|
||||
END_OF_FUNCTION = 255,
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import "core:math/bits"
|
||||
import "core:runtime"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
import "core:reflect"
|
||||
import "core:io"
|
||||
|
||||
Marshal_Data_Error :: enum {
|
||||
@@ -302,7 +303,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
|
||||
for name, i in info.names {
|
||||
opt_write_iteration(w, opt, i) or_return
|
||||
opt_write_key(w, opt, name) or_return
|
||||
if json_name := string(reflect.struct_tag_get(auto_cast info.tags[i], "json")); json_name != "" {
|
||||
opt_write_key(w, opt, json_name) or_return
|
||||
} else {
|
||||
opt_write_key(w, opt, name) or_return
|
||||
}
|
||||
|
||||
id := info.types[i].id
|
||||
data := rawptr(uintptr(v.data) + info.offsets[i])
|
||||
|
||||
@@ -380,13 +380,18 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
field := any{field_ptr, type.id}
|
||||
unmarshal_value(p, field) or_return
|
||||
|
||||
if parse_comma(p) {
|
||||
break struct_loop
|
||||
}
|
||||
continue struct_loop
|
||||
} else {
|
||||
// allows skipping unused struct fields
|
||||
parse_value(p) or_return
|
||||
if parse_comma(p) {
|
||||
break struct_loop
|
||||
}
|
||||
continue struct_loop
|
||||
}
|
||||
|
||||
return Unsupported_Type_Error{v.id, p.curr_token}
|
||||
}
|
||||
|
||||
case reflect.Type_Info_Map:
|
||||
@@ -398,7 +403,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
raw_map.entries.allocator = p.allocator
|
||||
}
|
||||
|
||||
header := runtime.__get_map_header_runtime(raw_map, t)
|
||||
header := runtime.__get_map_header_table_runtime(t)
|
||||
|
||||
elem_backing := bytes_make(t.value.size, t.value.align, p.allocator) or_return
|
||||
defer delete(elem_backing, p.allocator)
|
||||
@@ -415,19 +420,17 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
|
||||
delete(key, p.allocator)
|
||||
return err
|
||||
}
|
||||
|
||||
hash := runtime.Map_Hash {
|
||||
hash = runtime.default_hasher_string(&key, 0),
|
||||
key_ptr = &key,
|
||||
}
|
||||
|
||||
|
||||
key_hash := runtime.default_hasher_string(&key, 0)
|
||||
key_ptr := rawptr(&key)
|
||||
|
||||
key_cstr: cstring
|
||||
if reflect.is_cstring(t.key) {
|
||||
key_cstr = cstring(raw_data(key))
|
||||
hash.key_ptr = &key_cstr
|
||||
key_ptr = &key_cstr
|
||||
}
|
||||
|
||||
set_ptr := runtime.__dynamic_map_set(header, hash, map_backing_value.data)
|
||||
set_ptr := runtime.__dynamic_map_set(raw_map, header, key_hash, key_ptr, map_backing_value.data)
|
||||
if set_ptr == nil {
|
||||
delete(key, p.allocator)
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ foreign odin_env {
|
||||
}
|
||||
|
||||
@(private="file")
|
||||
write_vtable := &io.Stream_VTable{
|
||||
write_vtable := io.Stream_VTable{
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
fd := u32(uintptr(s.stream_data))
|
||||
write(fd, p)
|
||||
@@ -22,14 +22,14 @@ write_vtable := &io.Stream_VTable{
|
||||
@(private="file")
|
||||
stdout := io.Writer{
|
||||
stream = {
|
||||
stream_vtable = write_vtable,
|
||||
stream_vtable = &write_vtable,
|
||||
stream_data = rawptr(uintptr(1)),
|
||||
},
|
||||
}
|
||||
@(private="file")
|
||||
stderr := io.Writer{
|
||||
stream = {
|
||||
stream_vtable = write_vtable,
|
||||
stream_vtable = &write_vtable,
|
||||
stream_data = rawptr(uintptr(2)),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -188,6 +188,8 @@ type_field_index_of :: proc($T: typeid, $name: string) -> uintptr ---
|
||||
type_equal_proc :: proc($T: typeid) -> (equal: proc "contextless" (rawptr, rawptr) -> bool) where type_is_comparable(T) ---
|
||||
type_hasher_proc :: proc($T: typeid) -> (hasher: proc "contextless" (data: rawptr, seed: uintptr) -> uintptr) where type_is_comparable(T) ---
|
||||
|
||||
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
|
||||
|
||||
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
|
||||
// SIMD related
|
||||
|
||||
@@ -122,73 +122,3 @@ to_write_seeker :: proc(s: Stream) -> (w: Write_Seeker, ok: bool = true) #option
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
to_byte_reader :: proc(s: Stream) -> (b: Byte_Reader, ok: bool = true) #optional_ok {
|
||||
b.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read_byte == nil {
|
||||
ok = false
|
||||
if s.stream_vtable != nil && s.impl_read != nil {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
to_byte_scanner :: proc(s: Stream) -> (b: Byte_Scanner, ok: bool = true) #optional_ok {
|
||||
b.stream = s
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_unread_byte == nil {
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
if s.impl_read_byte != nil {
|
||||
ok = true
|
||||
} else if s.impl_read != nil {
|
||||
ok = true
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
to_byte_writer :: proc(s: Stream) -> (b: Byte_Writer, ok: bool = true) #optional_ok {
|
||||
b.stream = s
|
||||
if s.stream_vtable == nil || s.impl_write_byte == nil {
|
||||
ok = false
|
||||
if s.stream_vtable != nil && s.impl_write != nil {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
to_rune_reader :: proc(s: Stream) -> (r: Rune_Reader, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable == nil || s.impl_read_rune == nil {
|
||||
ok = false
|
||||
if s.stream_vtable != nil && s.impl_read != nil {
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
to_rune_scanner :: proc(s: Stream) -> (r: Rune_Scanner, ok: bool = true) #optional_ok {
|
||||
r.stream = s
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_unread_rune == nil {
|
||||
ok = false
|
||||
return
|
||||
}
|
||||
if s.impl_read_rune != nil {
|
||||
ok = true
|
||||
} else if s.impl_read != nil {
|
||||
ok = true
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
} else {
|
||||
ok = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+53
-34
@@ -123,13 +123,6 @@ Writer_At :: struct {using stream: Stream}
|
||||
Reader_From :: struct {using stream: Stream}
|
||||
Writer_To :: struct {using stream: Stream}
|
||||
|
||||
Byte_Reader :: struct {using stream: Stream}
|
||||
Byte_Scanner :: struct {using stream: Stream}
|
||||
Byte_Writer :: struct {using stream: Stream}
|
||||
|
||||
Rune_Reader :: struct {using stream: Stream}
|
||||
Rune_Scanner :: struct {using stream: Stream}
|
||||
|
||||
|
||||
destroy :: proc(s: Stream) -> Error {
|
||||
close_err := close({s})
|
||||
@@ -147,24 +140,48 @@ destroy :: proc(s: Stream) -> Error {
|
||||
// When read encounters an .EOF or error after successfully reading n > 0 bytes, it returns the number of
|
||||
// bytes read along with the error.
|
||||
read :: proc(s: Reader, p: []byte, n_read: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_read != nil {
|
||||
n, err = s->impl_read(p)
|
||||
if n_read != nil {
|
||||
n_read^ += n
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_read != nil {
|
||||
n, err = s->impl_read(p)
|
||||
if n_read != nil {
|
||||
n_read^ += n
|
||||
}
|
||||
return
|
||||
} else if s.impl_read_byte != nil {
|
||||
bytes_read := 0
|
||||
defer if n_read != nil {
|
||||
n_read^ += bytes_read
|
||||
}
|
||||
for _, i in p {
|
||||
p[i] = s->impl_read_byte() or_return
|
||||
bytes_read += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
|
||||
// write writes up to len(p) bytes into s. It returns the number of bytes written and any error if occurred.
|
||||
write :: proc(s: Writer, p: []byte, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
if s.stream_vtable != nil && s.impl_write != nil {
|
||||
n, err = s->impl_write(p)
|
||||
if n_written != nil {
|
||||
n_written^ += n
|
||||
if s.stream_vtable != nil {
|
||||
if s.impl_write != nil {
|
||||
n, err = s->impl_write(p)
|
||||
if n_written != nil {
|
||||
n_written^ += n
|
||||
}
|
||||
return
|
||||
} else if s.impl_write_byte != nil {
|
||||
bytes_written := 0
|
||||
defer if n_written != nil {
|
||||
n_written^ += bytes_written
|
||||
}
|
||||
for c in p {
|
||||
s->impl_write_byte(c) or_return
|
||||
bytes_written += 1
|
||||
}
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
return 0, .Empty
|
||||
}
|
||||
@@ -319,7 +336,7 @@ read_from :: proc(w: Reader_From, r: Reader) -> (n: i64, err: Error) {
|
||||
|
||||
|
||||
// read_byte reads and returns the next byte from r.
|
||||
read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
|
||||
read_byte :: proc(r: Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += 1
|
||||
}
|
||||
@@ -339,21 +356,12 @@ read_byte :: proc(r: Byte_Reader, n_read: ^int = nil) -> (b: byte, err: Error) {
|
||||
return buf[0], err
|
||||
}
|
||||
|
||||
write_byte :: proc{
|
||||
write_byte_to_byte_writer,
|
||||
write_byte_to_writer,
|
||||
}
|
||||
|
||||
write_byte_to_byte_writer :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> Error {
|
||||
return _write_byte(w, c, n_written)
|
||||
}
|
||||
|
||||
write_byte_to_writer :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error {
|
||||
write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> Error {
|
||||
return _write_byte(auto_cast w, c, n_written)
|
||||
}
|
||||
|
||||
@(private)
|
||||
_write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Error) {
|
||||
_write_byte :: proc(w: Writer, c: byte, n_written: ^int = nil) -> (err: Error) {
|
||||
defer if err == nil && n_written != nil {
|
||||
n_written^ += 1
|
||||
}
|
||||
@@ -373,7 +381,7 @@ _write_byte :: proc(w: Byte_Writer, c: byte, n_written: ^int = nil) -> (err: Err
|
||||
}
|
||||
|
||||
// read_rune reads a single UTF-8 encoded Unicode codepoint and returns the rune and its size in bytes.
|
||||
read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
|
||||
read_rune :: proc(br: Reader, n_read: ^int = nil) -> (ch: rune, size: int, err: Error) {
|
||||
defer if err == nil && n_read != nil {
|
||||
n_read^ += size
|
||||
}
|
||||
@@ -417,13 +425,21 @@ read_rune :: proc(br: Rune_Reader, n_read: ^int = nil) -> (ch: rune, size: int,
|
||||
return
|
||||
}
|
||||
|
||||
unread_byte :: proc(s: Byte_Scanner) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_unread_byte != nil {
|
||||
unread_byte :: proc(s: Stream) -> Error {
|
||||
if s.stream_vtable == nil {
|
||||
return .Empty
|
||||
}
|
||||
if s.impl_unread_byte != nil {
|
||||
return s->impl_unread_byte()
|
||||
}
|
||||
if s.impl_seek != nil {
|
||||
_, err := s->impl_seek(-1, .Current)
|
||||
return err
|
||||
}
|
||||
|
||||
return .Empty
|
||||
}
|
||||
unread_rune :: proc(s: Rune_Scanner) -> Error {
|
||||
unread_rune :: proc(s: Writer) -> Error {
|
||||
if s.stream_vtable != nil && s.impl_unread_rune != nil {
|
||||
return s->impl_unread_rune()
|
||||
}
|
||||
@@ -442,7 +458,10 @@ write_rune :: proc(s: Writer, r: rune, n_written: ^int = nil) -> (size: int, err
|
||||
n_written^ += size
|
||||
}
|
||||
|
||||
if s.stream_vtable != nil && s.impl_write_rune != nil {
|
||||
if s.stream_vtable == nil {
|
||||
return 0, .Empty
|
||||
}
|
||||
if s.impl_write_rune != nil {
|
||||
return s->impl_write_rune(r)
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ max_single :: proc(a: $T) -> (out: ELEM_TYPE(T)) where IS_NUMERIC(ELEM_TYPE(T))
|
||||
} else when N == 2 {
|
||||
out = builtin.max(a[0], a[1])
|
||||
} else when N == 3 {
|
||||
out = builtin.max(a[0], a[1], a[3])
|
||||
out = builtin.max(a[0], a[1], a[2])
|
||||
}else {
|
||||
out = builtin.max(a[0], a[1])
|
||||
for i in 2..<N {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package math
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:builtin"
|
||||
_ :: intrinsics
|
||||
|
||||
Float_Class :: enum {
|
||||
@@ -36,6 +37,11 @@ MAX_F16_PRECISION :: 4 // Maximum number of meaningful digits after the decimal
|
||||
RAD_PER_DEG :: TAU/360.0
|
||||
DEG_PER_RAD :: 360.0/TAU
|
||||
|
||||
abs :: builtin.abs
|
||||
min :: builtin.min
|
||||
max :: builtin.max
|
||||
clamp :: builtin.clamp
|
||||
|
||||
sqrt_f16le :: proc "contextless" (x: f16le) -> f16le { return #force_inline f16le(sqrt_f16(f16(x))) }
|
||||
sqrt_f16be :: proc "contextless" (x: f16be) -> f16be { return #force_inline f16be(sqrt_f16(f16(x))) }
|
||||
sqrt_f32le :: proc "contextless" (x: f32le) -> f32le { return #force_inline f32le(sqrt_f32(f32(x))) }
|
||||
|
||||
@@ -63,6 +63,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
}
|
||||
|
||||
page_size := DEFAULT_PAGE_SIZE
|
||||
assert(mem.is_power_of_two(uintptr(page_size)))
|
||||
committed := committed
|
||||
committed = clamp(committed, 0, reserved)
|
||||
|
||||
@@ -82,8 +83,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
pmblock := platform_memory_alloc(0, total_size) or_return
|
||||
|
||||
pmblock.block.base = ([^]byte)(uintptr(pmblock) + base_offset)
|
||||
commit_err := platform_memory_commit(pmblock, uint(base_offset) + committed)
|
||||
assert(commit_err == nil)
|
||||
platform_memory_commit(pmblock, uint(base_offset) + committed) or_return
|
||||
|
||||
// Should be zeroed
|
||||
assert(pmblock.block.used == 0)
|
||||
|
||||
@@ -51,6 +51,7 @@ PAGE_TARGETS_INVALID :: 0x40000000
|
||||
PAGE_TARGETS_NO_UPDATE :: 0x40000000
|
||||
|
||||
ERROR_INVALID_ADDRESS :: 487
|
||||
ERROR_COMMITMENT_LIMIT :: 1455
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign Kernel32 {
|
||||
@@ -76,12 +77,13 @@ _commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
result := VirtualAlloc(data, size, MEM_COMMIT, PAGE_READWRITE)
|
||||
if result == nil {
|
||||
switch err := GetLastError(); err {
|
||||
case ERROR_INVALID_ADDRESS:
|
||||
case 0:
|
||||
return .Invalid_Argument
|
||||
case ERROR_INVALID_ADDRESS, ERROR_COMMITMENT_LIMIT:
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
|
||||
// TODO(bill): Handle errors correctly
|
||||
return .Invalid_Argument
|
||||
return .Out_Of_Memory
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ Proc_Tag :: enum {
|
||||
Bounds_Check,
|
||||
No_Bounds_Check,
|
||||
Optional_Ok,
|
||||
Optional_Second,
|
||||
Optional_Allocator_Error,
|
||||
}
|
||||
Proc_Tags :: distinct bit_set[Proc_Tag; u32]
|
||||
|
||||
|
||||
@@ -2062,7 +2062,7 @@ parse_proc_tags :: proc(p: ^Parser) -> (tags: ast.Proc_Tags) {
|
||||
case "bounds_check": tags += {.Bounds_Check}
|
||||
case "no_bounds_check": tags += {.No_Bounds_Check}
|
||||
case "optional_ok": tags += {.Optional_Ok}
|
||||
case "optional_second": tags += {.Optional_Second}
|
||||
case "optional_allocator_error": tags += {.Optional_Allocator_Error}
|
||||
case:
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
|
||||
|
||||
data = make([]byte, int(length), allocator)
|
||||
if data == nil {
|
||||
return nil, false
|
||||
return nil, false
|
||||
}
|
||||
|
||||
bytes_read, read_err := read_full(fd, data)
|
||||
|
||||
@@ -4,7 +4,7 @@ import "core:io"
|
||||
|
||||
to_stream :: proc(f: ^File) -> (s: io.Stream) {
|
||||
s.stream_data = f
|
||||
s.stream_vtable = _file_stream_vtable
|
||||
s.stream_vtable = &_file_stream_vtable
|
||||
return
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ error_to_io_error :: proc(ferr: Error) -> io.Error {
|
||||
|
||||
|
||||
@(private)
|
||||
_file_stream_vtable := &io.Stream_VTable{
|
||||
_file_stream_vtable := io.Stream_VTable{
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
f := (^File)(s.stream_data)
|
||||
ferr: Error
|
||||
|
||||
+30
-12
@@ -369,27 +369,45 @@ close :: proc(fd: Handle) -> bool {
|
||||
return _unix_close(fd) == 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
MAX_RW :: 0x7fffffff // The limit on Darwin is max(i32), trying to read/write more than that fails.
|
||||
|
||||
write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1)
|
||||
|
||||
if len(data) == 0 {
|
||||
return 0, 0
|
||||
bytes_total := len(data)
|
||||
bytes_written_total := 0
|
||||
|
||||
for bytes_written_total < bytes_total {
|
||||
bytes_to_write := min(bytes_total - bytes_written_total, MAX_RW)
|
||||
slice := data[bytes_written_total:bytes_written_total + bytes_to_write]
|
||||
bytes_written := _unix_write(fd, raw_data(slice), bytes_to_write)
|
||||
if bytes_written == -1 {
|
||||
return bytes_written_total, 1
|
||||
}
|
||||
bytes_written_total += bytes_written
|
||||
}
|
||||
bytes_written := _unix_write(fd, raw_data(data), len(data))
|
||||
if bytes_written == -1 {
|
||||
return 0, 1
|
||||
}
|
||||
return bytes_written, 0
|
||||
|
||||
return bytes_written_total, 0
|
||||
}
|
||||
|
||||
read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
|
||||
assert(fd != -1)
|
||||
|
||||
bytes_read := _unix_read(fd, raw_data(data), len(data))
|
||||
if bytes_read == -1 {
|
||||
return 0, 1
|
||||
bytes_total := len(data)
|
||||
bytes_read_total := 0
|
||||
|
||||
for bytes_read_total < bytes_total {
|
||||
bytes_to_read := min(bytes_total - bytes_read_total, MAX_RW)
|
||||
slice := data[bytes_read_total:bytes_read_total + bytes_to_read]
|
||||
bytes_read := _unix_read(fd, raw_data(slice), bytes_to_read)
|
||||
if bytes_read == -1 {
|
||||
return bytes_read_total, 1
|
||||
}
|
||||
bytes_read_total += bytes_read
|
||||
}
|
||||
return bytes_read, 0
|
||||
|
||||
return bytes_read_total, 0
|
||||
}
|
||||
|
||||
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
@@ -596,7 +614,7 @@ absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
return "", Errno(get_last_error())
|
||||
}
|
||||
|
||||
path := strings.clone_from_cstring(cstring(&buf[0]), context.temp_allocator)
|
||||
path := strings.clone_from_cstring(cstring(&buf[0]))
|
||||
return path, ERROR_NONE
|
||||
}
|
||||
|
||||
|
||||
@@ -705,4 +705,4 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
res[i] = string(arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -5,13 +5,13 @@ import "core:io"
|
||||
stream_from_handle :: proc(fd: Handle) -> io.Stream {
|
||||
s: io.Stream
|
||||
s.stream_data = rawptr(uintptr(fd))
|
||||
s.stream_vtable = _file_stream_vtable
|
||||
s.stream_vtable = &_file_stream_vtable
|
||||
return s
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_file_stream_vtable := &io.Stream_VTable{
|
||||
_file_stream_vtable := io.Stream_VTable{
|
||||
impl_read = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
fd := Handle(uintptr(s.stream_data))
|
||||
os_err: Errno
|
||||
|
||||
@@ -2,6 +2,8 @@ package reflect
|
||||
|
||||
import "core:runtime"
|
||||
import "core:intrinsics"
|
||||
import "core:mem"
|
||||
_ :: mem
|
||||
_ :: intrinsics
|
||||
|
||||
Type_Info :: runtime.Type_Info
|
||||
@@ -739,6 +741,15 @@ get_union_variant :: proc(a: any) -> any {
|
||||
return any{a.data, id}
|
||||
}
|
||||
|
||||
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
|
||||
ptr := rawptr(val)
|
||||
tag := get_union_variant_raw_tag(val^)
|
||||
mem.copy(&res, &ptr, size_of(ptr))
|
||||
set_union_variant_raw_tag(res, tag)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
|
||||
set_union_variant_raw_tag :: proc(a: any, tag: i64) {
|
||||
if a == nil { return }
|
||||
|
||||
@@ -394,7 +394,7 @@ Raw_Dynamic_Array :: struct {
|
||||
}
|
||||
|
||||
Raw_Map :: struct {
|
||||
hashes: []int,
|
||||
hashes: []Map_Index,
|
||||
entries: Raw_Dynamic_Array,
|
||||
}
|
||||
|
||||
|
||||
@@ -189,7 +189,7 @@ delete :: proc{
|
||||
// The new built-in procedure allocates memory. The first argument is a type, not a value, and the value
|
||||
// return is a pointer to a newly allocated value of that type using the specified allocator, default is context.allocator
|
||||
@builtin
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_second {
|
||||
new :: proc($T: typeid, allocator := context.allocator, loc := #caller_location) -> (^T, Allocator_Error) #optional_allocator_error {
|
||||
return new_aligned(T, align_of(T), allocator, loc)
|
||||
}
|
||||
new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) {
|
||||
@@ -199,7 +199,7 @@ new_aligned :: proc($T: typeid, alignment: int, allocator := context.allocator,
|
||||
}
|
||||
|
||||
@builtin
|
||||
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_second {
|
||||
new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_location) -> (t: ^T, err: Allocator_Error) #optional_allocator_error {
|
||||
t_data := mem_alloc_bytes(size_of(T), align_of(T), allocator, loc) or_return
|
||||
t = (^T)(raw_data(t_data))
|
||||
if t != nil {
|
||||
@@ -210,7 +210,7 @@ new_clone :: proc(data: $T, allocator := context.allocator, loc := #caller_locat
|
||||
|
||||
DEFAULT_RESERVE_CAPACITY :: 16
|
||||
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
make_slice_error_loc(loc, len)
|
||||
data, err := mem_alloc_bytes(size_of(E)*len, alignment, allocator, loc)
|
||||
if data == nil && size_of(E) != 0 {
|
||||
@@ -221,19 +221,19 @@ make_aligned :: proc($T: typeid/[]$E, #any_int len: int, alignment: int, allocat
|
||||
}
|
||||
|
||||
@(builtin)
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
make_slice :: proc($T: typeid/[]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_aligned(T, len, align_of(E), allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
make_dynamic_array :: proc($T: typeid/[dynamic]$E, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, 0, DEFAULT_RESERVE_CAPACITY, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_second {
|
||||
make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (T, Allocator_Error) #optional_allocator_error {
|
||||
return make_dynamic_array_len_cap(T, len, len, allocator, loc)
|
||||
}
|
||||
@(builtin)
|
||||
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_dynamic_array_error_loc(loc, len, cap)
|
||||
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
|
||||
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
|
||||
@@ -253,7 +253,7 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int cap: int = DEFAULT_RESERVE_CAPAC
|
||||
return m
|
||||
}
|
||||
@(builtin)
|
||||
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_second {
|
||||
make_multi_pointer :: proc($T: typeid/[^]$E, #any_int len: int, allocator := context.allocator, loc := #caller_location) -> (mp: T, err: Allocator_Error) #optional_allocator_error {
|
||||
make_slice_error_loc(loc, len)
|
||||
data := mem_alloc_bytes(size_of(E)*len, align_of(E), allocator, loc) or_return
|
||||
if data == nil && size_of(E) != 0 {
|
||||
@@ -289,14 +289,15 @@ clear_map :: proc "contextless" (m: ^$T/map[$K]$V) {
|
||||
entries := (^Raw_Dynamic_Array)(&raw_map.entries)
|
||||
entries.len = 0
|
||||
for _, i in raw_map.hashes {
|
||||
raw_map.hashes[i] = -1
|
||||
raw_map.hashes[i] = MAP_SENTINEL
|
||||
}
|
||||
}
|
||||
|
||||
@builtin
|
||||
reserve_map :: proc(m: ^$T/map[$K]$V, capacity: int, loc := #caller_location) {
|
||||
if m != nil {
|
||||
__dynamic_map_reserve(__get_map_header(m), capacity, loc)
|
||||
h := __get_map_header_table(T)
|
||||
__dynamic_map_reserve(m, h, uint(capacity), loc)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,9 +326,8 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
if m != nil {
|
||||
key := key
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
fr := __map_find(h, &key)
|
||||
if fr.entry_index != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
deleted_key = (^K)(uintptr(entry)+h.key_offset)^
|
||||
deleted_value = (^V)(uintptr(entry)+h.value_offset)^
|
||||
@@ -335,7 +335,6 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -673,11 +672,10 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
||||
@builtin
|
||||
map_insert :: proc(m: ^$T/map[$K]$V, key: K, value: V, loc := #caller_location) -> (ptr: ^V) {
|
||||
key, value := key, value
|
||||
h := __get_map_header(m)
|
||||
hash := __get_map_hash(&key)
|
||||
|
||||
data := uintptr(__dynamic_map_set(h, hash, &value, loc))
|
||||
return (^V)(data + h.value_offset)
|
||||
h := __get_map_header_table(T)
|
||||
|
||||
e := __dynamic_map_set(m, h, __get_map_key_hash(&key), &key, &value, loc)
|
||||
return (^V)(uintptr(e) + h.value_offset)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ raw_soa_footer :: proc{
|
||||
|
||||
|
||||
@builtin
|
||||
make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
if length <= 0 {
|
||||
return
|
||||
}
|
||||
@@ -138,7 +138,7 @@ make_soa_aligned :: proc($T: typeid/#soa[]$E, length: int, alignment: int, alloc
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_second {
|
||||
make_soa_slice :: proc($T: typeid/#soa[]$E, length: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
|
||||
return make_soa_aligned(T, length, align_of(E), allocator, loc)
|
||||
}
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
|
||||
return
|
||||
}
|
||||
|
||||
new_cap := new_cap
|
||||
new_cap = max(new_cap, 0)
|
||||
old_size := array.cap * elem_size
|
||||
new_size := new_cap * elem_size
|
||||
allocator := array.allocator
|
||||
|
||||
@@ -11,38 +11,34 @@ Map_Hash :: struct {
|
||||
key_ptr: rawptr, // address of Map_Entry_Header.key
|
||||
}
|
||||
|
||||
__get_map_hash :: proc "contextless" (k: ^$K) -> (map_hash: Map_Hash) {
|
||||
__get_map_key_hash :: #force_inline proc "contextless" (k: ^$K) -> uintptr {
|
||||
hasher := intrinsics.type_hasher_proc(K)
|
||||
map_hash.key_ptr = k
|
||||
map_hash.hash = hasher(k, 0)
|
||||
return
|
||||
return hasher(k, 0)
|
||||
}
|
||||
|
||||
__get_map_hash_from_entry :: proc "contextless" (h: Map_Header, entry: ^Map_Entry_Header) -> (hash: Map_Hash) {
|
||||
hash.hash = entry.hash
|
||||
hash.key_ptr = rawptr(uintptr(entry) + h.key_offset)
|
||||
return
|
||||
__get_map_entry_key_ptr :: #force_inline proc "contextless" (h: Map_Header_Table, entry: ^Map_Entry_Header) -> rawptr {
|
||||
return rawptr(uintptr(entry) + h.key_offset)
|
||||
}
|
||||
|
||||
|
||||
Map_Index :: distinct uint
|
||||
MAP_SENTINEL :: ~Map_Index(0)
|
||||
|
||||
Map_Find_Result :: struct {
|
||||
hash_index: int,
|
||||
entry_prev: int,
|
||||
entry_index: int,
|
||||
hash_index: Map_Index,
|
||||
entry_prev: Map_Index,
|
||||
entry_index: Map_Index,
|
||||
}
|
||||
|
||||
Map_Entry_Header :: struct {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
next: Map_Index,
|
||||
/*
|
||||
key: Key_Value,
|
||||
value: Value_Type,
|
||||
*/
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^Raw_Map,
|
||||
Map_Header_Table :: struct {
|
||||
equal: Equal_Proc,
|
||||
|
||||
entry_size: int,
|
||||
@@ -55,6 +51,102 @@ Map_Header :: struct {
|
||||
value_size: int,
|
||||
}
|
||||
|
||||
Map_Header :: struct {
|
||||
m: ^Raw_Map,
|
||||
using table: Map_Header_Table,
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_get :: proc "contextless" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr) -> rawptr {
|
||||
if m != nil {
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
index := __dynamic_map_find(h, key_hash, key_ptr).entry_index
|
||||
if index != MAP_SENTINEL {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||
return rawptr(data + h.value_offset)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_set :: proc "odin" (m: rawptr, table: Map_Header_Table, key_hash: uintptr, key_ptr: rawptr, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||
add_entry :: proc "odin" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr, loc := #caller_location) -> Map_Index {
|
||||
prev := Map_Index(h.m.entries.len)
|
||||
c := Map_Index(__dynamic_array_append_nothing(&h.m.entries, h.entry_size, h.entry_align, loc))
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1)
|
||||
end.hash = key_hash
|
||||
mem_copy(rawptr(uintptr(end) + h.key_offset), key_ptr, h.key_size)
|
||||
end.next = MAP_SENTINEL
|
||||
}
|
||||
return prev
|
||||
}
|
||||
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
|
||||
index := MAP_SENTINEL
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(m, table, INITIAL_MAP_CAP, loc)
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, key_hash, key_ptr)
|
||||
if fr.entry_index != MAP_SENTINEL {
|
||||
index = fr.entry_index
|
||||
} else {
|
||||
index = add_entry(h, key_hash, key_ptr, loc)
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
entry.next = index
|
||||
} else if fr.hash_index != MAP_SENTINEL {
|
||||
h.m.hashes[fr.hash_index] = index
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(h, index)
|
||||
e.hash = key_hash
|
||||
|
||||
key := rawptr(uintptr(e) + h.key_offset)
|
||||
val := rawptr(uintptr(e) + h.value_offset)
|
||||
|
||||
mem_copy(key, key_ptr, h.key_size)
|
||||
mem_copy(val, value, h.value_size)
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
return __dynamic_map_get_entry(h, index)
|
||||
}
|
||||
|
||||
// USED INTERNALLY BY THE COMPILER
|
||||
__dynamic_map_reserve :: proc "odin" (m: rawptr, table: Map_Header_Table, cap: uint, loc := #caller_location) {
|
||||
h := Map_Header{(^Raw_Map)(m), table}
|
||||
|
||||
c := context
|
||||
if h.m.entries.allocator.procedure != nil {
|
||||
c.allocator = h.m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
cap := cap
|
||||
cap = ceil_to_pow2(cap)
|
||||
|
||||
__dynamic_array_reserve(&h.m.entries, h.entry_size, h.entry_align, int(cap), loc)
|
||||
|
||||
if h.m.entries.len*2 < len(h.m.hashes) {
|
||||
return
|
||||
}
|
||||
if __slice_resize(&h.m.hashes, int(cap*2), h.m.entries.allocator, loc) {
|
||||
__dynamic_map_reset_entries(h, loc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INITIAL_HASH_SEED :: 0xcbf29ce484222325
|
||||
|
||||
_fnv64a :: proc "contextless" (data: []byte, seed: u64 = INITIAL_HASH_SEED) -> u64 {
|
||||
@@ -138,11 +230,22 @@ default_hasher_cstring :: proc "contextless" (data: rawptr, seed: uintptr) -> ui
|
||||
}
|
||||
|
||||
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header := Map_Header{m = (^Raw_Map)(m)}
|
||||
__get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> (header: Map_Header) {
|
||||
header.m = (^Raw_Map)(m)
|
||||
header.table = #force_inline __get_map_header_table(T)
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> (header: Map_Header) {
|
||||
header.m = m
|
||||
header.table = #force_inline __get_map_header_table_runtime(ti)
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_table :: proc "contextless" ($T: typeid/map[$K]$V) -> (header: Map_Header_Table) {
|
||||
Entry :: struct {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
next: Map_Index,
|
||||
key: K,
|
||||
value: V,
|
||||
}
|
||||
@@ -158,18 +261,16 @@ __get_map_header :: proc "contextless" (m: ^$T/map[$K]$V) -> Map_Header {
|
||||
header.value_offset = offset_of(Entry, value)
|
||||
header.value_size = size_of(V)
|
||||
|
||||
return header
|
||||
return
|
||||
}
|
||||
|
||||
__get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map) -> Map_Header {
|
||||
header := Map_Header{m = m}
|
||||
|
||||
__get_map_header_table_runtime :: proc "contextless" (ti: Type_Info_Map) -> (header: Map_Header) {
|
||||
header.equal = ti.key_equal
|
||||
|
||||
|
||||
entries := ti.generated_struct.variant.(Type_Info_Struct).types[1]
|
||||
entry := entries.variant.(Type_Info_Dynamic_Array).elem
|
||||
e := entry.variant.(Type_Info_Struct)
|
||||
|
||||
|
||||
header.entry_size = entry.size
|
||||
header.entry_align = entry.align
|
||||
|
||||
@@ -179,11 +280,12 @@ __get_map_header_runtime :: proc "contextless" (m: ^Raw_Map, ti: Type_Info_Map)
|
||||
header.value_offset = e.offsets[3]
|
||||
header.value_size = e.types[3].size
|
||||
|
||||
return header
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
__slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||
|
||||
__slice_resize :: proc "odin" (array_: ^$T/[]$E, new_count: int, allocator: Allocator, loc := #caller_location) -> bool {
|
||||
array := (^Raw_Slice)(array_)
|
||||
|
||||
if new_count < array.len {
|
||||
@@ -205,136 +307,82 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
|
||||
return false
|
||||
}
|
||||
|
||||
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
|
||||
for i in 0..<len(m.hashes) {
|
||||
m.hashes[i] = -1
|
||||
__dynamic_map_reset_entries :: proc "contextless" (h: Map_Header, loc := #caller_location) {
|
||||
for i in 0..<len(h.m.hashes) {
|
||||
h.m.hashes[i] = MAP_SENTINEL
|
||||
}
|
||||
|
||||
for i in 0..<m.entries.len {
|
||||
entry_header := __dynamic_map_get_entry(header, i)
|
||||
entry_hash := __get_map_hash_from_entry(header, entry_header)
|
||||
entry_header.next = -1
|
||||
|
||||
fr := __dynamic_map_find(header, entry_hash)
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = i
|
||||
} else {
|
||||
e := __dynamic_map_get_entry(header, fr.entry_prev)
|
||||
for i in 0..<Map_Index(h.m.entries.len) {
|
||||
entry_header := __dynamic_map_get_entry(h, i)
|
||||
entry_header.next = MAP_SENTINEL
|
||||
|
||||
fr := __dynamic_map_find_from_entry(h, entry_header)
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
e := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
e.next = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_reserve :: proc(using header: Map_Header, cap: int, loc := #caller_location) {
|
||||
c := context
|
||||
if m.entries.allocator.procedure != nil {
|
||||
c.allocator = m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
__dynamic_array_reserve(&m.entries, entry_size, entry_align, cap, loc)
|
||||
|
||||
if m.entries.len*2 < len(m.hashes) {
|
||||
return
|
||||
}
|
||||
if __slice_resize(&m.hashes, cap*2, m.entries.allocator, loc) {
|
||||
__dynamic_map_reset_entries(header, loc)
|
||||
}
|
||||
}
|
||||
|
||||
__dynamic_map_shrink :: proc(using header: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
||||
c := context
|
||||
if m.entries.allocator.procedure != nil {
|
||||
c.allocator = m.entries.allocator
|
||||
}
|
||||
context = c
|
||||
|
||||
return __dynamic_array_shrink(&m.entries, entry_size, entry_align, cap, loc)
|
||||
}
|
||||
|
||||
__dynamic_map_rehash :: proc(using header: Map_Header, new_count: int, loc := #caller_location) {
|
||||
#force_inline __dynamic_map_reserve(header, new_count, loc)
|
||||
}
|
||||
|
||||
__dynamic_map_get :: proc(h: Map_Header, hash: Map_Hash) -> rawptr {
|
||||
index := __dynamic_map_find(h, hash).entry_index
|
||||
if index >= 0 {
|
||||
data := uintptr(__dynamic_map_get_entry(h, index))
|
||||
return rawptr(data + h.value_offset)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
__dynamic_map_set :: proc(h: Map_Header, hash: Map_Hash, value: rawptr, loc := #caller_location) -> ^Map_Entry_Header #no_bounds_check {
|
||||
index: int
|
||||
// assert(value != nil)
|
||||
|
||||
if len(h.m.hashes) == 0 {
|
||||
__dynamic_map_reserve(h, INITIAL_MAP_CAP, loc)
|
||||
__dynamic_map_grow(h, loc)
|
||||
}
|
||||
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
index = fr.entry_index
|
||||
} else {
|
||||
index = __dynamic_map_add_entry(h, hash, loc)
|
||||
if fr.entry_prev >= 0 {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
entry.next = index
|
||||
} else if fr.hash_index >= 0 {
|
||||
h.m.hashes[fr.hash_index] = index
|
||||
} else {
|
||||
return nil
|
||||
h.m.hashes[fr.hash_index] = i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
e := __dynamic_map_get_entry(h, index)
|
||||
e.hash = hash.hash
|
||||
|
||||
key := rawptr(uintptr(e) + h.key_offset)
|
||||
mem_copy(key, hash.key_ptr, h.key_size)
|
||||
|
||||
val := rawptr(uintptr(e) + h.value_offset)
|
||||
mem_copy(val, value, h.value_size)
|
||||
|
||||
if __dynamic_map_full(h) {
|
||||
__dynamic_map_grow(h, loc)
|
||||
// index = __dynamic_map_find(h, hash).entry_index
|
||||
// assert(index >= 0)
|
||||
__dynamic_map_shrink :: proc "odin" (h: Map_Header, cap: int, loc := #caller_location) -> (did_shrink: bool) {
|
||||
c := context
|
||||
if h.m.entries.allocator.procedure != nil {
|
||||
c.allocator = h.m.entries.allocator
|
||||
}
|
||||
|
||||
return __dynamic_map_get_entry(h, index)
|
||||
context = c
|
||||
|
||||
return __dynamic_array_shrink(&h.m.entries, h.entry_size, h.entry_align, cap, loc)
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_grow :: proc(using h: Map_Header, loc := #caller_location) {
|
||||
// TODO(bill): Determine an efficient growing rate
|
||||
new_count := max(4*m.entries.cap + 7, INITIAL_MAP_CAP)
|
||||
__dynamic_map_rehash(h, new_count, loc)
|
||||
@(private="file")
|
||||
ceil_to_pow2 :: proc "contextless" (n: uint) -> uint {
|
||||
if n <= 2 {
|
||||
return n
|
||||
}
|
||||
n := n
|
||||
n -= 1
|
||||
n |= n >> 1
|
||||
n |= n >> 2
|
||||
n |= n >> 4
|
||||
n |= n >> 8
|
||||
n |= n >> 16
|
||||
when size_of(int) == 8 {
|
||||
n |= n >> 32
|
||||
}
|
||||
n += 1
|
||||
return n
|
||||
}
|
||||
|
||||
__dynamic_map_full :: #force_inline proc "contextless" (using h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(m.hashes))) <= m.entries.len
|
||||
__dynamic_map_grow :: proc "odin" (h: Map_Header, loc := #caller_location) {
|
||||
new_count := max(uint(h.m.entries.cap) * 2, INITIAL_MAP_CAP)
|
||||
// Rehash through Reserve
|
||||
__dynamic_map_reserve(h.m, h.table, new_count, loc)
|
||||
}
|
||||
|
||||
|
||||
__dynamic_map_hash_equal :: proc "contextless" (h: Map_Header, a, b: Map_Hash) -> bool {
|
||||
return a.hash == b.hash && h.equal(a.key_ptr, b.key_ptr)
|
||||
__dynamic_map_full :: #force_inline proc "contextless" (h: Map_Header) -> bool {
|
||||
return int(0.75 * f64(len(h.m.hashes))) <= h.m.entries.len
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{-1, -1, -1}
|
||||
if n := uintptr(len(m.hashes)); n > 0 {
|
||||
fr.hash_index = int(hash.hash % n)
|
||||
fr.entry_index = m.hashes[fr.hash_index]
|
||||
for fr.entry_index >= 0 {
|
||||
__dynamic_map_find_from_entry :: proc "contextless" (h: Map_Header, e: ^Map_Entry_Header) -> Map_Find_Result #no_bounds_check {
|
||||
key_ptr := __get_map_entry_key_ptr(h, e)
|
||||
return __dynamic_map_find(h, e.hash, key_ptr)
|
||||
|
||||
}
|
||||
|
||||
__dynamic_map_find :: proc "contextless" (h: Map_Header, key_hash: uintptr, key_ptr: rawptr) -> Map_Find_Result #no_bounds_check {
|
||||
fr := Map_Find_Result{MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL}
|
||||
if n := uintptr(len(h.m.hashes)); n != 0 {
|
||||
fr.hash_index = Map_Index(key_hash & (n-1))
|
||||
fr.entry_index = h.m.hashes[fr.hash_index]
|
||||
for fr.entry_index != MAP_SENTINEL {
|
||||
entry := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
entry_hash := __get_map_hash_from_entry(h, entry)
|
||||
if __dynamic_map_hash_equal(h, entry_hash, hash) {
|
||||
entry_key_ptr := __get_map_entry_key_ptr(h, entry)
|
||||
if entry.hash == key_hash && h.equal(entry_key_ptr, key_ptr) {
|
||||
return fr
|
||||
}
|
||||
// assert(entry.next < m.entries.len)
|
||||
|
||||
fr.entry_prev = fr.entry_index
|
||||
fr.entry_index = entry.next
|
||||
@@ -343,58 +391,38 @@ __dynamic_map_find :: proc(using h: Map_Header, hash: Map_Hash) -> Map_Find_Resu
|
||||
return fr
|
||||
}
|
||||
|
||||
__dynamic_map_add_entry :: proc(using h: Map_Header, hash: Map_Hash, loc := #caller_location) -> int {
|
||||
prev := m.entries.len
|
||||
c := __dynamic_array_append_nothing(&m.entries, entry_size, entry_align, loc)
|
||||
if c != prev {
|
||||
end := __dynamic_map_get_entry(h, c-1)
|
||||
end.hash = hash.hash
|
||||
mem_copy(rawptr(uintptr(end) + key_offset), hash.key_ptr, key_size)
|
||||
end.next = -1
|
||||
}
|
||||
return prev
|
||||
// Utility procedure used by other runtime procedures
|
||||
__map_find :: proc "contextless" (h: Map_Header, key_ptr: ^$K) -> Map_Find_Result #no_bounds_check {
|
||||
hash := __get_map_key_hash(key_ptr)
|
||||
return #force_inline __dynamic_map_find(h, hash, key_ptr)
|
||||
}
|
||||
|
||||
__dynamic_map_delete_key :: proc(using h: Map_Header, hash: Map_Hash) {
|
||||
fr := __dynamic_map_find(h, hash)
|
||||
if fr.entry_index >= 0 {
|
||||
__dynamic_map_erase(h, fr)
|
||||
}
|
||||
__dynamic_map_get_entry :: #force_inline proc "contextless" (h: Map_Header, index: Map_Index) -> ^Map_Entry_Header {
|
||||
return (^Map_Entry_Header)(uintptr(h.m.entries.data) + uintptr(index*Map_Index(h.entry_size)))
|
||||
}
|
||||
|
||||
__dynamic_map_get_entry :: proc(using h: Map_Header, index: int) -> ^Map_Entry_Header {
|
||||
// assert(0 <= index && index < m.entries.len)
|
||||
return (^Map_Entry_Header)(uintptr(m.entries.data) + uintptr(index*entry_size))
|
||||
}
|
||||
|
||||
__dynamic_map_copy_entry :: proc(h: Map_Header, new, old: ^Map_Entry_Header) {
|
||||
mem_copy(new, old, h.entry_size)
|
||||
}
|
||||
|
||||
__dynamic_map_erase :: proc(using h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev < 0 {
|
||||
m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||
} else {
|
||||
__dynamic_map_erase :: proc "contextless" (h: Map_Header, fr: Map_Find_Result) #no_bounds_check {
|
||||
if fr.entry_prev != MAP_SENTINEL {
|
||||
prev := __dynamic_map_get_entry(h, fr.entry_prev)
|
||||
curr := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
prev.next = curr.next
|
||||
}
|
||||
if fr.entry_index == m.entries.len-1 {
|
||||
// NOTE(bill): No need to do anything else, just pop
|
||||
} else {
|
||||
h.m.hashes[fr.hash_index] = __dynamic_map_get_entry(h, fr.entry_index).next
|
||||
}
|
||||
last_index := Map_Index(h.m.entries.len-1)
|
||||
if fr.entry_index != last_index {
|
||||
old := __dynamic_map_get_entry(h, fr.entry_index)
|
||||
end := __dynamic_map_get_entry(h, m.entries.len-1)
|
||||
__dynamic_map_copy_entry(h, old, end)
|
||||
end := __dynamic_map_get_entry(h, last_index)
|
||||
mem_copy(old, end, h.entry_size)
|
||||
|
||||
old_hash := __get_map_hash_from_entry(h, old)
|
||||
|
||||
if last := __dynamic_map_find(h, old_hash); last.entry_prev >= 0 {
|
||||
last_entry := __dynamic_map_get_entry(h, last.entry_prev)
|
||||
last_entry.next = fr.entry_index
|
||||
last := __dynamic_map_find_from_entry(h, old)
|
||||
if last.entry_prev != MAP_SENTINEL {
|
||||
e := __dynamic_map_get_entry(h, last.entry_prev)
|
||||
e.next = fr.entry_index
|
||||
} else {
|
||||
m.hashes[last.hash_index] = fr.entry_index
|
||||
h.m.hashes[last.hash_index] = fr.entry_index
|
||||
}
|
||||
}
|
||||
|
||||
m.entries.len -= 1
|
||||
h.m.entries.len -= 1
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ type_assertion_trap :: proc "contextless" () -> ! {
|
||||
|
||||
|
||||
bounds_check_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||
if 0 <= index && index < count {
|
||||
if uint(index) < uint(count) {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
@@ -99,8 +99,8 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
||||
|
||||
|
||||
matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||
if 0 <= row_index && row_index < row_count &&
|
||||
0 <= column_index && column_index < column_count {
|
||||
if uint(row_index) < uint(row_count) &&
|
||||
uint(column_index) < uint(column_count) {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
|
||||
+9
-7
@@ -4,10 +4,10 @@ import "core:builtin"
|
||||
import "core:mem"
|
||||
|
||||
ptr_add :: proc(p: $P/^$T, x: int) -> ^T {
|
||||
return (^T)(uintptr(p) + size_of(T)*x)
|
||||
return ([^]T)(p)[x:]
|
||||
}
|
||||
ptr_sub :: proc(p: $P/^$T, x: int) -> ^T {
|
||||
return #force_inline ptr_add(p, -x)
|
||||
return ([^]T)(p)[-x:]
|
||||
}
|
||||
|
||||
ptr_swap_non_overlapping :: proc(x, y: rawptr, len: int) {
|
||||
@@ -84,12 +84,14 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
||||
mid = ptr_add(mid, left)
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
||||
mid = ptr_add(mid, left)
|
||||
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,14 +321,14 @@ last_ptr :: proc(array: $T/[]$E) -> ^E {
|
||||
}
|
||||
|
||||
get :: proc(array: $T/[]$E, index: int) -> (value: E, ok: bool) {
|
||||
if 0 <= index && index < len(array) {
|
||||
if uint(index) < len(array) {
|
||||
value = array[index]
|
||||
ok = true
|
||||
}
|
||||
return
|
||||
}
|
||||
get_ptr :: proc(array: $T/[]$E, index: int) -> (value: ^E, ok: bool) {
|
||||
if 0 <= index && index < len(array) {
|
||||
if uint(index) < len(array) {
|
||||
value = &array[index]
|
||||
ok = true
|
||||
}
|
||||
@@ -509,3 +509,10 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
|
||||
}
|
||||
return r, true
|
||||
}
|
||||
|
||||
|
||||
// Convert a pointer to an enumerated array to a slice of the element type
|
||||
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
|
||||
where intrinsics.type_is_enumerated_array(T) {
|
||||
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
|
||||
}
|
||||
@@ -43,7 +43,7 @@ sort_by_indices :: proc{ sort_by_indices_allocate, _sort_by_indices}
|
||||
|
||||
sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) {
|
||||
assert(len(data) == len(indices))
|
||||
sorted = make([]int, len(data), allocator)
|
||||
sorted = make(T, len(data), allocator)
|
||||
for v, i in indices {
|
||||
sorted[i] = data[v]
|
||||
}
|
||||
|
||||
@@ -567,7 +567,7 @@ parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
|
||||
// ```
|
||||
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
s := str
|
||||
defer if n != nil { n^ = len(str)-len(s) }
|
||||
defer if n != nil { n^ = len(str) - len(s) }
|
||||
if s == "" {
|
||||
return
|
||||
}
|
||||
@@ -588,6 +588,38 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
|
||||
v := _digit_value(r)
|
||||
if v >= 10 {
|
||||
if r == '.' || r == 'e' || r == 'E' { // Skip parsing NaN and Inf if it's probably a regular float
|
||||
break
|
||||
}
|
||||
if len(s) >= 3 + i {
|
||||
buf: [4]u8
|
||||
copy(buf[:], s[i:][:3])
|
||||
|
||||
v2 := transmute(u32)buf
|
||||
v2 &= 0xDFDFDFDF // Knock out lower-case bits
|
||||
|
||||
buf = transmute([4]u8)v2
|
||||
|
||||
when ODIN_ENDIAN == .Little {
|
||||
if v2 == 0x464e49 { // "INF"
|
||||
s = s[3+i:]
|
||||
value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
||||
return value, len(s) == 0
|
||||
} else if v2 == 0x4e414e { // "NAN"
|
||||
s = s[3+i:]
|
||||
return 0h7ff80000_00000001, len(s) == 0
|
||||
}
|
||||
} else {
|
||||
if v2 == 0x494e4600 { // "\0FNI"
|
||||
s = s[3+i:]
|
||||
value = 0h7ff00000_00000000 if sign == 1 else 0hfff00000_00000000
|
||||
return value, len(s) == 0
|
||||
} else if v2 == 0x4e414e00 { // "\0NAN"
|
||||
s = s[3+i:]
|
||||
return 0h7ff80000_00000001, len(s) == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
value *= 10
|
||||
|
||||
@@ -67,7 +67,7 @@ builder_init :: proc{
|
||||
}
|
||||
|
||||
@(private)
|
||||
_builder_stream_vtable := &io.Stream_VTable{
|
||||
_builder_stream_vtable := io.Stream_VTable{
|
||||
impl_write = proc(s: io.Stream, p: []byte) -> (n: int, err: io.Error) {
|
||||
b := (^Builder)(s.stream_data)
|
||||
n = write_bytes(b, p)
|
||||
@@ -97,7 +97,7 @@ _builder_stream_vtable := &io.Stream_VTable{
|
||||
|
||||
// return an `io.Stream` from a builder
|
||||
to_stream :: proc(b: ^Builder) -> io.Stream {
|
||||
return io.Stream{stream_vtable=_builder_stream_vtable, stream_data=b}
|
||||
return io.Stream{stream_vtable=&_builder_stream_vtable, stream_data=b}
|
||||
}
|
||||
|
||||
// return an `io.Writer` from a builder
|
||||
|
||||
@@ -24,7 +24,7 @@ reader_init :: proc(r: ^Reader, s: string) {
|
||||
// returns a stream from the reader data
|
||||
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
|
||||
s.stream_data = r
|
||||
s.stream_vtable = _reader_vtable
|
||||
s.stream_vtable = &_reader_vtable
|
||||
return
|
||||
}
|
||||
|
||||
@@ -42,20 +42,6 @@ to_reader_at :: proc(r: ^Reader, s: string) -> io.Reader_At {
|
||||
return rr
|
||||
}
|
||||
|
||||
// init a reader to the string `s` and return an io.Byte_Reader
|
||||
to_byte_reader :: proc(r: ^Reader, s: string) -> io.Byte_Reader {
|
||||
reader_init(r, s)
|
||||
rr, _ := io.to_byte_reader(reader_to_stream(r))
|
||||
return rr
|
||||
}
|
||||
|
||||
// init a reader to the string `s` and return an io.Rune_Reader
|
||||
to_rune_reader :: proc(r: ^Reader, s: string) -> io.Rune_Reader {
|
||||
reader_init(r, s)
|
||||
rr, _ := io.to_rune_reader(reader_to_stream(r))
|
||||
return rr
|
||||
}
|
||||
|
||||
// remaining length of the reader
|
||||
reader_length :: proc(r: ^Reader) -> int {
|
||||
if r.i >= i64(len(r.s)) {
|
||||
@@ -191,7 +177,7 @@ reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_reader_vtable := &io.Stream_VTable{
|
||||
_reader_vtable := io.Stream_VTable{
|
||||
impl_size = proc(s: io.Stream) -> i64 {
|
||||
r := (^Reader)(s.stream_data)
|
||||
return reader_size(r)
|
||||
|
||||
+12
-12
@@ -760,7 +760,7 @@ last_index_byte :: proc(s: string, c: byte) -> int {
|
||||
*/
|
||||
index_rune :: proc(s: string, r: rune) -> int {
|
||||
switch {
|
||||
case 0 <= r && r < utf8.RUNE_SELF:
|
||||
case u32(r) < utf8.RUNE_SELF:
|
||||
return index_byte(s, byte(r))
|
||||
|
||||
case r == utf8.RUNE_ERROR:
|
||||
@@ -937,14 +937,14 @@ index_any :: proc(s, chars: string) -> int {
|
||||
}
|
||||
|
||||
/*
|
||||
returns the index of any first char of `chars` found in `s`, -1 if not found
|
||||
returns the last matching index in `s` of any char in `chars` found in `s`, -1 if not found
|
||||
iterates the string in reverse
|
||||
|
||||
strings.index_any("test", "s") -> 2
|
||||
strings.index_any("test", "se") -> 2
|
||||
strings.index_any("test", "et") -> 1
|
||||
strings.index_any("test", "set") -> 3
|
||||
strings.index_any("test", "x") -> -1
|
||||
strings.last_index_any("test", "s") -> 2
|
||||
strings.last_index_any("test", "se") -> 2
|
||||
strings.last_index_any("test", "et") -> 3
|
||||
strings.last_index_any("test", "set") -> 3
|
||||
strings.last_index_any("test", "x") -> -1
|
||||
*/
|
||||
last_index_any :: proc(s, chars: string) -> int {
|
||||
if chars == "" {
|
||||
@@ -1686,7 +1686,7 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
@@ -1702,14 +1702,14 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
|
||||
return to_string(b)
|
||||
}
|
||||
|
||||
// left_justify returns a string with a pad string at left side if the str's rune length is smaller than length
|
||||
// left_justify returns a string with a pad string at right side if the str's rune length is smaller than length
|
||||
left_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str)
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
@@ -1724,14 +1724,14 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
|
||||
return to_string(b)
|
||||
}
|
||||
|
||||
// right_justify returns a string with a pad string at right side if the str's rune length is smaller than length
|
||||
// right_justify returns a string with a pad string at left side if the str's rune length is smaller than length
|
||||
right_justify :: proc(str: string, length: int, pad: string, allocator := context.allocator) -> string {
|
||||
n := rune_count(str)
|
||||
if n >= length || pad == "" {
|
||||
return clone(str, allocator)
|
||||
}
|
||||
|
||||
remains := length-1
|
||||
remains := length-n
|
||||
pad_len := rune_count(pad)
|
||||
|
||||
b: Builder
|
||||
|
||||
@@ -8,8 +8,9 @@ import "core:time"
|
||||
foreign import System "System.framework"
|
||||
|
||||
foreign System {
|
||||
// __ulock_wait is not available on 10.15
|
||||
// See https://github.com/odin-lang/Odin/issues/1959
|
||||
__ulock_wait :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_us: u32) -> c.int ---
|
||||
__ulock_wait2 :: proc "c" (operation: u32, addr: rawptr, value: u64, timeout_ns: u64, value2: u64) -> c.int ---
|
||||
__ulock_wake :: proc "c" (operation: u32, addr: rawptr, wake_value: u64) -> c.int ---
|
||||
}
|
||||
|
||||
@@ -28,9 +29,9 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
timeout_ns := u64(duration)
|
||||
timeout_ns := u32(duration) * 1000
|
||||
|
||||
s := __ulock_wait2(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns, 0)
|
||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
||||
if s >= 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package darwin
|
||||
|
||||
import "core:strings"
|
||||
import "core:c"
|
||||
import "core:runtime"
|
||||
|
||||
// this package uses the sys prefix for the proc names to indicate that these aren't native syscalls but directly call such
|
||||
sys_write_string :: proc (fd: c.int, message: string) -> bool {
|
||||
return syscall_write(fd, strings.ptr_from_string(message), cast(u64)len(message))
|
||||
return syscall_write(fd, raw_data(message), cast(u64)len(message))
|
||||
}
|
||||
|
||||
Offset_From :: enum c.int {
|
||||
@@ -87,11 +87,20 @@ _sys_permission_mode :: #force_inline proc (mode: Permission) -> u32 {
|
||||
return cflags
|
||||
}
|
||||
|
||||
@(private)
|
||||
clone_to_cstring :: proc(s: string, allocator: runtime.Allocator, loc := #caller_location) -> cstring {
|
||||
c := make([]byte, len(s)+1, allocator, loc)
|
||||
copy(c, s)
|
||||
c[len(s)] = 0
|
||||
return cstring(&c[0])
|
||||
}
|
||||
|
||||
|
||||
sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, bool) {
|
||||
|
||||
cmode: u32 = 0
|
||||
cflags: u32 = 0
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
cflags = _sys_permission_mode(mode)
|
||||
|
||||
@@ -123,32 +132,32 @@ sys_open :: proc(path: string, oflag: Open_Flags, mode: Permission) -> (c.int, b
|
||||
}
|
||||
|
||||
sys_mkdir :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_mkdir_at :: proc(fd: c.int, path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_mkdir_at(fd, cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rmdir :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cflags := _sys_permission_mode(mode)
|
||||
return syscall_rmdir(cpath, cflags) != -1
|
||||
}
|
||||
|
||||
sys_rename :: proc(path: string, new_path: string) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename(cpath, cnpath) != -1
|
||||
}
|
||||
|
||||
sys_rename_at :: proc(fd: c.int, path: string, to_fd: c.int, new_path: string) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cnpath: cstring = clone_to_cstring(new_path, context.temp_allocator)
|
||||
return syscall_rename_at(fd, cpath, to_fd, cnpath) != -1
|
||||
}
|
||||
|
||||
@@ -157,12 +166,12 @@ sys_lseek :: proc(fd: c.int, offset: i64, whence: Offset_From) -> i64 {
|
||||
}
|
||||
|
||||
sys_chmod :: proc(path: string, mode: Permission) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
cmode := _sys_permission_mode(mode)
|
||||
return syscall_chmod(cpath, cmode) != -1
|
||||
}
|
||||
|
||||
sys_lstat :: proc(path: string, status: ^stat) -> bool {
|
||||
cpath: cstring = strings.clone_to_cstring(path, context.temp_allocator)
|
||||
cpath: cstring = clone_to_cstring(path, context.temp_allocator)
|
||||
return syscall_lstat(cpath, status) != -1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
//+build arm32, arm64
|
||||
package sysinfo
|
||||
|
||||
// TODO: Set up an enum with the ARM equivalent of the above.
|
||||
CPU_Feature :: enum u64 {}
|
||||
|
||||
cpu_features: Maybe(CPU_Feature)
|
||||
cpu_name: Maybe(string)
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
}
|
||||
|
||||
@(private)
|
||||
_cpu_name_buf: [72]u8
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc "c" () {
|
||||
when ODIN_ARCH == .arm32 {
|
||||
copy(_cpu_name_buf[:], "ARM")
|
||||
cpu_name = string(_cpu_name_buf[:3])
|
||||
} else {
|
||||
copy(_cpu_name_buf[:], "ARM64")
|
||||
cpu_name = string(_cpu_name_buf[:5])
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//+build i386, amd64
|
||||
package simd_x86
|
||||
package sysinfo
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
@@ -9,7 +9,6 @@ cpuid :: intrinsics.x86_cpuid
|
||||
// xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
|
||||
xgetbv :: intrinsics.x86_xgetbv
|
||||
|
||||
|
||||
CPU_Feature :: enum u64 {
|
||||
aes, // AES hardware implementation (AES NI)
|
||||
adx, // Multi-precision add-carry instruction extensions
|
||||
@@ -34,6 +33,7 @@ CPU_Feature :: enum u64 {
|
||||
CPU_Features :: distinct bit_set[CPU_Feature; u64]
|
||||
|
||||
cpu_features: Maybe(CPU_Features)
|
||||
cpu_name: Maybe(string)
|
||||
|
||||
@(init, private)
|
||||
init_cpu_features :: proc "c" () {
|
||||
@@ -67,6 +67,13 @@ init_cpu_features :: proc "c" () {
|
||||
try_set(&set, .os_xsave, 27, ecx1)
|
||||
try_set(&set, .rdrand, 30, ecx1)
|
||||
|
||||
when ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
|
||||
// xgetbv is an illegal instruction under FreeBSD 13 & OpenBSD 7.1
|
||||
// return before probing further
|
||||
cpu_features = set
|
||||
return
|
||||
}
|
||||
|
||||
os_supports_avx := false
|
||||
if .os_xsave in set {
|
||||
eax, _ := xgetbv(0)
|
||||
@@ -92,3 +99,31 @@ init_cpu_features :: proc "c" () {
|
||||
|
||||
cpu_features = set
|
||||
}
|
||||
|
||||
@(private)
|
||||
_cpu_name_buf: [72]u8
|
||||
|
||||
@(init, private)
|
||||
init_cpu_name :: proc "c" () {
|
||||
number_of_extended_ids, _, _, _ := cpuid(0x8000_0000, 0)
|
||||
if number_of_extended_ids < 0x8000_0004 {
|
||||
return
|
||||
}
|
||||
|
||||
_buf := transmute(^[0x12]u32)&_cpu_name_buf
|
||||
_buf[ 0], _buf[ 1], _buf[ 2], _buf[ 3] = cpuid(0x8000_0002, 0)
|
||||
_buf[ 4], _buf[ 5], _buf[ 6], _buf[ 7] = cpuid(0x8000_0003, 0)
|
||||
_buf[ 8], _buf[ 9], _buf[10], _buf[11] = cpuid(0x8000_0004, 0)
|
||||
|
||||
// Some CPUs like may include leading or trailing spaces. Trim them.
|
||||
// e.g. ` Intel(R) Xeon(R) CPU E5-1650 v2 @ 3.50GHz`
|
||||
|
||||
brand := string(_cpu_name_buf[:])
|
||||
for len(brand) > 0 && brand[0] == 0 || brand[0] == ' ' {
|
||||
brand = brand[1:]
|
||||
}
|
||||
for len(brand) > 0 && brand[len(brand) - 1] == 0 || brand[len(brand) - 1] == ' ' {
|
||||
brand = brand[:len(brand) - 1]
|
||||
}
|
||||
cpu_name = brand
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
Package `core:sys/info` gathers system information on:
|
||||
Windows, Linux, macOS, FreeBSD & OpenBSD.
|
||||
|
||||
Simply import the package and you'll have access to the OS version, RAM amount
|
||||
and CPU information.
|
||||
|
||||
On Windows, GPUs will also be enumerated using the registry.
|
||||
|
||||
CPU feature flags can be tested against `cpu_features`, where applicable, e.g.
|
||||
`if .aes in si.aes { ... }`
|
||||
*/
|
||||
// +ignore
|
||||
package sysinfo
|
||||
|
||||
import "core:fmt"
|
||||
import si "core:sys/info"
|
||||
|
||||
main :: proc() {
|
||||
fmt.printf("Odin: %v\n", ODIN_VERSION)
|
||||
fmt.printf("OS: %v\n", si.os_version.as_string)
|
||||
fmt.printf("OS: %#v\n", si.os_version)
|
||||
fmt.printf("CPU: %v\n", si.cpu_name)
|
||||
fmt.printf("RAM: %v MiB\n", si.ram.total_ram / 1024 / 1024)
|
||||
|
||||
fmt.println()
|
||||
for gpu, i in si.gpus {
|
||||
fmt.printf("GPU #%v:\n", i)
|
||||
fmt.printf("\tVendor: %v\n", gpu.vendor_name)
|
||||
fmt.printf("\tModel: %v\n", gpu.model_name)
|
||||
fmt.printf("\tVRAM: %v MiB\n", gpu.total_ram / 1024 / 1024)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Example Windows output:
|
||||
Odin: dev-2022-09
|
||||
OS: Windows 10 Professional (version: 20H2), build: 19042.1466
|
||||
OS: OS_Version{
|
||||
platform = "Windows",
|
||||
major = 10,
|
||||
minor = 0,
|
||||
patch = 0,
|
||||
build = [
|
||||
19042,
|
||||
1466,
|
||||
],
|
||||
version = "20H2",
|
||||
as_string = "Windows 10 Professional (version: 20H2), build: 19042.1466",
|
||||
}
|
||||
CPU: AMD Ryzen 7 1800X Eight-Core Processor
|
||||
RAM: 65469 MiB
|
||||
|
||||
GPU #0:
|
||||
Vendor: Advanced Micro Devices, Inc.
|
||||
Model: Radeon RX Vega
|
||||
VRAM: 8176 MiB
|
||||
|
||||
Example macOS output:
|
||||
ODIN: dev-2022-09
|
||||
OS: OS_Version{
|
||||
platform = "MacOS",
|
||||
major = 21,
|
||||
minor = 5,
|
||||
patch = 0,
|
||||
build = [
|
||||
0,
|
||||
0,
|
||||
],
|
||||
version = "21F79",
|
||||
as_string = "macOS Monterey 12.4 (build 21F79, kernel 21.5.0)",
|
||||
}
|
||||
CPU: Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
|
||||
RAM: 8192 MiB
|
||||
*/
|
||||
@@ -0,0 +1,510 @@
|
||||
// +build darwin
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strconv"
|
||||
import "core:strings"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .MacOS
|
||||
|
||||
// Start building display version
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSVERSION}
|
||||
build_buf: [12]u8
|
||||
|
||||
ok := sys.sysctl(mib, &build_buf)
|
||||
if !ok {
|
||||
strings.write_string(&b, "macOS Unknown")
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
}
|
||||
|
||||
build := string(cstring(&build_buf[0]))
|
||||
|
||||
// Do we have an exact match?
|
||||
match: Darwin_Match
|
||||
rel, exact := macos_release_map[build]
|
||||
|
||||
if exact {
|
||||
match = .Exact
|
||||
} else {
|
||||
// Match on XNU kernel version
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
version_bits: [12]u8 // enough for 999.999.999\x00
|
||||
have_kernel_version := sys.sysctl(mib, &version_bits)
|
||||
|
||||
major_ok, minor_ok, patch_ok: bool
|
||||
|
||||
triplet := strings.split(string(cstring(&version_bits[0])), ".", context.temp_allocator)
|
||||
if len(triplet) != 3 {
|
||||
have_kernel_version = false
|
||||
} else {
|
||||
rel.darwin.x, major_ok = strconv.parse_int(triplet[0])
|
||||
rel.darwin.y, minor_ok = strconv.parse_int(triplet[1])
|
||||
rel.darwin.z, patch_ok = strconv.parse_int(triplet[2])
|
||||
|
||||
if !(major_ok && minor_ok && patch_ok) {
|
||||
have_kernel_version = false
|
||||
}
|
||||
}
|
||||
|
||||
if !have_kernel_version {
|
||||
// We don't know the kernel version, but we do know the build
|
||||
strings.write_string(&b, "macOS Unknown (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
strings.write_rune(&b, ')')
|
||||
os_version.as_string = strings.to_string(b)
|
||||
return
|
||||
}
|
||||
rel, match = map_darwin_kernel_version_to_macos_release(build, rel.darwin)
|
||||
}
|
||||
|
||||
os_version.major = rel.darwin.x
|
||||
os_version.minor = rel.darwin.y
|
||||
os_version.patch = rel.darwin.z
|
||||
|
||||
strings.write_string(&b, rel.os_name)
|
||||
if match == .Exact || match == .Nearest {
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_string(&b, rel.release.name)
|
||||
strings.write_rune(&b, ' ')
|
||||
strings.write_int(&b, rel.release.version.x)
|
||||
if rel.release.version.y > 0 || rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.y)
|
||||
}
|
||||
if rel.release.version.z > 0 {
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.release.version.z)
|
||||
}
|
||||
if match == .Nearest {
|
||||
strings.write_rune(&b, '?')
|
||||
}
|
||||
} else {
|
||||
strings.write_string(&b, " Unknown")
|
||||
}
|
||||
|
||||
strings.write_string(&b, " (build ")
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, build)
|
||||
os_version.version = strings.to_string(b)[l:]
|
||||
|
||||
strings.write_string(&b, ", kernel ")
|
||||
strings.write_int(&b, rel.darwin.x)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.y)
|
||||
strings.write_rune(&b, '.')
|
||||
strings.write_int(&b, rel.darwin.z)
|
||||
strings.write_rune(&b, ')')
|
||||
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
|
||||
mib := []i32{sys.CTL_HW, sys.HW_MEMSIZE}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_To_Release :: struct {
|
||||
darwin: [3]int, // Darwin kernel triplet
|
||||
os_name: string, // OS X, MacOS
|
||||
release: struct {
|
||||
name: string, // Monterey, Mojave, etc.
|
||||
version: [3]int, // 12.4, etc.
|
||||
},
|
||||
}
|
||||
|
||||
// Important: Order from lowest to highest kernel version
|
||||
@(private)
|
||||
macos_release_map: map[string]Darwin_To_Release = {
|
||||
// MacOS Tiger
|
||||
"8A428" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8A432" = {{8, 0, 0}, "macOS", {"Tiger", {10, 4, 0}}},
|
||||
"8B15" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8B17" = {{8, 1, 0}, "macOS", {"Tiger", {10, 4, 1}}},
|
||||
"8C46" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8C47" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E102" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E45" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8E90" = {{8, 2, 0}, "macOS", {"Tiger", {10, 4, 2}}},
|
||||
"8F46" = {{8, 3, 0}, "macOS", {"Tiger", {10, 4, 3}}},
|
||||
"8G32" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8G1165" = {{8, 4, 0}, "macOS", {"Tiger", {10, 4, 4}}},
|
||||
"8H14" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8G1454" = {{8, 5, 0}, "macOS", {"Tiger", {10, 4, 5}}},
|
||||
"8I127" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8I1119" = {{8, 6, 0}, "macOS", {"Tiger", {10, 4, 6}}},
|
||||
"8J135" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8J2135a" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8K1079" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8N5107" = {{8, 7, 0}, "macOS", {"Tiger", {10, 4, 7}}},
|
||||
"8L127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8L2127" = {{8, 8, 0}, "macOS", {"Tiger", {10, 4, 8}}},
|
||||
"8P135" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8P2137" = {{8, 9, 0}, "macOS", {"Tiger", {10, 4, 9}}},
|
||||
"8R218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2218" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8R2232" = {{8, 10, 0}, "macOS", {"Tiger", {10, 4, 10}}},
|
||||
"8S165" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
"8S2167" = {{8, 11, 0}, "macOS", {"Tiger", {10, 4, 11}}},
|
||||
|
||||
// MacOS Leopard
|
||||
"9A581" = {{9, 0, 0}, "macOS", {"Leopard", {10, 5, 0}}},
|
||||
"9B18" = {{9, 1, 0}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9B2117" = {{9, 1, 1}, "macOS", {"Leopard", {10, 5, 1}}},
|
||||
"9C31" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9C7010" = {{9, 2, 0}, "macOS", {"Leopard", {10, 5, 2}}},
|
||||
"9D34" = {{9, 3, 0}, "macOS", {"Leopard", {10, 5, 3}}},
|
||||
"9E17" = {{9, 4, 0}, "macOS", {"Leopard", {10, 5, 4}}},
|
||||
"9F33" = {{9, 5, 0}, "macOS", {"Leopard", {10, 5, 5}}},
|
||||
"9G55" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G66" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9G71" = {{9, 6, 0}, "macOS", {"Leopard", {10, 5, 6}}},
|
||||
"9J61" = {{9, 7, 0}, "macOS", {"Leopard", {10, 5, 7}}},
|
||||
"9L30" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
"9L34" = {{9, 8, 0}, "macOS", {"Leopard", {10, 5, 8}}},
|
||||
|
||||
// MacOS Snow Leopard
|
||||
"10A432" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10A433" = {{10, 0, 0}, "macOS", {"Snow Leopard", {10, 6, 0}}},
|
||||
"10B504" = {{10, 1, 0}, "macOS", {"Snow Leopard", {10, 6, 1}}},
|
||||
"10C540" = {{10, 2, 0}, "macOS", {"Snow Leopard", {10, 6, 2}}},
|
||||
"10D573" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D575" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10D578" = {{10, 3, 0}, "macOS", {"Snow Leopard", {10, 6, 3}}},
|
||||
"10F569" = {{10, 4, 0}, "macOS", {"Snow Leopard", {10, 6, 4}}},
|
||||
"10H574" = {{10, 5, 0}, "macOS", {"Snow Leopard", {10, 6, 5}}},
|
||||
"10J567" = {{10, 6, 0}, "macOS", {"Snow Leopard", {10, 6, 6}}},
|
||||
"10J869" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J3250" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10J4138" = {{10, 7, 0}, "macOS", {"Snow Leopard", {10, 6, 7}}},
|
||||
"10K540" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
"10K549" = {{10, 8, 0}, "macOS", {"Snow Leopard", {10, 6, 8}}},
|
||||
|
||||
// MacOS Lion
|
||||
"11A511" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A511s" = {{11, 0, 0}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2061" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11A2063" = {{11, 0, 2}, "macOS", {"Lion", {10, 7, 0}}},
|
||||
"11B26" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11B2118" = {{11, 1, 0}, "macOS", {"Lion", {10, 7, 1}}},
|
||||
"11C74" = {{11, 2, 0}, "macOS", {"Lion", {10, 7, 2}}},
|
||||
"11D50" = {{11, 3, 0}, "macOS", {"Lion", {10, 7, 3}}},
|
||||
"11E53" = {{11, 4, 0}, "macOS", {"Lion", {10, 7, 4}}},
|
||||
"11G56" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
"11G63" = {{11, 4, 2}, "macOS", {"Lion", {10, 7, 5}}},
|
||||
|
||||
// MacOS Mountain Lion
|
||||
"12A269" = {{12, 0, 0}, "macOS", {"Mountain Lion", {10, 8, 0}}},
|
||||
"12B19" = {{12, 1, 0}, "macOS", {"Mountain Lion", {10, 8, 1}}},
|
||||
"12C54" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C60" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C2034" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12C3104" = {{12, 2, 0}, "macOS", {"Mountain Lion", {10, 8, 2}}},
|
||||
"12D78" = {{12, 3, 0}, "macOS", {"Mountain Lion", {10, 8, 3}}},
|
||||
"12E55" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E3067" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12E4022" = {{12, 4, 0}, "macOS", {"Mountain Lion", {10, 8, 4}}},
|
||||
"12F37" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F45" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2501" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2518" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2542" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
"12F2560" = {{12, 5, 0}, "macOS", {"Mountain Lion", {10, 8, 5}}},
|
||||
|
||||
// MacOS Mavericks
|
||||
"13A603" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 0}}},
|
||||
"13B42" = {{13, 0, 0}, "macOS", {"Mavericks", {10, 9, 1}}},
|
||||
"13C64" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13C1021" = {{13, 1, 0}, "macOS", {"Mavericks", {10, 9, 2}}},
|
||||
"13D65" = {{13, 2, 0}, "macOS", {"Mavericks", {10, 9, 3}}},
|
||||
"13E28" = {{13, 3, 0}, "macOS", {"Mavericks", {10, 9, 4}}},
|
||||
"13F34" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1066" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1077" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1096" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1112" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1134" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1507" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1603" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1712" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1808" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
"13F1911" = {{13, 4, 0}, "macOS", {"Mavericks", {10, 9, 5}}},
|
||||
|
||||
// MacOS Yosemite
|
||||
"14A389" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 0}}},
|
||||
"14B25" = {{14, 0, 0}, "macOS", {"Yosemite", {10, 10, 1}}},
|
||||
"14C109" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1510" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2043" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C1514" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14C2513" = {{14, 1, 0}, "macOS", {"Yosemite", {10, 10, 2}}},
|
||||
"14D131" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14D136" = {{14, 3, 0}, "macOS", {"Yosemite", {10, 10, 3}}},
|
||||
"14E46" = {{14, 4, 0}, "macOS", {"Yosemite", {10, 10, 4}}},
|
||||
"14F27" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1021" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1505" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1509" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1605" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1713" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1808" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1909" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F1912" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2009" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2109" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2315" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2411" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
"14F2511" = {{14, 5, 0}, "macOS", {"Yosemite", {10, 10, 5}}},
|
||||
|
||||
// MacOS El Capitan
|
||||
"15A284" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 0}}},
|
||||
"15B42" = {{15, 0, 0}, "macOS", {"El Capitan", {10, 11, 1}}},
|
||||
"15C50" = {{15, 2, 0}, "macOS", {"El Capitan", {10, 11, 2}}},
|
||||
"15D21" = {{15, 3, 0}, "macOS", {"El Capitan", {10, 11, 3}}},
|
||||
"15E65" = {{15, 4, 0}, "macOS", {"El Capitan", {10, 11, 4}}},
|
||||
"15F34" = {{15, 5, 0}, "macOS", {"El Capitan", {10, 11, 5}}},
|
||||
"15G31" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1004" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1011" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1108" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1212" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1217" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1421" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1510" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G1611" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G17023" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G18013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G19009" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G20015" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G21013" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
"15G22010" = {{15, 6, 0}, "macOS", {"El Capitan", {10, 11, 6}}},
|
||||
|
||||
// MacOS Sierra
|
||||
"16A323" = {{16, 0, 0}, "macOS", {"Sierra", {10, 12, 0}}},
|
||||
"16B2555" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16B2657" = {{16, 1, 0}, "macOS", {"Sierra", {10, 12, 1}}},
|
||||
"16C67" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16C68" = {{16, 3, 0}, "macOS", {"Sierra", {10, 12, 2}}},
|
||||
"16D32" = {{16, 4, 0}, "macOS", {"Sierra", {10, 12, 3}}},
|
||||
"16E195" = {{16, 5, 0}, "macOS", {"Sierra", {10, 12, 4}}},
|
||||
"16F73" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16F2073" = {{16, 6, 0}, "macOS", {"Sierra", {10, 12, 5}}},
|
||||
"16G29" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1036" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1114" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1212" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1314" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1408" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1510" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1618" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1710" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1815" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1917" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G1918" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2016" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2127" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2128" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
"16G2136" = {{16, 7, 0}, "macOS", {"Sierra", {10, 12, 6}}},
|
||||
|
||||
// MacOS High Sierra
|
||||
"17A365" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17A405" = {{17, 0, 0}, "macOS", {"High Sierra", {10, 13, 0}}},
|
||||
"17B48" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1002" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17B1003" = {{17, 2, 0}, "macOS", {"High Sierra", {10, 13, 1}}},
|
||||
"17C88" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C89" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17C2205" = {{17, 3, 0}, "macOS", {"High Sierra", {10, 13, 2}}},
|
||||
"17D47" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2047" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17D2102" = {{17, 4, 0}, "macOS", {"High Sierra", {10, 13, 3}}},
|
||||
"17E199" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17E202" = {{17, 5, 0}, "macOS", {"High Sierra", {10, 13, 4}}},
|
||||
"17F77" = {{17, 6, 0}, "macOS", {"High Sierra", {10, 13, 5}}},
|
||||
"17G65" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2208" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G2307" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G3025" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G4015" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G5019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G6030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G7024" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8029" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8030" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G8037" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G9016" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G10021" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G11023" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G12034" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G13035" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14019" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14033" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
"17G14042" = {{17, 7, 0}, "macOS", {"High Sierra", {10, 13, 6}}},
|
||||
|
||||
// MacOS Mojave
|
||||
"18A391" = {{18, 0, 0}, "macOS", {"Mojave", {10, 14, 0}}},
|
||||
"18B75" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B2107" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18B3094" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 1}}},
|
||||
"18C54" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 2}}},
|
||||
"18D42" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D43" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18D109" = {{18, 2, 0}, "macOS", {"Mojave", {10, 14, 3}}},
|
||||
"18E226" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18E227" = {{18, 5, 0}, "macOS", {"Mojave", {10, 14, 4}}},
|
||||
"18F132" = {{18, 6, 0}, "macOS", {"Mojave", {10, 14, 5}}},
|
||||
"18G84" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G87" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G95" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G103" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G1012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G2022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G3020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G4032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G5033" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6020" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6032" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G6042" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G7016" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8012" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G8022" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9028" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9216" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
"18G9323" = {{18, 7, 0}, "macOS", {"Mojave", {10, 14, 6}}},
|
||||
|
||||
// MacOS Catalina
|
||||
"19A583" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A602" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19A603" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 0}}},
|
||||
"19B88" = {{19, 0, 0}, "macOS", {"Catalina", {10, 15, 1}}},
|
||||
"19C57" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19C58" = {{19, 2, 0}, "macOS", {"Catalina", {10, 15, 2}}},
|
||||
"19D76" = {{19, 3, 0}, "macOS", {"Catalina", {10, 15, 3}}},
|
||||
"19E266" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19E287" = {{19, 4, 0}, "macOS", {"Catalina", {10, 15, 4}}},
|
||||
"19F96" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19F101" = {{19, 5, 0}, "macOS", {"Catalina", {10, 15, 5}}},
|
||||
"19G73" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19G2021" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 6}}},
|
||||
"19H2" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H4" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H15" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H114" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H512" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H524" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1030" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1217" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1323" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1417" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1419" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1519" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1615" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1713" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1715" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1824" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H1922" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
"19H2026" = {{19, 6, 0}, "macOS", {"Catalina", {10, 15, 7}}},
|
||||
|
||||
// MacOS Big Sur
|
||||
"20A2411" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 0}}},
|
||||
"20B29" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20B50" = {{20, 1, 0}, "macOS", {"Big Sur", {11, 0, 1}}},
|
||||
"20C69" = {{20, 2, 0}, "macOS", {"Big Sur", {11, 1, 0}}},
|
||||
"20D64" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 0}}},
|
||||
"20D74" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D75" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 1}}},
|
||||
"20D80" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 2}}},
|
||||
"20D91" = {{20, 3, 0}, "macOS", {"Big Sur", {11, 2, 3}}},
|
||||
"20E232" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 0}}},
|
||||
"20E241" = {{20, 4, 0}, "macOS", {"Big Sur", {11, 3, 1}}},
|
||||
"20F71" = {{20, 5, 0}, "macOS", {"Big Sur", {11, 4, 0}}},
|
||||
"20G71" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 0}}},
|
||||
"20G80" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 1}}},
|
||||
"20G95" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 5, 2}}},
|
||||
"20G165" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 0}}},
|
||||
"20G224" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 1}}},
|
||||
"20G314" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 2}}},
|
||||
"20G415" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 3}}},
|
||||
"20G417" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 4}}},
|
||||
"20G527" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 5}}},
|
||||
"20G624" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 6}}},
|
||||
"20G630" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 7}}},
|
||||
"20G730" = {{20, 6, 0}, "macOS", {"Big Sur", {11, 6, 8}}},
|
||||
|
||||
// MacOS Monterey
|
||||
"21A344" = {{21, 0, 1}, "macOS", {"Monterey", {12, 0, 0}}},
|
||||
"21A559" = {{21, 1, 0}, "macOS", {"Monterey", {12, 0, 1}}},
|
||||
"21C52" = {{21, 2, 0}, "macOS", {"Monterey", {12, 1, 0}}},
|
||||
"21D49" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 0}}},
|
||||
"21D62" = {{21, 3, 0}, "macOS", {"Monterey", {12, 2, 1}}},
|
||||
"21E230" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 0}}},
|
||||
"21E258" = {{21, 4, 0}, "macOS", {"Monterey", {12, 3, 1}}},
|
||||
"21F79" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2081" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21F2092" = {{21, 5, 0}, "macOS", {"Monterey", {12, 4, 0}}},
|
||||
"21G72" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 0}}},
|
||||
"21G83" = {{21, 6, 0}, "macOS", {"Monterey", {12, 5, 1}}},
|
||||
}
|
||||
|
||||
@(private)
|
||||
Darwin_Match :: enum {
|
||||
Unknown,
|
||||
Exact,
|
||||
Nearest,
|
||||
}
|
||||
|
||||
@(private)
|
||||
map_darwin_kernel_version_to_macos_release :: proc(build: string, darwin: [3]int) -> (res: Darwin_To_Release, match: Darwin_Match) {
|
||||
// Find exact release match if possible.
|
||||
if v, v_ok := macos_release_map[build]; v_ok {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
nearest: Darwin_To_Release
|
||||
for _, v in macos_release_map {
|
||||
// Try an exact match on XNU version first.
|
||||
if darwin == v.darwin {
|
||||
return v, .Exact
|
||||
}
|
||||
|
||||
// Major kernel version needs to match exactly,
|
||||
// otherwise the release is considered .Unknown
|
||||
if darwin.x == v.darwin.x {
|
||||
if nearest == {} {
|
||||
nearest = v
|
||||
}
|
||||
if darwin.y >= v.darwin.y && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
if darwin.z >= v.darwin.z && v.darwin != nearest.darwin {
|
||||
nearest = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if nearest == {} {
|
||||
return {darwin, "macOS", {"Unknown", {}}}, .Unknown
|
||||
} else {
|
||||
return nearest, .Nearest
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// +build freebsd
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .FreeBSD
|
||||
|
||||
kernel_version_buf: [129]u8
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
// Retrieve kernel info using `sysctl`, e.g. FreeBSD 13.1-RELEASE-p2 GENERIC
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_VERSION}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
pretty_name := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
pretty_name = strings.trim(pretty_name, "\n")
|
||||
strings.write_string(&b, pretty_name)
|
||||
|
||||
// l := strings.builder_len(b)
|
||||
|
||||
// Retrieve kernel revision using `sysctl`, e.g. 199506
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSREV}
|
||||
revision: int
|
||||
if !sys.sysctl(mib, &revision) {
|
||||
return
|
||||
}
|
||||
os_version.patch = revision
|
||||
|
||||
strings.write_string(&b, ", revision ")
|
||||
strings.write_int(&b, revision)
|
||||
|
||||
// Finalize pretty name.
|
||||
os_version.as_string = strings.to_string(b)
|
||||
|
||||
// Retrieve kernel release using `sysctl`, e.g. 13.1-RELEASE-p2
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
// Parse kernel version
|
||||
release := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
version_bits := strings.split_n(release, "-", 2, context.temp_allocator)
|
||||
if len(version_bits) > 1 {
|
||||
// Parse major, minor from KERN_OSRELEASE
|
||||
triplet := strings.split(version_bits[0], ".", context.temp_allocator)
|
||||
if len(triplet) == 2 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
|
||||
if major_ok && minor_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// +build linux
|
||||
package sysinfo
|
||||
|
||||
import "core:c"
|
||||
import sys "core:sys/unix"
|
||||
import "core:intrinsics"
|
||||
import "core:os"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .Linux
|
||||
|
||||
// Try to parse `/etc/os-release` for `PRETTY_NAME="Ubuntu 20.04.3 LTS`
|
||||
fd, err := os.open("/etc/os-release", os.O_RDONLY, 0)
|
||||
if err != 0 {
|
||||
return
|
||||
}
|
||||
defer os.close(fd)
|
||||
|
||||
os_release_buf: [2048]u8
|
||||
n, read_err := os.read(fd, os_release_buf[:])
|
||||
if read_err != 0 {
|
||||
return
|
||||
}
|
||||
release := string(os_release_buf[:n])
|
||||
|
||||
NEEDLE :: "PRETTY_NAME=\""
|
||||
pretty_start := strings.index(release, NEEDLE)
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
|
||||
if pretty_start > 0 {
|
||||
for r, i in release[pretty_start + len(NEEDLE):] {
|
||||
if r == '"' {
|
||||
strings.write_string(&b, release[pretty_start + len(NEEDLE):][:i])
|
||||
break
|
||||
} else if r == '\r' || r == '\n' {
|
||||
strings.write_string(&b, "Unknown Linux Distro")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NEW_UTS_LEN :: 64
|
||||
UTS_Name :: struct {
|
||||
sys_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
node_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
release: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
version: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
machine: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
domain_name: [NEW_UTS_LEN + 1]u8 `fmt:"s,0"`,
|
||||
}
|
||||
uts: UTS_Name
|
||||
|
||||
// Grab kernel info using `uname()` syscall, https://linux.die.net/man/2/uname
|
||||
if intrinsics.syscall(sys.SYS_uname, uintptr(&uts)) != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
strings.write_string(&b, ", ")
|
||||
strings.write_string(&b, string(cstring(&uts.sys_name[0])))
|
||||
strings.write_rune(&b, ' ')
|
||||
|
||||
l := strings.builder_len(b)
|
||||
strings.write_string(&b, string(cstring(&uts.release[0])))
|
||||
|
||||
// Parse kernel version, as substrings of the version info in `version_string_buf`
|
||||
version_bits := strings.split_n(strings.to_string(b)[l:], "-", 2, context.temp_allocator)
|
||||
if len(version_bits) > 1 {
|
||||
os_version.version = version_bits[1]
|
||||
}
|
||||
|
||||
// Parse major, minor, patch from release info
|
||||
triplet := strings.split(version_bits[0], ".", context.temp_allocator)
|
||||
if len(triplet) == 3 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
patch, patch_ok := strconv.parse_int(triplet[2])
|
||||
|
||||
if major_ok && minor_ok && patch_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
os_version.patch = patch
|
||||
}
|
||||
}
|
||||
|
||||
// Finish the string
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
Sys_Info :: struct {
|
||||
uptime: c.long, // Seconds since boot
|
||||
loads: [3]c.long, // 1, 5, 15 minute load averages
|
||||
totalram: c.ulong, // Total usable main memory size
|
||||
freeram: c.ulong, // Available memory size
|
||||
sharedram: c.ulong, // Amount of shared memory
|
||||
bufferram: c.ulong, // Memory used by buffers
|
||||
totalswap: c.ulong, // Total swap space size
|
||||
freeswap: c.ulong, // Swap space still available
|
||||
procs: c.ushort, // Number of current processes
|
||||
totalhigh: c.ulong, // Total high memory size
|
||||
freehigh: c.ulong, // Available high memory size
|
||||
mem_unit: c.int, // Memory unit size in bytes
|
||||
_padding: [20 - (2 * size_of(c.long)) - size_of(c.int)]u8,
|
||||
}
|
||||
|
||||
get_sysinfo :: proc "c" () -> (res: Sys_Info, ok: bool) {
|
||||
si: Sys_Info
|
||||
err := intrinsics.syscall(sys.SYS_sysinfo, uintptr(rawptr(&si)))
|
||||
if err != 0 {
|
||||
// Unable to retrieve sysinfo
|
||||
return {}, false
|
||||
}
|
||||
return si, true
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysinfo`
|
||||
si, ok := get_sysinfo()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
ram = RAM{
|
||||
total_ram = int(si.totalram) * int(si.mem_unit),
|
||||
free_ram = int(si.freeram) * int(si.mem_unit),
|
||||
total_swap = int(si.totalswap) * int(si.mem_unit),
|
||||
free_swap = int(si.freeswap) * int(si.mem_unit),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// +build openbsd
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/unix"
|
||||
import "core:strings"
|
||||
import "core:strconv"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
os_version.platform = .OpenBSD
|
||||
|
||||
kernel_version_buf: [1024]u8
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
// Retrieve kernel info using `sysctl`, e.g. OpenBSD
|
||||
mib := []i32{sys.CTL_KERN, sys.KERN_OSTYPE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
os_type := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
strings.write_string(&b, os_type)
|
||||
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSRELEASE}
|
||||
if !sys.sysctl(mib, &kernel_version_buf) {
|
||||
return
|
||||
}
|
||||
|
||||
strings.write_rune(&b, ' ')
|
||||
version := string(cstring(raw_data(kernel_version_buf[:])))
|
||||
strings.write_string(&b, version)
|
||||
|
||||
// // Parse kernel version
|
||||
triplet := strings.split(version, ".", context.temp_allocator)
|
||||
if len(triplet) == 2 {
|
||||
major, major_ok := strconv.parse_int(triplet[0])
|
||||
minor, minor_ok := strconv.parse_int(triplet[1])
|
||||
|
||||
if major_ok && minor_ok {
|
||||
os_version.major = major
|
||||
os_version.minor = minor
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve kernel revision using `sysctl`, e.g. 199506
|
||||
mib = []i32{sys.CTL_KERN, sys.KERN_OSREV}
|
||||
revision: int
|
||||
if !sys.sysctl(mib, &revision) {
|
||||
return
|
||||
}
|
||||
os_version.patch = revision
|
||||
strings.write_string(&b, ", build ")
|
||||
strings.write_int(&b, revision)
|
||||
|
||||
// Finalize pretty name.
|
||||
os_version.as_string = strings.to_string(b)
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
// Retrieve RAM info using `sysctl`
|
||||
mib := []i32{sys.CTL_HW, sys.HW_PHYSMEM64}
|
||||
mem_size: u64
|
||||
if sys.sysctl(mib, &mem_size) {
|
||||
ram.total_ram = int(mem_size)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,375 @@
|
||||
// +build windows
|
||||
package sysinfo
|
||||
|
||||
import sys "core:sys/windows"
|
||||
import "core:intrinsics"
|
||||
import "core:strings"
|
||||
import "core:unicode/utf16"
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
@(private)
|
||||
version_string_buf: [1024]u8
|
||||
|
||||
@(init, private)
|
||||
init_os_version :: proc () {
|
||||
/*
|
||||
NOTE(Jeroen):
|
||||
`GetVersionEx` will return 6.2 for Windows 10 unless the program is manifested for Windows 10.
|
||||
`RtlGetVersion` will return the true version.
|
||||
|
||||
Rather than include the WinDDK, we ask the kernel directly.
|
||||
`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion` is for the minor build version (Update Build Release)
|
||||
|
||||
*/
|
||||
os_version.platform = .Windows
|
||||
|
||||
osvi: sys.OSVERSIONINFOEXW
|
||||
osvi.dwOSVersionInfoSize = size_of(osvi)
|
||||
status := sys.RtlGetVersion(&osvi)
|
||||
|
||||
if status != 0 {
|
||||
return
|
||||
}
|
||||
|
||||
product_type: sys.Windows_Product_Type
|
||||
sys.GetProductInfo(
|
||||
osvi.dwMajorVersion, osvi.dwMinorVersion,
|
||||
u32(osvi.wServicePackMajor), u32(osvi.wServicePackMinor),
|
||||
&product_type,
|
||||
)
|
||||
|
||||
os_version.major = int(osvi.dwMajorVersion)
|
||||
os_version.minor = int(osvi.dwMinorVersion)
|
||||
os_version.build[0] = int(osvi.dwBuildNumber)
|
||||
|
||||
b := strings.builder_from_bytes(version_string_buf[:])
|
||||
strings.write_string(&b, "Windows ")
|
||||
|
||||
switch osvi.dwMajorVersion {
|
||||
case 10:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
if osvi.dwBuildNumber < 22000 {
|
||||
strings.write_string(&b, "10 ")
|
||||
} else {
|
||||
strings.write_string(&b, "11 ")
|
||||
}
|
||||
format_windows_product_type(&b, product_type)
|
||||
|
||||
case: // Server or Domain Controller
|
||||
switch osvi.dwBuildNumber {
|
||||
case 14393:
|
||||
strings.write_string(&b, "2016 Server")
|
||||
case 17763:
|
||||
strings.write_string(&b, "2019 Server")
|
||||
case 20348:
|
||||
strings.write_string(&b, "2022 Server")
|
||||
case:
|
||||
strings.write_string(&b, "Unknown Server")
|
||||
}
|
||||
}
|
||||
|
||||
case 6:
|
||||
switch osvi.dwMinorVersion {
|
||||
case 0:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION
|
||||
strings.write_string(&b, "Windows Vista ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2008")
|
||||
}
|
||||
|
||||
case 1:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 7 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2008 R2")
|
||||
}
|
||||
|
||||
case 2:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 8 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2012")
|
||||
}
|
||||
|
||||
case 3:
|
||||
switch osvi.wProductType {
|
||||
case 1: // VER_NT_WORKSTATION:
|
||||
strings.write_string(&b, "Windows 8.1 ")
|
||||
format_windows_product_type(&b, product_type)
|
||||
case 3:
|
||||
strings.write_string(&b, "Windows Server 2012 R2")
|
||||
}
|
||||
}
|
||||
|
||||
case 5:
|
||||
switch osvi.dwMinorVersion {
|
||||
case 0:
|
||||
strings.write_string(&b, "Windows 2000")
|
||||
case 1:
|
||||
strings.write_string(&b, "Windows XP")
|
||||
case 2:
|
||||
strings.write_string(&b, "Windows Server 2003")
|
||||
}
|
||||
}
|
||||
|
||||
// Grab DisplayVersion
|
||||
os_version.version = format_display_version(&b)
|
||||
|
||||
// Grab build number and UBR
|
||||
os_version.build[1] = format_build_number(&b, int(osvi.dwBuildNumber))
|
||||
|
||||
// Finish the string
|
||||
os_version.as_string = strings.to_string(b)
|
||||
|
||||
format_windows_product_type :: proc (b: ^strings.Builder, prod_type: sys.Windows_Product_Type) {
|
||||
#partial switch prod_type {
|
||||
case .ULTIMATE:
|
||||
strings.write_string(b, "Ultimate")
|
||||
|
||||
case .HOME_BASIC:
|
||||
strings.write_string(b, "Home Basic")
|
||||
|
||||
case .HOME_PREMIUM:
|
||||
strings.write_string(b, "Home Premium")
|
||||
|
||||
case .ENTERPRISE:
|
||||
strings.write_string(b, "Enterprise")
|
||||
|
||||
case .CORE:
|
||||
strings.write_string(b, "Home Basic")
|
||||
|
||||
case .HOME_BASIC_N:
|
||||
strings.write_string(b, "Home Basic N")
|
||||
|
||||
case .EDUCATION:
|
||||
strings.write_string(b, "Education")
|
||||
|
||||
case .EDUCATION_N:
|
||||
strings.write_string(b, "Education N")
|
||||
|
||||
case .BUSINESS:
|
||||
strings.write_string(b, "Business")
|
||||
|
||||
case .STANDARD_SERVER:
|
||||
strings.write_string(b, "Standard Server")
|
||||
|
||||
case .DATACENTER_SERVER:
|
||||
strings.write_string(b, "Datacenter")
|
||||
|
||||
case .SMALLBUSINESS_SERVER:
|
||||
strings.write_string(b, "Windows Small Business Server")
|
||||
|
||||
case .ENTERPRISE_SERVER:
|
||||
strings.write_string(b, "Enterprise Server")
|
||||
|
||||
case .STARTER:
|
||||
strings.write_string(b, "Starter")
|
||||
|
||||
case .DATACENTER_SERVER_CORE:
|
||||
strings.write_string(b, "Datacenter Server Core")
|
||||
|
||||
case .STANDARD_SERVER_CORE:
|
||||
strings.write_string(b, "Server Standard Core")
|
||||
|
||||
case .ENTERPRISE_SERVER_CORE:
|
||||
strings.write_string(b, "Enterprise Server Core")
|
||||
|
||||
case .BUSINESS_N:
|
||||
strings.write_string(b, "Business N")
|
||||
|
||||
case .HOME_SERVER:
|
||||
strings.write_string(b, "Home Server")
|
||||
|
||||
case .SERVER_FOR_SMALLBUSINESS:
|
||||
strings.write_string(b, "Windows Server 2008 for Windows Essential Server Solutions")
|
||||
|
||||
case .SMALLBUSINESS_SERVER_PREMIUM:
|
||||
strings.write_string(b, "Small Business Server Premium")
|
||||
|
||||
case .HOME_PREMIUM_N:
|
||||
strings.write_string(b, "Home Premium N")
|
||||
|
||||
case .ENTERPRISE_N:
|
||||
strings.write_string(b, "Enterprise N")
|
||||
|
||||
case .ULTIMATE_N:
|
||||
strings.write_string(b, "Ultimate N")
|
||||
|
||||
case .HYPERV:
|
||||
strings.write_string(b, "HyperV")
|
||||
|
||||
case .STARTER_N:
|
||||
strings.write_string(b, "Starter N")
|
||||
|
||||
case .PROFESSIONAL:
|
||||
strings.write_string(b, "Professional")
|
||||
|
||||
case .PROFESSIONAL_N:
|
||||
strings.write_string(b, "Professional N")
|
||||
|
||||
case:
|
||||
strings.write_string(b, "Unknown Edition")
|
||||
}
|
||||
}
|
||||
|
||||
// Grab Windows DisplayVersion (like 20H02)
|
||||
format_display_version :: proc (b: ^strings.Builder) -> (version: string) {
|
||||
dv, ok := read_reg(
|
||||
sys.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
"DisplayVersion",
|
||||
string,
|
||||
)
|
||||
defer delete(dv) // It'll be interned into `version_string_buf`
|
||||
|
||||
if ok {
|
||||
strings.write_string(b, " (version: ")
|
||||
l := strings.builder_len(b^)
|
||||
strings.write_string(b, dv)
|
||||
version = strings.to_string(b^)[l:][:len(dv)]
|
||||
strings.write_rune(b, ')')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Grab build number and UBR
|
||||
format_build_number :: proc (b: ^strings.Builder, major_build: int) -> (ubr: int) {
|
||||
res, ok := read_reg(
|
||||
sys.HKEY_LOCAL_MACHINE,
|
||||
"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
|
||||
"UBR",
|
||||
i32,
|
||||
)
|
||||
|
||||
if ok {
|
||||
ubr = int(res)
|
||||
strings.write_string(b, ", build: ")
|
||||
strings.write_int(b, major_build)
|
||||
strings.write_rune(b, '.')
|
||||
strings.write_int(b, ubr)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@(init)
|
||||
init_ram :: proc() {
|
||||
state: sys.MEMORYSTATUSEX
|
||||
|
||||
state.dwLength = size_of(state)
|
||||
ok := sys.GlobalMemoryStatusEx(&state)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
ram = RAM{
|
||||
total_ram = int(state.ullTotalPhys),
|
||||
free_ram = int(state.ullAvailPhys),
|
||||
total_swap = int(state.ullTotalPageFil),
|
||||
free_swap = int(state.ullAvailPageFil),
|
||||
}
|
||||
}
|
||||
|
||||
@(init, private)
|
||||
init_gpu_info :: proc() {
|
||||
|
||||
GPU_INFO_BASE :: "SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}\\"
|
||||
|
||||
gpu_list: [dynamic]GPU
|
||||
gpu_index: int
|
||||
|
||||
for {
|
||||
key := fmt.tprintf("%v\\%04d", GPU_INFO_BASE, gpu_index)
|
||||
|
||||
if vendor, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "ProviderName", string); ok {
|
||||
append(&gpu_list, GPU{vendor_name = vendor})
|
||||
} else {
|
||||
break
|
||||
}
|
||||
|
||||
if desc, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "DriverDesc", string); ok {
|
||||
gpu_list[gpu_index].model_name = desc
|
||||
}
|
||||
|
||||
if vram, ok := read_reg(sys.HKEY_LOCAL_MACHINE, key, "HardwareInformation.qwMemorySize", i64); ok {
|
||||
gpu_list[gpu_index].total_ram = int(vram)
|
||||
}
|
||||
gpu_index += 1
|
||||
}
|
||||
gpus = gpu_list[:]
|
||||
}
|
||||
|
||||
@(private)
|
||||
read_reg :: proc(hkey: sys.HKEY, subkey, val: string, $T: typeid) -> (res: T, ok: bool) {
|
||||
BUF_SIZE :: 1024
|
||||
|
||||
if len(subkey) == 0 || len(val) == 0 {
|
||||
return {}, false
|
||||
}
|
||||
|
||||
key_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
val_name_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
|
||||
utf16.encode_string(key_name_wide, subkey)
|
||||
utf16.encode_string(val_name_wide, val)
|
||||
|
||||
when T == string {
|
||||
result_wide := make([]u16, BUF_SIZE, context.temp_allocator)
|
||||
result_size := sys.DWORD(BUF_SIZE * size_of(u16))
|
||||
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_SZ,
|
||||
nil,
|
||||
raw_data(result_wide[:]),
|
||||
&result_size,
|
||||
)
|
||||
if status != 0 {
|
||||
// Couldn't retrieve string
|
||||
return
|
||||
}
|
||||
|
||||
// Result string will be allocated for the caller.
|
||||
result_utf8 := make([]u8, BUF_SIZE * 4, context.temp_allocator)
|
||||
utf16.decode_to_utf8(result_utf8, result_wide[:result_size])
|
||||
return strings.clone_from_cstring(cstring(raw_data(result_utf8))), true
|
||||
|
||||
} else when T == i32 {
|
||||
result_size := sys.DWORD(size_of(i32))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_DWORD,
|
||||
nil,
|
||||
&res,
|
||||
&result_size,
|
||||
)
|
||||
return res, status == 0
|
||||
|
||||
} else when T == i64 {
|
||||
result_size := sys.DWORD(size_of(i64))
|
||||
status := sys.RegGetValueW(
|
||||
hkey,
|
||||
&key_name_wide[0],
|
||||
&val_name_wide[0],
|
||||
sys.RRF_RT_REG_QWORD,
|
||||
nil,
|
||||
&res,
|
||||
&result_size,
|
||||
)
|
||||
return res, status == 0
|
||||
} else {
|
||||
#assert(false, "Unhandled type for read_reg")
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package sysinfo
|
||||
|
||||
when !(ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 || ODIN_ARCH == .arm32 || ODIN_ARCH == .arm64) {
|
||||
#assert(false, "This package is unsupported on this architecture.")
|
||||
}
|
||||
|
||||
os_version: OS_Version
|
||||
ram: RAM
|
||||
gpus: []GPU
|
||||
|
||||
OS_Version_Platform :: enum {
|
||||
Unknown,
|
||||
Windows,
|
||||
Linux,
|
||||
MacOS,
|
||||
iOS,
|
||||
FreeBSD,
|
||||
OpenBSD,
|
||||
NetBSD,
|
||||
}
|
||||
|
||||
OS_Version :: struct {
|
||||
platform: OS_Version_Platform,
|
||||
|
||||
major: int,
|
||||
minor: int,
|
||||
patch: int,
|
||||
build: [2]int,
|
||||
version: string,
|
||||
|
||||
as_string: string,
|
||||
}
|
||||
|
||||
RAM :: struct {
|
||||
total_ram: int,
|
||||
free_ram: int,
|
||||
total_swap: int,
|
||||
free_swap: int,
|
||||
}
|
||||
|
||||
GPU :: struct {
|
||||
vendor_name: string,
|
||||
model_name: string,
|
||||
total_ram: int,
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package unix
|
||||
|
||||
// FreeBSD 13 syscall numbers
|
||||
// See: https://alfonsosiciliano.gitlab.io/posts/2021-01-02-freebsd-system-calls-table.html
|
||||
|
||||
SYS_uname : uintptr : 164
|
||||
SYS_sysctl : uintptr : 202
|
||||
@@ -0,0 +1,6 @@
|
||||
package unix
|
||||
|
||||
// OpenBSD 7.1 syscall numbers
|
||||
// See: /usr/include/sys/syscall.h
|
||||
|
||||
SYS_sysctl : uintptr : 202
|
||||
@@ -0,0 +1,45 @@
|
||||
//+build darwin
|
||||
package unix
|
||||
|
||||
import "core:sys/darwin"
|
||||
import "core:intrinsics"
|
||||
|
||||
_ :: darwin
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := i64(size_of(T))
|
||||
|
||||
res := intrinsics.syscall(
|
||||
darwin.unix_offset_syscall(.sysctl),
|
||||
uintptr(raw_data(mib)), uintptr(len(mib)),
|
||||
uintptr(val), uintptr(&result_size),
|
||||
uintptr(0), uintptr(0),
|
||||
)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See sysctl.h for darwin for details
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1 // Darwin
|
||||
KERN_OSRELEASE :: 2 // 21.5.0 for 12.4 Monterey
|
||||
KERN_OSREV :: 3 // i32: system revision
|
||||
KERN_VERSION :: 4 // Darwin Kernel Version 21.5.0: Tue Apr 26 21:08:22 PDT 2022; root:darwin-8020.121.3~4/RELEASE_X86_64
|
||||
KERN_OSRELDATE :: 26 // i32: OS release date
|
||||
KERN_OSVERSION :: 65 // Build number, e.g. 21F79
|
||||
CTL_VM :: 2
|
||||
CTL_VFS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1 // x86_64
|
||||
HW_MODEL :: 2 // MacbookPro14,1
|
||||
HW_NCPU :: 3 /* int: number of cpus */
|
||||
HW_BYTEORDER :: 4 /* int: machine byte order */
|
||||
HW_MACHINE_ARCH :: 12 /* string: machine architecture */
|
||||
HW_VECTORUNIT :: 13 /* int: has HW vector unit? */
|
||||
HW_MEMSIZE :: 24 // u64
|
||||
HW_AVAILCPU :: 25 /* int: number of available CPUs */
|
||||
|
||||
CTL_MACHDEP :: 7
|
||||
CTL_USER :: 8
|
||||
@@ -0,0 +1,44 @@
|
||||
//+build freebsd
|
||||
package unix
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := i64(size_of(T))
|
||||
|
||||
res := intrinsics.syscall(SYS_sysctl,
|
||||
uintptr(raw_data(mib)), uintptr(len(mib)),
|
||||
uintptr(val), uintptr(&result_size),
|
||||
uintptr(0), uintptr(0),
|
||||
)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See /usr/include/sys/sysctl.h for details
|
||||
CTL_SYSCTL :: 0
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1
|
||||
KERN_OSRELEASE :: 2
|
||||
KERN_OSREV :: 3
|
||||
KERN_VERSION :: 4
|
||||
CTL_VM :: 2
|
||||
CTL_VFS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1
|
||||
HW_MODEL :: 2
|
||||
HW_NCPU :: 3
|
||||
HW_BYTEORDER :: 4
|
||||
HW_PHYSMEM :: 5
|
||||
HW_USERMEM :: 6
|
||||
HW_PAGESIZE :: 7
|
||||
HW_DISKNAMES :: 8
|
||||
HW_DISKSTATS :: 9
|
||||
HW_FLOATINGPT :: 10
|
||||
HW_MACHINE_ARCH :: 11
|
||||
HW_REALMEM :: 12
|
||||
CTL_MACHDEP :: 7
|
||||
CTL_USER :: 8
|
||||
CTL_P1003_1B :: 9
|
||||
@@ -0,0 +1,49 @@
|
||||
//+build openbsd
|
||||
package unix
|
||||
|
||||
import "core:c"
|
||||
foreign import libc "system:c"
|
||||
|
||||
@(default_calling_convention="c")
|
||||
foreign libc {
|
||||
@(link_name="sysctl") _unix_sysctl :: proc(name: [^]i32, namelen: u32, oldp: rawptr, oldlenp: ^c.size_t, newp: rawptr, newlen: c.size_t) -> i32 ---
|
||||
}
|
||||
|
||||
sysctl :: proc(mib: []i32, val: ^$T) -> (ok: bool) {
|
||||
mib := mib
|
||||
result_size := c.size_t(size_of(T))
|
||||
res := _unix_sysctl(raw_data(mib), u32(len(mib)), val, &result_size, nil, 0)
|
||||
return res == 0
|
||||
}
|
||||
|
||||
// See /usr/include/sys/sysctl.h for details
|
||||
CTL_SYSCTL :: 0
|
||||
CTL_KERN :: 1
|
||||
KERN_OSTYPE :: 1
|
||||
KERN_OSRELEASE :: 2
|
||||
KERN_OSREV :: 3
|
||||
KERN_VERSION :: 4
|
||||
CTL_VM :: 2
|
||||
CTL_FS :: 3
|
||||
CTL_NET :: 4
|
||||
CTL_DEBUG :: 5
|
||||
CTL_HW :: 6
|
||||
HW_MACHINE :: 1
|
||||
HW_MODEL :: 2
|
||||
HW_NCPU :: 3
|
||||
HW_BYTEORDER :: 4
|
||||
HW_PHYSMEM :: 5
|
||||
HW_USERMEM :: 6
|
||||
HW_PAGESIZE :: 7
|
||||
HW_DISKNAMES :: 8
|
||||
HW_DISKSTATS :: 9
|
||||
HW_DISKCOUNT :: 10
|
||||
HW_SENSORS :: 11
|
||||
HW_CPUSPEED :: 12
|
||||
HW_SETPERF :: 13
|
||||
HW_VENDOR :: 14
|
||||
HW_PRODUCT :: 15
|
||||
HW_VERSION :: 16
|
||||
HW_SERIALNO :: 17
|
||||
HW_UUID :: 18
|
||||
HW_PHYSMEM64 :: 19
|
||||
@@ -13,10 +13,10 @@ Callgrind_Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
callgrind_client_request_expr :: proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
callgrind_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
callgrind_client_request_stmt :: proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
callgrind_client_request_stmt :: #force_inline proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
//+build amd64
|
||||
package sys_valgrind
|
||||
|
||||
import "core:intrinsics"
|
||||
|
||||
Helgrind_Client_Request :: enum uintptr {
|
||||
Clean_Memory = 'H'<<24 | 'G'<<16,
|
||||
Set_My_pthread_t = ('H'<<25 | 'G'<<16)+256,
|
||||
Pthread_Join_Post,
|
||||
Pthread_Mutex_Init_Post,
|
||||
Pthread_Mutex_Destroy_Pre,
|
||||
Pthread_Mutex_Unlock_Pre,
|
||||
Pthread_Mutex_Unlock_Post,
|
||||
Pthread_Mutex_Lock_Pre,
|
||||
Pthread_Mutex_Lock_Post,
|
||||
Pthread_Cond_Signal_Pre,
|
||||
Pthread_Cond_Broadcast_Pre,
|
||||
Pthread_Cond_Wait_Pre,
|
||||
Pthread_Cond_Wait_Post,
|
||||
Pthread_Cond_Destroy_Pre,
|
||||
Pthread_Rwlock_Init_Post,
|
||||
Pthread_Rwlock_Destroy_Pre,
|
||||
Pthread_Rwlock_Lock_Pre,
|
||||
Pthread_Rwlock_Lock_Post,
|
||||
Pthread_Rwlock_Unlock_Pre,
|
||||
Pthread_Rwlock_Unlock_Post,
|
||||
Posix_Sem_Init_Post,
|
||||
Posix_Sem_Destroy_Pre,
|
||||
Posix_Sem_Post_Pre,
|
||||
Posix_Sem_Wait_Post,
|
||||
Pthread_Barrier_Init_Pre,
|
||||
Pthread_Barrier_Wait_Pre,
|
||||
Pthread_Barrier_Destroy_Pre,
|
||||
Pthread_Spin_Init_Or_Unlock_Pre,
|
||||
Pthread_Spin_Init_Or_Unlock_Post,
|
||||
Pthread_Spin_Lock_Pre,
|
||||
Pthread_Spin_Lock_Post,
|
||||
Pthread_Spin_Destroy_Pre,
|
||||
Clientreq_Unimp,
|
||||
Userso_Send_Pre,
|
||||
Userso_Recv_Post,
|
||||
Userso_Forget_All,
|
||||
Reserved2,
|
||||
Reserved3,
|
||||
Reserved4,
|
||||
Arange_Make_Untracked,
|
||||
Arange_Make_Tracked,
|
||||
Pthread_Barrier_Resize_Pre,
|
||||
Clean_Memory_Heapblock,
|
||||
Pthread_Cond_Init_Post,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
helgrind_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Helgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
helgrind_client_request_stmt :: #force_inline proc "c" (request: Helgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
helgrind_mutex_init_post :: proc "c" (mutex: rawptr, mb_rec: uint) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Init_Post, uintptr(mutex), uintptr(mb_rec), 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_destroy_pre :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Destroy_Pre, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_lock_pre :: proc "c" (mutex: rawptr, is_try_lock: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Lock_Pre, uintptr(mutex), uintptr(is_try_lock), 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_lock_post :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Lock_Post, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_unlock_pre :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Unlock_Pre, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_mutex_unlock_post :: proc "c" (mutex: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Mutex_Unlock_Post, uintptr(mutex), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
helgrind_rwlock_init_post :: proc "c" (lock: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Init_Post, uintptr(lock), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_destroy_pre :: proc "c" (lock: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Destroy_Pre, uintptr(lock), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_lock_pre :: proc "c" (lock: rawptr, is_w: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Lock_Pre, uintptr(lock), uintptr(is_w), 0, 0, 0)
|
||||
}
|
||||
helgrind_rwlock_unlock_post :: proc "c" (lock: rawptr, is_w: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Rwlock_Unlock_Pre, uintptr(lock), uintptr(is_w), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_sem_init_post :: proc "c" (sem: rawptr, value: uint) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Init_Post, uintptr(sem), uintptr(value), 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_wait_post :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Wait_Post, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_post_pre :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Post_Pre, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_sem_destroy_pre :: proc "c" (sem: rawptr) {
|
||||
helgrind_client_request_stmt(.Posix_Sem_Destroy_Pre, uintptr(sem), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_barrier_init_pre :: proc "c" (bar: rawptr, count: uint, resizable: bool) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Init_Pre, uintptr(bar), uintptr(count), uintptr(resizable), 0, 0)
|
||||
}
|
||||
helgrind_barrier_wait_pre :: proc "c" (bar: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Wait_Pre, uintptr(bar), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_barrier_resize_pre :: proc "c" (bar: rawptr, new_count: uint) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Resize_Pre, uintptr(bar), uintptr(new_count), 0, 0, 0)
|
||||
}
|
||||
helgrind_barrier_destroy_pre :: proc "c" (bar: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Barrier_Destroy_Pre, uintptr(bar), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
|
||||
helgrind_clean_memory :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Clean_Memory, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
helgrind_clean_memory_slice :: proc "c" (qzz: []byte) {
|
||||
helgrind_client_request_stmt(.Clean_Memory, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
|
||||
}
|
||||
helgrind_clean_memory_heap_block :: proc "c" (qzz_blockstart: rawptr) -> int {
|
||||
return int(helgrind_client_request_expr(~uintptr(1), .Clean_Memory_Heapblock, uintptr(qzz_blockstart), 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
|
||||
helgrind_disable_checking :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Arange_Make_Untracked, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
helgrind_enable_checking :: proc "c" (qzz_start: rawptr, qzz_len: uint) {
|
||||
helgrind_client_request_stmt(.Arange_Make_Tracked, uintptr(qzz_start), uintptr(qzz_len), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_cond_init_post :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Init_Post, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_destroy_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Destroy_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_signal_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Signal_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_broadcast_pre :: proc "c" (cond: rawptr) {
|
||||
helgrind_client_request_stmt(.Pthread_Cond_Broadcast_Pre, uintptr(cond), 0, 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_wait_pre :: proc "c" (cond: rawptr, lock: rawptr) -> bool {
|
||||
return 0 != helgrind_client_request_expr(0, .Pthread_Cond_Wait_Pre, uintptr(cond), uintptr(lock), 0, 0, 0)
|
||||
}
|
||||
helgrind_cond_wait_post :: proc "c" (cond: rawptr, lock: rawptr) -> bool {
|
||||
return 0 != helgrind_client_request_expr(0, .Pthread_Cond_Wait_Post, uintptr(cond), uintptr(lock), 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_client_request_unimp :: #force_inline proc "c" (msg: cstring) {
|
||||
helgrind_client_request_stmt(.Clientreq_Unimp, uintptr(rawptr(msg)), 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
|
||||
helgrind_annotate_condvar_lock_wait :: #force_inline proc "c" (cv: rawptr, lock: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_LOCK_WAIT")
|
||||
}
|
||||
helgrind_annotate_condvar_wait :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_WAIT")
|
||||
}
|
||||
helgrind_annotate_condvar_signal :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_SIGNAL")
|
||||
}
|
||||
helgrind_annotate_condvar_signal_all :: proc "c" (cv: rawptr) {
|
||||
helgrind_client_request_unimp("ANNOTATE_CONDVAR_SIGNAL_ALL")
|
||||
}
|
||||
@@ -22,10 +22,10 @@ Mem_Check_Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
mem_check_client_request_expr :: proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
mem_check_client_request_expr :: #force_inline proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
mem_check_client_request_stmt :: proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
mem_check_client_request_stmt :: #force_inline proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ Client_Request :: enum uintptr {
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
client_request_expr :: proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
client_request_expr :: #force_inline proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
|
||||
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
client_request_stmt :: #force_inline proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
|
||||
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: ui
|
||||
// 0 - running natively
|
||||
// 1 - running under Valgrind
|
||||
// 2 - running under Valgrind which is running under another Valgrind
|
||||
running_on_valgrind :: proc "c" () -> uintptr {
|
||||
return client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0)
|
||||
running_on_valgrind :: proc "c" () -> uint {
|
||||
return uint(client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0))
|
||||
}
|
||||
|
||||
// Discard translation of code in the slice qzz. Useful if you are debugging a JIT-er or some such,
|
||||
|
||||
@@ -657,6 +657,13 @@ foreign kernel32 {
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
GlobalMemoryStatusEx :: proc(
|
||||
lpBuffer: ^MEMORYSTATUSEX,
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
PBAD_MEMORY_CALLBACK_ROUTINE :: #type proc "stdcall" ()
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
@@ -800,5 +807,160 @@ foreign kernel32 {
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
GetProductInfo :: proc(
|
||||
OSMajorVersion: DWORD,
|
||||
OSMinorVersion: DWORD,
|
||||
SpMajorVersion: DWORD,
|
||||
SpMinorVersion: DWORD,
|
||||
product_type: ^Windows_Product_Type,
|
||||
) -> BOOL ---
|
||||
}
|
||||
|
||||
HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
|
||||
PHANDLER_ROUTINE :: HandlerRoutine
|
||||
|
||||
|
||||
|
||||
|
||||
DCB_Config :: struct {
|
||||
fParity: bool,
|
||||
fOutxCtsFlow: bool,
|
||||
fOutxDsrFlow: bool,
|
||||
fDtrControl: DTR_Control,
|
||||
fDsrSensitivity: bool,
|
||||
fTXContinueOnXoff: bool,
|
||||
fOutX: bool,
|
||||
fInX: bool,
|
||||
fErrorChar: bool,
|
||||
fNull: bool,
|
||||
fRtsControl: RTS_Control,
|
||||
fAbortOnError: bool,
|
||||
BaudRate: DWORD,
|
||||
ByteSize: BYTE,
|
||||
Parity: Parity,
|
||||
StopBits: Stop_Bits,
|
||||
XonChar: byte,
|
||||
XoffChar: byte,
|
||||
ErrorChar: byte,
|
||||
EvtChar: byte,
|
||||
}
|
||||
DTR_Control :: enum byte {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
Handshake = 2,
|
||||
}
|
||||
RTS_Control :: enum byte {
|
||||
Disable = 0,
|
||||
Enable = 1,
|
||||
Handshake = 2,
|
||||
Toggle = 3,
|
||||
}
|
||||
Parity :: enum byte {
|
||||
None = 0,
|
||||
Odd = 1,
|
||||
Even = 2,
|
||||
Mark = 3,
|
||||
Space = 4,
|
||||
}
|
||||
Stop_Bits :: enum byte {
|
||||
One = 0,
|
||||
One_And_A_Half = 1,
|
||||
Two = 2,
|
||||
}
|
||||
|
||||
// A helper procedure to set the values of a DCB structure.
|
||||
init_dcb_with_config :: proc "contextless" (dcb: ^DCB, config: DCB_Config) {
|
||||
out: u32
|
||||
|
||||
// NOTE(tetra, 2022-09-21): On both Clang 14 on Windows, and MSVC, the bits in the bitfield
|
||||
// appear to be defined from LSB to MSB order.
|
||||
// i.e: `fBinary` (the first bitfield in the C source) is the LSB in the `settings` u32.
|
||||
|
||||
out |= u32(1) << 0 // fBinary must always be true on Windows.
|
||||
|
||||
out |= u32(config.fParity) << 1
|
||||
out |= u32(config.fOutxCtsFlow) << 2
|
||||
out |= u32(config.fOutxDsrFlow) << 3
|
||||
|
||||
out |= u32(config.fDtrControl) << 4
|
||||
|
||||
out |= u32(config.fDsrSensitivity) << 6
|
||||
out |= u32(config.fTXContinueOnXoff) << 7
|
||||
out |= u32(config.fOutX) << 8
|
||||
out |= u32(config.fInX) << 9
|
||||
out |= u32(config.fErrorChar) << 10
|
||||
out |= u32(config.fNull) << 11
|
||||
|
||||
out |= u32(config.fRtsControl) << 12
|
||||
|
||||
out |= u32(config.fAbortOnError) << 14
|
||||
|
||||
dcb.settings = out
|
||||
|
||||
dcb.BaudRate = config.BaudRate
|
||||
dcb.ByteSize = config.ByteSize
|
||||
dcb.Parity = config.Parity
|
||||
dcb.StopBits = config.StopBits
|
||||
dcb.XonChar = config.XonChar
|
||||
dcb.XoffChar = config.XoffChar
|
||||
dcb.ErrorChar = config.ErrorChar
|
||||
dcb.EvtChar = config.EvtChar
|
||||
|
||||
dcb.DCBlength = size_of(DCB)
|
||||
}
|
||||
get_dcb_config :: proc "contextless" (dcb: DCB) -> (config: DCB_Config) {
|
||||
config.fParity = bool((dcb.settings >> 1) & 0x01)
|
||||
config.fOutxCtsFlow = bool((dcb.settings >> 2) & 0x01)
|
||||
config.fOutxDsrFlow = bool((dcb.settings >> 3) & 0x01)
|
||||
|
||||
config.fDtrControl = DTR_Control((dcb.settings >> 4) & 0x02)
|
||||
|
||||
config.fDsrSensitivity = bool((dcb.settings >> 6) & 0x01)
|
||||
config.fTXContinueOnXoff = bool((dcb.settings >> 7) & 0x01)
|
||||
config.fOutX = bool((dcb.settings >> 8) & 0x01)
|
||||
config.fInX = bool((dcb.settings >> 9) & 0x01)
|
||||
config.fErrorChar = bool((dcb.settings >> 10) & 0x01)
|
||||
config.fNull = bool((dcb.settings >> 11) & 0x01)
|
||||
|
||||
config.fRtsControl = RTS_Control((dcb.settings >> 12) & 0x02)
|
||||
|
||||
config.fAbortOnError = bool((dcb.settings >> 14) & 0x01)
|
||||
|
||||
config.BaudRate = dcb.BaudRate
|
||||
config.ByteSize = dcb.ByteSize
|
||||
config.Parity = dcb.Parity
|
||||
config.StopBits = dcb.StopBits
|
||||
config.XonChar = dcb.XonChar
|
||||
config.XoffChar = dcb.XoffChar
|
||||
config.ErrorChar = dcb.ErrorChar
|
||||
config.EvtChar = dcb.EvtChar
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// NOTE(tetra): See get_dcb_config() and init_dcb_with_config() for help with initializing this.
|
||||
DCB :: struct {
|
||||
DCBlength: DWORD, // NOTE(tetra): Must be set to size_of(DCB).
|
||||
BaudRate: DWORD,
|
||||
settings: u32, // NOTE(tetra): These are bitfields in the C struct.
|
||||
wReserved: WORD,
|
||||
XOnLim: WORD,
|
||||
XOffLim: WORD,
|
||||
ByteSize: BYTE,
|
||||
Parity: Parity,
|
||||
StopBits: Stop_Bits,
|
||||
XonChar: byte,
|
||||
XoffChar: byte,
|
||||
ErrorChar: byte,
|
||||
EofChar: byte,
|
||||
EvtChar: byte,
|
||||
wReserved1: WORD,
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign kernel32 {
|
||||
GetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||
SetCommState :: proc(handle: HANDLE, dcb: ^DCB) -> BOOL ---
|
||||
}
|
||||
@@ -6,4 +6,12 @@ foreign import shell32 "system:Shell32.lib"
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign shell32 {
|
||||
CommandLineToArgvW :: proc(cmd_list: wstring, num_args: ^c_int) -> ^wstring ---
|
||||
ShellExecuteW :: proc(
|
||||
hwnd: HWND,
|
||||
lpOperation: LPCWSTR,
|
||||
lpFile: LPCWSTR,
|
||||
lpParameters: LPCWSTR,
|
||||
lpDirectory: LPCWSTR,
|
||||
nShowCmd: INT,
|
||||
) -> HINSTANCE ---
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ size_t :: c.size_t
|
||||
wchar_t :: c.wchar_t
|
||||
|
||||
DWORD :: c_ulong
|
||||
DWORDLONG :: c.ulonglong
|
||||
QWORD :: c.ulonglong
|
||||
HANDLE :: distinct LPVOID
|
||||
HINSTANCE :: HANDLE
|
||||
@@ -589,6 +590,10 @@ BS_MULTILINE :: 0x00002000
|
||||
BS_NOTIFY :: 0x00004000
|
||||
BS_FLAT :: 0x00008000
|
||||
BS_RIGHTBUTTON :: BS_LEFTTEXT
|
||||
BS_SPLITBUTTON :: 0x0000000C
|
||||
BS_DEFSPLITBUTTON :: 0x0000000D
|
||||
BS_COMMANDLINK :: 0x0000000E
|
||||
BS_DEFCOMMANDLINK :: 0x0000000F
|
||||
|
||||
// Button Control Messages
|
||||
BST_UNCHECKED :: 0x0000
|
||||
@@ -827,6 +832,53 @@ CREATESTRUCTW:: struct {
|
||||
dwExStyle: DWORD,
|
||||
}
|
||||
|
||||
MAX_LINKID_TEXT :: 48
|
||||
L_MAX_URL_LENGTH :: 2048 + 32 + len("://")
|
||||
|
||||
LITEM :: struct {
|
||||
mask: UINT,
|
||||
iLink: c_int,
|
||||
state: UINT,
|
||||
stateMask: UINT,
|
||||
szID: [MAX_LINKID_TEXT]WCHAR,
|
||||
szUrl: [L_MAX_URL_LENGTH]WCHAR,
|
||||
}
|
||||
|
||||
NMLINK :: struct {
|
||||
hdr: NMHDR,
|
||||
item: LITEM,
|
||||
}
|
||||
|
||||
NMHDR :: struct {
|
||||
hwndFrom: HWND,
|
||||
idFrom: UINT_PTR,
|
||||
code: UINT, // NM_ code
|
||||
}
|
||||
|
||||
// Generic WM_NOTIFY notification codes
|
||||
NM_OUTOFMEMORY :: ~uintptr(0) // -1
|
||||
NM_CLICK :: NM_OUTOFMEMORY-1 // uses NMCLICK struct
|
||||
NM_DBLCLK :: NM_OUTOFMEMORY-2
|
||||
NM_RETURN :: NM_OUTOFMEMORY-3
|
||||
NM_RCLICK :: NM_OUTOFMEMORY-4 // uses NMCLICK struct
|
||||
NM_RDBLCLK :: NM_OUTOFMEMORY-5
|
||||
NM_SETFOCUS :: NM_OUTOFMEMORY-6
|
||||
NM_KILLFOCUS :: NM_OUTOFMEMORY-7
|
||||
NM_CUSTOMDRAW :: NM_OUTOFMEMORY-11
|
||||
NM_HOVER :: NM_OUTOFMEMORY-12
|
||||
NM_NCHITTEST :: NM_OUTOFMEMORY-13 // uses NMMOUSE struct
|
||||
NM_KEYDOWN :: NM_OUTOFMEMORY-14 // uses NMKEY struct
|
||||
NM_RELEASEDCAPTURE :: NM_OUTOFMEMORY-15
|
||||
NM_SETCURSOR :: NM_OUTOFMEMORY-16 // uses NMMOUSE struct
|
||||
NM_CHAR :: NM_OUTOFMEMORY-17 // uses NMCHAR struct
|
||||
NM_TOOLTIPSCREATED :: NM_OUTOFMEMORY-18 // notify of when the tooltips window is create
|
||||
NM_LDOWN :: NM_OUTOFMEMORY-19
|
||||
NM_RDOWN :: NM_OUTOFMEMORY-20
|
||||
NM_THEMECHANGED :: NM_OUTOFMEMORY-21
|
||||
NM_FONTCHANGED :: NM_OUTOFMEMORY-22
|
||||
NM_CUSTOMTEXT :: NM_OUTOFMEMORY-23 // uses NMCUSTOMTEXT struct
|
||||
NM_TVSTATEIMAGECHANGING :: NM_OUTOFMEMORY-23 // uses NMTVSTATEIMAGECHANGING struct, defined after HTREEITEM
|
||||
|
||||
DEVMODEW :: struct {
|
||||
dmDeviceName: [32]wchar_t,
|
||||
dmSpecVersion: WORD,
|
||||
@@ -950,6 +1002,13 @@ CS_BYTEALIGNWINDOW : UINT : 0x2000
|
||||
CS_GLOBALCLASS : UINT : 0x4000
|
||||
CS_DROPSHADOW : UINT : 0x0002_0000
|
||||
|
||||
AURL_ENABLEURL :: 1
|
||||
AURL_ENABLEEMAILADDR :: 2
|
||||
AURL_ENABLETELNO :: 4
|
||||
AURL_ENABLEEAURLS :: 8
|
||||
AURL_ENABLEDRIVELETTERS :: 16
|
||||
AURL_DISABLEMIXEDLGC :: 32 // Disable mixed Latin Greek Cyrillic IDNs
|
||||
|
||||
WS_BORDER : UINT : 0x0080_0000
|
||||
WS_CAPTION : UINT : 0x00C0_0000
|
||||
WS_CHILD : UINT : 0x4000_0000
|
||||
@@ -1603,6 +1662,7 @@ WSAENOTCONN: c_int : 10057
|
||||
WSAESHUTDOWN: c_int : 10058
|
||||
WSAETIMEDOUT: c_int : 10060
|
||||
WSAECONNREFUSED: c_int : 10061
|
||||
WSATRY_AGAIN: c_int : 11002
|
||||
|
||||
MAX_PROTOCOL_CHAIN: DWORD : 7
|
||||
|
||||
@@ -3298,6 +3358,119 @@ IFileSaveDialogVtbl :: struct {
|
||||
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
|
||||
}
|
||||
|
||||
MEMORYSTATUSEX :: struct {
|
||||
dwLength: DWORD,
|
||||
dwMemoryLoad: DWORD,
|
||||
ullTotalPhys: DWORDLONG,
|
||||
ullAvailPhys: DWORDLONG,
|
||||
ullTotalPageFil: DWORDLONG,
|
||||
ullAvailPageFil: DWORDLONG,
|
||||
ullTotalVirtual: DWORDLONG,
|
||||
ullAvailVirtual: DWORDLONG,
|
||||
ullAvailExtendedVirtual: DWORDLONG,
|
||||
}
|
||||
|
||||
Windows_Product_Type :: enum DWORD {
|
||||
BUSINESS = 0x00000006, // Business
|
||||
BUSINESS_N = 0x00000010, // Business N
|
||||
CLUSTER_SERVER = 0x00000012, // HPC Edition
|
||||
CLUSTER_SERVER_V = 0x00000040, // Server Hyper Core V
|
||||
CORE = 0x00000065, // Windows 10 Home
|
||||
CORE_COUNTRYSPECIFIC = 0x00000063, // Windows 10 Home China
|
||||
CORE_N = 0x00000062, // Windows 10 Home N
|
||||
CORE_SINGLELANGUAGE = 0x00000064, // Windows 10 Home Single Language
|
||||
DATACENTER_EVALUATION_SERVER = 0x00000050, // Server Datacenter (evaluation installation)
|
||||
DATACENTER_A_SERVER_CORE = 0x00000091, // Server Datacenter, Semi-Annual Channel (core installation)
|
||||
STANDARD_A_SERVER_CORE = 0x00000092, // Server Standard, Semi-Annual Channel (core installation)
|
||||
DATACENTER_SERVER = 0x00000008, // Server Datacenter (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.)
|
||||
DATACENTER_SERVER_CORE = 0x0000000C, // Server Datacenter (core installation, Windows Server 2008 R2 and earlier)
|
||||
DATACENTER_SERVER_CORE_V = 0x00000027, // Server Datacenter without Hyper-V (core installation)
|
||||
DATACENTER_SERVER_V = 0x00000025, // Server Datacenter without Hyper-V (full installation)
|
||||
EDUCATION = 0x00000079, // Windows 10 Education
|
||||
EDUCATION_N = 0x0000007A, // Windows 10 Education N
|
||||
ENTERPRISE = 0x00000004, // Windows 10 Enterprise
|
||||
ENTERPRISE_E = 0x00000046, // Windows 10 Enterprise E
|
||||
ENTERPRISE_EVALUATION = 0x00000048, // Windows 10 Enterprise Evaluation
|
||||
ENTERPRISE_N = 0x0000001B, // Windows 10 Enterprise N
|
||||
ENTERPRISE_N_EVALUATION = 0x00000054, // Windows 10 Enterprise N Evaluation
|
||||
ENTERPRISE_S = 0x0000007D, // Windows 10 Enterprise 2015 LTSB
|
||||
ENTERPRISE_S_EVALUATION = 0x00000081, // Windows 10 Enterprise 2015 LTSB Evaluation
|
||||
ENTERPRISE_S_N = 0x0000007E, // Windows 10 Enterprise 2015 LTSB N
|
||||
ENTERPRISE_S_N_EVALUATION = 0x00000082, // Windows 10 Enterprise 2015 LTSB N Evaluation
|
||||
ENTERPRISE_SERVER = 0x0000000A, // Server Enterprise (full installation)
|
||||
ENTERPRISE_SERVER_CORE = 0x0000000E, // Server Enterprise (core installation)
|
||||
ENTERPRISE_SERVER_CORE_V = 0x00000029, // Server Enterprise without Hyper-V (core installation)
|
||||
ENTERPRISE_SERVER_IA64 = 0x0000000F, // Server Enterprise for Itanium-based Systems
|
||||
ENTERPRISE_SERVER_V = 0x00000026, // Server Enterprise without Hyper-V (full installation)
|
||||
ESSENTIALBUSINESS_SERVER_ADDL = 0x0000003C, // Windows Essential Server Solution Additional
|
||||
ESSENTIALBUSINESS_SERVER_ADDLSVC = 0x0000003E, // Windows Essential Server Solution Additional SVC
|
||||
ESSENTIALBUSINESS_SERVER_MGMT = 0x0000003B, // Windows Essential Server Solution Management
|
||||
ESSENTIALBUSINESS_SERVER_MGMTSVC = 0x0000003D, // Windows Essential Server Solution Management SVC
|
||||
HOME_BASIC = 0x00000002, // Home Basic
|
||||
HOME_BASIC_E = 0x00000043, // Not supported
|
||||
HOME_BASIC_N = 0x00000005, // Home Basic N
|
||||
HOME_PREMIUM = 0x00000003, // Home Premium
|
||||
HOME_PREMIUM_E = 0x00000044, // Not supported
|
||||
HOME_PREMIUM_N = 0x0000001A, // Home Premium N
|
||||
HOME_PREMIUM_SERVER = 0x00000022, // Windows Home Server 2011
|
||||
HOME_SERVER = 0x00000013, // Windows Storage Server 2008 R2 Essentials
|
||||
HYPERV = 0x0000002A, // Microsoft Hyper-V Server
|
||||
IOTENTERPRISE = 0x000000BC, // Windows IoT Enterprise
|
||||
IOTENTERPRISE_S = 0x000000BF, // Windows IoT Enterprise LTSC
|
||||
IOTUAP = 0x0000007B, // Windows 10 IoT Core
|
||||
IOTUAPCOMMERCIAL = 0x00000083, // Windows 10 IoT Core Commercial
|
||||
MEDIUMBUSINESS_SERVER_MANAGEMENT = 0x0000001E, // Windows Essential Business Server Management Server
|
||||
MEDIUMBUSINESS_SERVER_MESSAGING = 0x00000020, // Windows Essential Business Server Messaging Server
|
||||
MEDIUMBUSINESS_SERVER_SECURITY = 0x0000001F, // Windows Essential Business Server Security Server
|
||||
MOBILE_CORE = 0x00000068, // Windows 10 Mobile
|
||||
MOBILE_ENTERPRISE = 0x00000085, // Windows 10 Mobile Enterprise
|
||||
MULTIPOINT_PREMIUM_SERVER = 0x0000004D, // Windows MultiPoint Server Premium (full installation)
|
||||
MULTIPOINT_STANDARD_SERVER = 0x0000004C, // Windows MultiPoint Server Standard (full installation)
|
||||
PRO_WORKSTATION = 0x000000A1, // Windows 10 Pro for Workstations
|
||||
PRO_WORKSTATION_N = 0x000000A2, // Windows 10 Pro for Workstations N
|
||||
PROFESSIONAL = 0x00000030, // Windows 10 Pro
|
||||
PROFESSIONAL_E = 0x00000045, // Not supported
|
||||
PROFESSIONAL_N = 0x00000031, // Windows 10 Pro N
|
||||
PROFESSIONAL_WMC = 0x00000067, // Professional with Media Center
|
||||
SB_SOLUTION_SERVER = 0x00000032, // Windows Small Business Server 2011 Essentials
|
||||
SB_SOLUTION_SERVER_EM = 0x00000036, // Server For SB Solutions EM
|
||||
SERVER_FOR_SB_SOLUTIONS = 0x00000033, // Server For SB Solutions
|
||||
SERVER_FOR_SB_SOLUTIONS_EM = 0x00000037, // Server For SB Solutions EM
|
||||
SERVER_FOR_SMALLBUSINESS = 0x00000018, // Windows Server 2008 for Windows Essential Server Solutions
|
||||
SERVER_FOR_SMALLBUSINESS_V = 0x00000023, // Windows Server 2008 without Hyper-V for Windows Essential Server Solutions
|
||||
SERVER_FOUNDATION = 0x00000021, // Server Foundation
|
||||
SMALLBUSINESS_SERVER = 0x00000009, // Windows Small Business Server
|
||||
SMALLBUSINESS_SERVER_PREMIUM = 0x00000019, // Small Business Server Premium
|
||||
SMALLBUSINESS_SERVER_PREMIUM_CORE = 0x0000003F, // Small Business Server Premium (core installation)
|
||||
SOLUTION_EMBEDDEDSERVER = 0x00000038, // Windows MultiPoint Server
|
||||
STANDARD_EVALUATION_SERVER = 0x0000004F, // Server Standard (evaluation installation)
|
||||
STANDARD_SERVER = 0x00000007, // Server Standard (full installation. For Server Core installations of Windows Server 2012 and later, use the method, Determining whether Server Core is running.)
|
||||
STANDARD_SERVER_CORE = 0x0000000D, // Server Standard (core installation, Windows Server 2008 R2 and earlier)
|
||||
STANDARD_SERVER_CORE_V = 0x00000028, // Server Standard without Hyper-V (core installation)
|
||||
STANDARD_SERVER_V = 0x00000024, // Server Standard without Hyper-V
|
||||
STANDARD_SERVER_SOLUTIONS = 0x00000034, // Server Solutions Premium
|
||||
STANDARD_SERVER_SOLUTIONS_CORE = 0x00000035, // Server Solutions Premium (core installation)
|
||||
STARTER = 0x0000000B, // Starter
|
||||
STARTER_E = 0x00000042, // Not supported
|
||||
STARTER_N = 0x0000002F, // Starter N
|
||||
STORAGE_ENTERPRISE_SERVER = 0x00000017, // Storage Server Enterprise
|
||||
STORAGE_ENTERPRISE_SERVER_CORE = 0x0000002E, // Storage Server Enterprise (core installation)
|
||||
STORAGE_EXPRESS_SERVER = 0x00000014, // Storage Server Express
|
||||
STORAGE_EXPRESS_SERVER_CORE = 0x0000002B, // Storage Server Express (core installation)
|
||||
STORAGE_STANDARD_EVALUATION_SERVER = 0x00000060, // Storage Server Standard (evaluation installation)
|
||||
STORAGE_STANDARD_SERVER = 0x00000015, // Storage Server Standard
|
||||
STORAGE_STANDARD_SERVER_CORE = 0x0000002C, // Storage Server Standard (core installation)
|
||||
STORAGE_WORKGROUP_EVALUATION_SERVER = 0x0000005F, // Storage Server Workgroup (evaluation installation)
|
||||
STORAGE_WORKGROUP_SERVER = 0x00000016, // Storage Server Workgroup
|
||||
STORAGE_WORKGROUP_SERVER_CORE = 0x0000002D, // Storage Server Workgroup (core installation)
|
||||
ULTIMATE = 0x00000001, // Ultimate
|
||||
ULTIMATE_E = 0x00000047, // Not supported
|
||||
ULTIMATE_N = 0x0000001C, // Ultimate N
|
||||
UNDEFINED = 0x00000000, // An unknown product
|
||||
WEB_SERVER = 0x00000011, // Web Server (full installation)
|
||||
WEB_SERVER_CORE = 0x0000001D, // Web Server (core installation)
|
||||
}
|
||||
|
||||
ENABLE_ECHO_INPUT : DWORD : 0x0004
|
||||
ENABLE_INSERT_MODE : DWORD : 0x0020
|
||||
ENABLE_LINE_INPUT : DWORD : 0x0002
|
||||
|
||||
@@ -104,6 +104,9 @@ foreign user32 {
|
||||
GetDC :: proc(hWnd: HWND) -> HDC ---
|
||||
ReleaseDC :: proc(hWnd: HWND, hDC: HDC) -> c_int ---
|
||||
|
||||
GetDlgCtrlID :: proc(hWnd: HWND) -> c_int ---
|
||||
GetDlgItem :: proc(hDlg: HWND, nIDDlgItem: c_int) -> HWND ---
|
||||
|
||||
GetUpdateRect :: proc(hWnd: HWND, lpRect: LPRECT, bErase: BOOL) -> BOOL ---
|
||||
ValidateRect :: proc(hWnd: HWND, lpRect: ^RECT) -> BOOL ---
|
||||
InvalidateRect :: proc(hWnd: HWND, lpRect: ^RECT, bErase: BOOL) -> BOOL ---
|
||||
|
||||
@@ -73,10 +73,10 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator)
|
||||
|
||||
// If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated
|
||||
// and will scan it to find the first null terminated character. The resulting string will
|
||||
// also null terminated.
|
||||
// also be null terminated.
|
||||
// If N != -1 it assumes the wide string is not null terminated and the resulting string
|
||||
// will not be null terminated, we therefore have to force it to be null terminated manually.
|
||||
text := make([]byte, n+1 if N != -1 else n) or_return
|
||||
// will not be null terminated.
|
||||
text := make([]byte, n) or_return
|
||||
|
||||
n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(text), n, nil, nil)
|
||||
if n1 == 0 {
|
||||
|
||||
+1092
-1084
File diff suppressed because it is too large
Load Diff
@@ -7,4 +7,5 @@ foreign import winmm "system:Winmm.lib"
|
||||
foreign winmm {
|
||||
timeBeginPeriod :: proc(uPeriod: UINT) -> MMRESULT ---
|
||||
timeEndPeriod :: proc(uPeriod: UINT) -> MMRESULT ---
|
||||
timeGetTime :: proc() -> DWORD ---
|
||||
}
|
||||
|
||||
+72
-67
@@ -3,22 +3,22 @@ package all
|
||||
// Imports every package
|
||||
// This is useful for knowing what exists and producing documentation with `odin doc`
|
||||
|
||||
import bufio "core:bufio"
|
||||
import bytes "core:bytes"
|
||||
import bufio "core:bufio"
|
||||
import bytes "core:bytes"
|
||||
|
||||
import c "core:c"
|
||||
import libc "core:c/libc"
|
||||
import c "core:c"
|
||||
import libc "core:c/libc"
|
||||
|
||||
import compress "core:compress"
|
||||
import shoco "core:compress/shoco"
|
||||
import gzip "core:compress/gzip"
|
||||
import zlib "core:compress/zlib"
|
||||
import compress "core:compress"
|
||||
import shoco "core:compress/shoco"
|
||||
import gzip "core:compress/gzip"
|
||||
import zlib "core:compress/zlib"
|
||||
|
||||
import bit_array "core:container/bit_array"
|
||||
import priority_queue "core:container/priority_queue"
|
||||
import queue "core:container/queue"
|
||||
import small_array "core:container/small_array"
|
||||
import lru "core:container/lru"
|
||||
import bit_array "core:container/bit_array"
|
||||
import priority_queue "core:container/priority_queue"
|
||||
import queue "core:container/queue"
|
||||
import small_array "core:container/small_array"
|
||||
import lru "core:container/lru"
|
||||
|
||||
import crypto "core:crypto"
|
||||
import blake "core:crypto/blake"
|
||||
@@ -27,7 +27,7 @@ import blake2s "core:crypto/blake2s"
|
||||
import chacha20 "core:crypto/chacha20"
|
||||
import chacha20poly1305 "core:crypto/chacha20poly1305"
|
||||
import gost "core:crypto/gost"
|
||||
import groestl "core:crypto/groestl"
|
||||
import groestl "core:crypto/groestl"
|
||||
import haval "core:crypto/haval"
|
||||
import jh "core:crypto/jh"
|
||||
import keccak "core:crypto/keccak"
|
||||
@@ -48,71 +48,74 @@ import crypto_util "core:crypto/util"
|
||||
import whirlpool "core:crypto/whirlpool"
|
||||
import x25519 "core:crypto/x25519"
|
||||
|
||||
import dynlib "core:dynlib"
|
||||
import dynlib "core:dynlib"
|
||||
|
||||
import base32 "core:encoding/base32"
|
||||
import base64 "core:encoding/base64"
|
||||
import csv "core:encoding/csv"
|
||||
import hxa "core:encoding/hxa"
|
||||
import json "core:encoding/json"
|
||||
import varint "core:encoding/varint"
|
||||
import xml "core:encoding/xml"
|
||||
import base32 "core:encoding/base32"
|
||||
import base64 "core:encoding/base64"
|
||||
import csv "core:encoding/csv"
|
||||
import hxa "core:encoding/hxa"
|
||||
import json "core:encoding/json"
|
||||
import varint "core:encoding/varint"
|
||||
import xml "core:encoding/xml"
|
||||
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
|
||||
import image "core:image"
|
||||
import netpbm "core:image/netpbm"
|
||||
import png "core:image/png"
|
||||
import qoi "core:image/qoi"
|
||||
import tga "core:image/tga"
|
||||
import image "core:image"
|
||||
import netpbm "core:image/netpbm"
|
||||
import png "core:image/png"
|
||||
import qoi "core:image/qoi"
|
||||
import tga "core:image/tga"
|
||||
|
||||
import io "core:io"
|
||||
import log "core:log"
|
||||
import io "core:io"
|
||||
import log "core:log"
|
||||
|
||||
import math "core:math"
|
||||
import big "core:math/big"
|
||||
import bits "core:math/bits"
|
||||
import fixed "core:math/fixed"
|
||||
import linalg "core:math/linalg"
|
||||
import glm "core:math/linalg/glsl"
|
||||
import hlm "core:math/linalg/hlsl"
|
||||
import rand "core:math/rand"
|
||||
import math "core:math"
|
||||
import big "core:math/big"
|
||||
import bits "core:math/bits"
|
||||
import fixed "core:math/fixed"
|
||||
import linalg "core:math/linalg"
|
||||
import glm "core:math/linalg/glsl"
|
||||
import hlm "core:math/linalg/hlsl"
|
||||
import noise "core:math/noise"
|
||||
import rand "core:math/rand"
|
||||
|
||||
import mem "core:mem"
|
||||
import mem "core:mem"
|
||||
// import virtual "core:mem/virtual"
|
||||
|
||||
import ast "core:odin/ast"
|
||||
import doc_format "core:odin/doc-format"
|
||||
import odin_format "core:odin/format"
|
||||
import odin_parser "core:odin/parser"
|
||||
import odin_printer "core:odin/printer"
|
||||
import odin_tokenizer "core:odin/tokenizer"
|
||||
import ast "core:odin/ast"
|
||||
import doc_format "core:odin/doc-format"
|
||||
import odin_format "core:odin/format"
|
||||
import odin_parser "core:odin/parser"
|
||||
import odin_printer "core:odin/printer"
|
||||
import odin_tokenizer "core:odin/tokenizer"
|
||||
|
||||
import os "core:os"
|
||||
import os "core:os"
|
||||
|
||||
import slashpath "core:path/slashpath"
|
||||
import filepath "core:path/filepath"
|
||||
import slashpath "core:path/slashpath"
|
||||
import filepath "core:path/filepath"
|
||||
|
||||
import reflect "core:reflect"
|
||||
import runtime "core:runtime"
|
||||
import simd "core:simd"
|
||||
import slice "core:slice"
|
||||
import slice_heap "core:slice/heap"
|
||||
import sort "core:sort"
|
||||
import strconv "core:strconv"
|
||||
import strings "core:strings"
|
||||
import sync "core:sync"
|
||||
import testing "core:testing"
|
||||
import scanner "core:text/scanner"
|
||||
import i18n "core:text/i18n"
|
||||
import thread "core:thread"
|
||||
import time "core:time"
|
||||
import reflect "core:reflect"
|
||||
import runtime "core:runtime"
|
||||
import simd "core:simd"
|
||||
import slice "core:slice"
|
||||
import slice_heap "core:slice/heap"
|
||||
import sort "core:sort"
|
||||
import strconv "core:strconv"
|
||||
import strings "core:strings"
|
||||
import sync "core:sync"
|
||||
import testing "core:testing"
|
||||
import scanner "core:text/scanner"
|
||||
import i18n "core:text/i18n"
|
||||
import thread "core:thread"
|
||||
import time "core:time"
|
||||
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
import utf16 "core:unicode/utf16"
|
||||
import sysinfo "core:sys/info"
|
||||
|
||||
import unicode "core:unicode"
|
||||
import utf8 "core:unicode/utf8"
|
||||
import utf8string "core:unicode/utf8/utf8string"
|
||||
import utf16 "core:unicode/utf16"
|
||||
|
||||
main :: proc(){}
|
||||
|
||||
@@ -181,6 +184,7 @@ _ :: fixed
|
||||
_ :: linalg
|
||||
_ :: glm
|
||||
_ :: hlm
|
||||
_ :: noise
|
||||
_ :: rand
|
||||
_ :: mem
|
||||
_ :: ast
|
||||
@@ -206,6 +210,7 @@ _ :: scanner
|
||||
_ :: i18n
|
||||
_ :: thread
|
||||
_ :: time
|
||||
_ :: sysinfo
|
||||
_ :: unicode
|
||||
_ :: utf8
|
||||
_ :: utf8string
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
package all
|
||||
|
||||
import botan "vendor:botan"
|
||||
import ENet "vendor:ENet"
|
||||
import ggpo "vendor:ggpo"
|
||||
import gl "vendor:OpenGL"
|
||||
import glfw "vendor:glfw"
|
||||
import microui "vendor:microui"
|
||||
import miniaudio "vendor:miniaudio"
|
||||
import PM "vendor:portmidi"
|
||||
import rl "vendor:raylib"
|
||||
import exr "vendor:OpenEXRCore"
|
||||
import botan "vendor:botan"
|
||||
import ENet "vendor:ENet"
|
||||
import ggpo "vendor:ggpo"
|
||||
import gl "vendor:OpenGL"
|
||||
import glfw "vendor:glfw"
|
||||
import microui "vendor:microui"
|
||||
import miniaudio "vendor:miniaudio"
|
||||
import PM "vendor:portmidi"
|
||||
import rl "vendor:raylib"
|
||||
import exr "vendor:OpenEXRCore"
|
||||
|
||||
import SDL "vendor:sdl2"
|
||||
import SDLNet "vendor:sdl2/net"
|
||||
import IMG "vendor:sdl2/image"
|
||||
import MIX "vendor:sdl2/mixer"
|
||||
import TTF "vendor:sdl2/ttf"
|
||||
import SDL "vendor:sdl2"
|
||||
import SDLNet "vendor:sdl2/net"
|
||||
import IMG "vendor:sdl2/image"
|
||||
import MIX "vendor:sdl2/mixer"
|
||||
import TTF "vendor:sdl2/ttf"
|
||||
|
||||
import vk "vendor:vulkan"
|
||||
import vk "vendor:vulkan"
|
||||
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
import NS "vendor:darwin/Foundation"
|
||||
import MTL "vendor:darwin/Metal"
|
||||
import CA "vendor:darwin/QuartzCore"
|
||||
|
||||
_ :: botan
|
||||
_ :: ENet
|
||||
@@ -33,12 +33,15 @@ _ :: miniaudio
|
||||
_ :: PM
|
||||
_ :: rl
|
||||
_ :: exr
|
||||
|
||||
_ :: SDL
|
||||
_ :: SDLNet
|
||||
_ :: IMG
|
||||
_ :: MIX
|
||||
_ :: TTF
|
||||
|
||||
_ :: vk
|
||||
|
||||
_ :: NS
|
||||
_ :: MTL
|
||||
_ :: CA
|
||||
_ :: CA
|
||||
@@ -0,0 +1,5 @@
|
||||
//+build windows, linux
|
||||
package all
|
||||
|
||||
import cm "vendor:commonmark"
|
||||
_ :: cm
|
||||
@@ -0,0 +1,5 @@
|
||||
//+build windows, linux
|
||||
package all
|
||||
|
||||
import zlib "vendor:zlib"
|
||||
_ :: zlib
|
||||
+644
-318
File diff suppressed because it is too large
Load Diff
+87
-5
@@ -225,6 +225,7 @@ struct BuildContext {
|
||||
String ODIN_VENDOR; // compiler vendor
|
||||
String ODIN_VERSION; // compiler version
|
||||
String ODIN_ROOT; // Odin ROOT
|
||||
String ODIN_BUILD_PROJECT_NAME; // Odin main/initial package's directory name
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
|
||||
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
|
||||
@@ -830,10 +831,73 @@ String internal_odin_root_dir(void) {
|
||||
gb_mfree(argv);
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
// copy argv[0] to path_buf
|
||||
|
||||
// NOTE(Jeroen):
|
||||
// On OpenBSD, if `odin` is on the path, `argv[0]` will contain just `odin`,
|
||||
// even though that isn't then the relative path.
|
||||
// When run from Odin's directory, it returns `./odin`.
|
||||
// Check argv[0] for lack of / to see if it's a reference to PATH.
|
||||
// If so, walk PATH to find the executable.
|
||||
|
||||
len = gb_strlen(argv[0]);
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], argv[0], len);
|
||||
|
||||
bool slash_found = false;
|
||||
bool odin_found = false;
|
||||
|
||||
for (int i = 0; i < len; i += 1) {
|
||||
if (argv[0][i] == '/') {
|
||||
slash_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (slash_found) {
|
||||
// copy argv[0] to path_buf
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], argv[0], len);
|
||||
odin_found = true;
|
||||
}
|
||||
} else {
|
||||
gbAllocator a = heap_allocator();
|
||||
char const *path_env = gb_get_env("PATH", a);
|
||||
defer (gb_free(a, cast(void *)path_env));
|
||||
|
||||
if (path_env) {
|
||||
int path_len = gb_strlen(path_env);
|
||||
int path_start = 0;
|
||||
int path_end = 0;
|
||||
|
||||
for (; path_start < path_len; ) {
|
||||
for (; path_end <= path_len; path_end++) {
|
||||
if (path_env[path_end] == ':' || path_end == path_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
String path_needle = (const String)make_string((const u8 *)(path_env + path_start), path_end - path_start);
|
||||
String argv0 = (const String)make_string((const u8 *)argv[0], len);
|
||||
String odin_candidate = concatenate3_strings(a, path_needle, STR_LIT("/"), argv0);
|
||||
defer (gb_free(a, odin_candidate.text));
|
||||
|
||||
if (gb_file_exists((const char *)odin_candidate.text)) {
|
||||
len = odin_candidate.len;
|
||||
if(len < path_buf.count) {
|
||||
gb_memmove(&path_buf[0], odin_candidate.text, len);
|
||||
}
|
||||
odin_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
path_start = path_end + 1;
|
||||
path_end = path_start;
|
||||
if (path_start > path_len) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!odin_found) {
|
||||
gb_printf_err("Odin could not locate itself in PATH, and ODIN_ROOT wasn't set either.\n");
|
||||
}
|
||||
}
|
||||
gb_mfree(argv);
|
||||
#endif
|
||||
@@ -922,6 +986,15 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
gb_memmove(str+i, path.text, path.len); i += path.len;
|
||||
str[i] = 0;
|
||||
|
||||
// IMPORTANT NOTE(bill): Remove trailing path separators
|
||||
// this is required to make sure there is a conventional
|
||||
// notation for the path
|
||||
for (/**/; i > 0; i--) {
|
||||
u8 c = str[i-1];
|
||||
if (c != '/' && c != '\\') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
String res = make_string(str, i);
|
||||
res = string_trim_whitespace(res);
|
||||
@@ -1238,13 +1311,16 @@ void enable_target_feature(TokenPos pos, String const &target_feature_list) {
|
||||
defer (mutex_unlock(&bc->target_features_mutex));
|
||||
|
||||
auto items = split_by_comma(target_feature_list);
|
||||
array_free(&items);
|
||||
for_array(i, items) {
|
||||
String const &item = items.data[i];
|
||||
if (!check_target_feature_is_valid(pos, item)) {
|
||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||
continue;
|
||||
}
|
||||
|
||||
string_set_add(&bc->target_features_set, item);
|
||||
}
|
||||
array_free(&items);
|
||||
}
|
||||
|
||||
|
||||
@@ -1267,7 +1343,7 @@ char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quot
|
||||
|
||||
if (with_quotes) features[len++] = '"';
|
||||
String feature = build_context.target_features_set.entries[i].value;
|
||||
gb_memmove(features, feature.text, feature.len);
|
||||
gb_memmove(features + len, feature.text, feature.len);
|
||||
len += feature.len;
|
||||
if (with_quotes) features[len++] = '"';
|
||||
}
|
||||
@@ -1291,6 +1367,12 @@ bool init_build_paths(String init_filename) {
|
||||
// [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
|
||||
bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename);
|
||||
|
||||
{
|
||||
String build_project_name = last_path_element(bc->build_paths[BuildPath_Main_Package].basename);
|
||||
GB_ASSERT(build_project_name.len > 0);
|
||||
bc->ODIN_BUILD_PROJECT_NAME = build_project_name;
|
||||
}
|
||||
|
||||
bool produces_output_file = false;
|
||||
if (bc->command_kind == Command_doc && bc->cmd_doc_flags & CmdDocFlag_DocFormat) {
|
||||
produces_output_file = true;
|
||||
|
||||
+157
-15
@@ -1614,6 +1614,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc_type_info_of:
|
||||
case BuiltinProc_typeid_of:
|
||||
case BuiltinProc_len:
|
||||
case BuiltinProc_cap:
|
||||
case BuiltinProc_min:
|
||||
case BuiltinProc_max:
|
||||
case BuiltinProc_type_is_subtype_of:
|
||||
@@ -1696,16 +1697,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
return check_builtin_procedure_directive(c, operand, call, type_hint);
|
||||
|
||||
case BuiltinProc_len:
|
||||
check_expr_or_type(c, operand, ce->args[0]);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
/* fallthrough */
|
||||
|
||||
case BuiltinProc_cap:
|
||||
{
|
||||
// len :: proc(Type) -> int
|
||||
// cap :: proc(Type) -> int
|
||||
check_expr_or_type(c, operand, ce->args[0]);
|
||||
if (operand->mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *op_type = type_deref(operand->type);
|
||||
Type *type = t_int;
|
||||
@@ -1749,11 +1748,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
mode = Addressing_Value;
|
||||
} else if (is_type_map(op_type)) {
|
||||
mode = Addressing_Value;
|
||||
} else if (operand->mode == Addressing_Type && is_type_enum(op_type) && id == BuiltinProc_len) {
|
||||
} else if (operand->mode == Addressing_Type && is_type_enum(op_type)) {
|
||||
Type *bt = base_type(op_type);
|
||||
mode = Addressing_Constant;
|
||||
value = exact_value_i64(bt->Enum.fields.count);
|
||||
type = t_untyped_integer;
|
||||
mode = Addressing_Constant;
|
||||
type = t_untyped_integer;
|
||||
if (id == BuiltinProc_len) {
|
||||
value = exact_value_i64(bt->Enum.fields.count);
|
||||
} else {
|
||||
GB_ASSERT(id == BuiltinProc_cap);
|
||||
value = exact_value_sub(*bt->Enum.max_value, *bt->Enum.min_value);
|
||||
value = exact_value_increment_one(value);
|
||||
}
|
||||
} else if (is_type_struct(op_type)) {
|
||||
Type *bt = base_type(op_type);
|
||||
if (bt->Struct.soa_kind == StructSoa_Fixed) {
|
||||
@@ -1899,6 +1904,21 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *bt = base_type(type);
|
||||
if (bt->kind == Type_Struct && bt->Struct.scope != nullptr) {
|
||||
if (is_type_polymorphic(bt)) {
|
||||
gbString t = type_to_string(type);
|
||||
error(field_arg, "Cannot use '%.*s' on an unspecialized polymorphic struct type, got '%s'", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
} else if (bt->Struct.fields.count == 0 && bt->Struct.node == nullptr) {
|
||||
gbString t = type_to_string(type);
|
||||
error(field_arg, "Cannot use '%.*s' on incomplete struct declaration, got '%s'", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(type, field_name, false);
|
||||
if (sel.entity == nullptr) {
|
||||
@@ -3665,8 +3685,92 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
gb_string_free(xts);
|
||||
}
|
||||
|
||||
Type *type = default_type(x.type);
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = default_type(x.type);
|
||||
operand->type = type;
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// make runtime only for the time being
|
||||
} else if (x.mode == Addressing_Constant && x.value.kind == ExactValue_Integer) {
|
||||
convert_to_typed(c, &x, type);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ExactValue res = {};
|
||||
|
||||
i64 sz = type_size_of(x.type);
|
||||
u64 bit_size = sz*8;
|
||||
u64 rop64[4] = {}; // 2 u64 is the maximum we will ever need, so doubling it will ne fine
|
||||
u8 *rop = cast(u8 *)rop64;
|
||||
|
||||
size_t max_count = 0;
|
||||
size_t written = 0;
|
||||
size_t size = 1;
|
||||
size_t nails = 0;
|
||||
mp_endian endian = MP_LITTLE_ENDIAN;
|
||||
|
||||
max_count = mp_pack_count(&x.value.value_integer, nails, size);
|
||||
GB_ASSERT(sz >= cast(i64)max_count);
|
||||
|
||||
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||
GB_ASSERT(err == MP_OKAY);
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// TODO(bill): Should this even be allowed at compile time?
|
||||
} else {
|
||||
u64 v = 0;
|
||||
switch (id) {
|
||||
case BuiltinProc_count_ones:
|
||||
case BuiltinProc_count_zeros:
|
||||
switch (sz) {
|
||||
case 1: v = bit_set_count(cast(u32)rop[0]); break;
|
||||
case 2: v = bit_set_count(cast(u32)*(u16 *)rop); break;
|
||||
case 4: v = bit_set_count(*(u32 *)rop); break;
|
||||
case 8: v = bit_set_count(rop64[0]); break;
|
||||
case 16:
|
||||
v += bit_set_count(rop64[0]);
|
||||
v += bit_set_count(rop64[1]);
|
||||
break;
|
||||
default: GB_PANIC("Unhandled sized");
|
||||
}
|
||||
if (id == BuiltinProc_count_zeros) {
|
||||
// flip the result
|
||||
v = bit_size - v;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_trailing_zeros:
|
||||
for (u64 i = 0; i < bit_size; i++) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_count_leading_zeros:
|
||||
for (u64 i = bit_size-1; i < bit_size; i--) {
|
||||
u8 b = cast(u8)(i & 7);
|
||||
u8 j = cast(u8)(i >> 3);
|
||||
if (rop[j] & (1 << b)) {
|
||||
break;
|
||||
}
|
||||
v += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
res = exact_value_u64(v);
|
||||
}
|
||||
|
||||
if (res.kind != ExactValue_Invalid) {
|
||||
operand->mode = Addressing_Constant;
|
||||
operand->value = res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -4613,6 +4717,47 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_convert_variants_to_pointers:
|
||||
if (operand->mode != Addressing_Type) {
|
||||
error(operand->expr, "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
} else {
|
||||
Type *bt = base_type(operand->type);
|
||||
if (is_type_polymorphic(bt)) {
|
||||
// IGNORE polymorphic types
|
||||
return true;
|
||||
} else if (bt->kind != Type_Union) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Expected a union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
} else if (bt->Union.is_polymorphic) {
|
||||
gbString t = type_to_string(operand->type);
|
||||
error(operand->expr, "Expected a non-polymorphic union type for '%.*s', got %s", LIT(builtin_name), t);
|
||||
gb_string_free(t);
|
||||
|
||||
operand->mode = Addressing_Invalid;
|
||||
operand->type = t_invalid;
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *new_type = alloc_type_union();
|
||||
auto variants = slice_make<Type *>(permanent_allocator(), bt->Union.variants.count);
|
||||
for_array(i, bt->Union.variants) {
|
||||
variants[i] = alloc_type_pointer(bt->Union.variants[i]);
|
||||
}
|
||||
new_type->Union.variants = variants;
|
||||
|
||||
// NOTE(bill): Is this even correct?
|
||||
new_type->Union.node = operand->expr;
|
||||
new_type->Union.scope = bt->Union.scope;
|
||||
|
||||
operand->type = new_type;
|
||||
}
|
||||
operand->mode = Addressing_Type;
|
||||
break;
|
||||
|
||||
case BuiltinProc_type_is_boolean:
|
||||
case BuiltinProc_type_is_integer:
|
||||
@@ -5398,10 +5543,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
case BuiltinProc_valgrind_client_request:
|
||||
{
|
||||
if (!is_arch_x86()) {
|
||||
error(call, "'%.*s' is only allowed on x86 targets (i386, amd64)", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
// NOTE(bill): Check it but make it a no-op for non x86 (i386, amd64) targets
|
||||
|
||||
enum {ARG_COUNT = 7};
|
||||
GB_ASSERT(builtin_procs[BuiltinProc_valgrind_client_request].arg_count == ARG_COUNT);
|
||||
|
||||
+80
-12
@@ -1060,6 +1060,8 @@ void check_assignment(CheckerContext *c, Operand *operand, Type *type, String co
|
||||
type_extra = gb_string_append_fmt(type_extra, " (package %.*s)", LIT(type_pkg->name));
|
||||
}
|
||||
}
|
||||
|
||||
ERROR_BLOCK();
|
||||
error(operand->expr,
|
||||
"Cannot assign value '%s' of type '%s%s' to '%s%s' in %.*s",
|
||||
expr_str,
|
||||
@@ -1143,6 +1145,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->Pointer.elem, true, modify_type);
|
||||
} else if (source->kind == Type_MultiPointer) {
|
||||
isize level = check_is_assignable_to_using_subtype(source->MultiPointer.elem, poly->Pointer.elem);
|
||||
if (level > 0) {
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->Pointer.elem, source->MultiPointer.elem, true, modify_type);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1153,6 +1161,12 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->MultiPointer.elem, true, modify_type);
|
||||
} else if (source->kind == Type_Pointer) {
|
||||
isize level = check_is_assignable_to_using_subtype(source->Pointer.elem, poly->MultiPointer.elem);
|
||||
if (level > 0) {
|
||||
return true;
|
||||
}
|
||||
return is_polymorphic_type_assignable(c, poly->MultiPointer.elem, source->Pointer.elem, true, modify_type);
|
||||
}
|
||||
return false;
|
||||
case Type_Array:
|
||||
@@ -1348,7 +1362,13 @@ bool is_polymorphic_type_assignable(CheckerContext *c, Type *poly, Type *source,
|
||||
if (source->kind == Type_Map) {
|
||||
bool key = is_polymorphic_type_assignable(c, poly->Map.key, source->Map.key, true, modify_type);
|
||||
bool value = is_polymorphic_type_assignable(c, poly->Map.value, source->Map.value, true, modify_type);
|
||||
return key || value;
|
||||
if (key || value) {
|
||||
poly->Map.entry_type = nullptr;
|
||||
poly->Map.internal_type = nullptr;
|
||||
poly->Map.lookup_result_type = nullptr;
|
||||
init_map_internal_types(poly);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -1965,10 +1985,18 @@ void check_assignment_error_suggestion(CheckerContext *c, Operand *o, Type *type
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
} else if (are_types_identical(src, dst)) {
|
||||
} else if (is_type_dynamic_array(src) && is_type_slice(dst)) {
|
||||
Type *s = src->DynamicArray.elem;
|
||||
Type *d = dst->Slice.elem;
|
||||
if (are_types_identical(s, d)) {
|
||||
error_line("\tSuggestion: the dynamic array expression may be sliced with %s[:]\n", a);
|
||||
}
|
||||
}else if (are_types_identical(src, dst) && !are_types_identical(o->type, type)) {
|
||||
error_line("\tSuggestion: the expression may be directly casted to type %s\n", b);
|
||||
} else if (are_types_identical(src, t_string) && is_type_u8_slice(dst)) {
|
||||
error_line("\tSuggestion: a string may be transmuted to %s\n", b);
|
||||
error_line("\t This is an UNSAFE operation as string data is assumed to be immutable, \n");
|
||||
error_line("\t whereas slices in general are assumed to be mutable.\n");
|
||||
} else if (is_type_u8_slice(src) && are_types_identical(dst, t_string)) {
|
||||
error_line("\tSuggestion: the expression may be casted to %s\n", b);
|
||||
}
|
||||
@@ -2028,7 +2056,9 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
|
||||
gbString a = expr_to_string(o->expr);
|
||||
gbString b = type_to_string(type);
|
||||
gbString c = type_to_string(o->type);
|
||||
gbString s = exact_value_to_string(o->value);
|
||||
defer(
|
||||
gb_string_free(s);
|
||||
gb_string_free(c);
|
||||
gb_string_free(b);
|
||||
gb_string_free(a);
|
||||
@@ -2037,13 +2067,15 @@ bool check_is_expressible(CheckerContext *ctx, Operand *o, Type *type) {
|
||||
|
||||
if (is_type_numeric(o->type) && is_type_numeric(type)) {
|
||||
if (!is_type_integer(o->type) && is_type_integer(type)) {
|
||||
error(o->expr, "'%s' truncated to '%s'", a, b);
|
||||
error(o->expr, "'%s' truncated to '%s', got %s", a, b, s);
|
||||
} else {
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s", a, b, c);
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert numeric value '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
} else {
|
||||
error(o->expr, "Cannot convert '%s' to '%s' from '%s", a, b, c);
|
||||
ERROR_BLOCK();
|
||||
error(o->expr, "Cannot convert '%s' to '%s' from '%s', got %s", a, b, c, s);
|
||||
check_assignment_error_suggestion(ctx, o, type);
|
||||
}
|
||||
return false;
|
||||
@@ -3039,8 +3071,8 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
x->type = xt;
|
||||
goto matrix_success;
|
||||
} else {
|
||||
GB_ASSERT(is_type_matrix(yt));
|
||||
GB_ASSERT(!is_type_matrix(xt));
|
||||
GB_ASSERT(is_type_matrix(yt));
|
||||
|
||||
if (op.kind == Token_Mul) {
|
||||
// NOTE(bill): no need to handle the matrix case here since it should be handled above
|
||||
@@ -3061,6 +3093,9 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
|
||||
x->type = alloc_type_matrix(yt->Matrix.elem, 1, yt->Matrix.column_count);
|
||||
}
|
||||
goto matrix_success;
|
||||
} else if (are_types_identical(yt->Matrix.elem, xt)) {
|
||||
x->type = check_matrix_type_hint(y->type, type_hint);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!are_types_identical(xt, yt)) {
|
||||
@@ -3901,7 +3936,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
}
|
||||
} else if (!is_type_integer(operand.type) && !is_type_enum(operand.type)) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' must be an integer", expr_str);
|
||||
gbString type_str = type_to_string(operand.type);
|
||||
error(operand.expr, "Index '%s' must be an integer, got %s", expr_str, type_str);
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(expr_str);
|
||||
if (value) *value = 0;
|
||||
return false;
|
||||
@@ -3911,8 +3948,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
(c->state_flags & StateFlag_no_bounds_check) == 0) {
|
||||
BigInt i = exact_value_to_integer(operand.value).value_integer;
|
||||
if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) {
|
||||
String idx_str = big_int_to_string(temporary_allocator(), &i);
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
|
||||
error(operand.expr, "Index '%s' cannot be a negative value, got %.*s", expr_str, LIT(idx_str));
|
||||
gb_string_free(expr_str);
|
||||
if (value) *value = 0;
|
||||
return false;
|
||||
@@ -3943,7 +3981,7 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
if (out_of_bounds) {
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
if (lo_str.len > 0) {
|
||||
error(operand.expr, "Index '%s' is out of bounds range %.*s .. %.*s", expr_str, LIT(lo_str), LIT(hi_str));
|
||||
error(operand.expr, "Index '%s' is out of bounds range %.*s ..= %.*s", expr_str, LIT(lo_str), LIT(hi_str));
|
||||
} else {
|
||||
gbString index_type_str = type_to_string(index_type);
|
||||
error(operand.expr, "Index '%s' is out of bounds range of enum type %s", expr_str, index_type_str);
|
||||
@@ -3973,8 +4011,9 @@ bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast
|
||||
}
|
||||
|
||||
if (out_of_bounds) {
|
||||
String idx_str = big_int_to_string(temporary_allocator(), &i);
|
||||
gbString expr_str = expr_to_string(operand.expr);
|
||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld", expr_str, max_count);
|
||||
error(operand.expr, "Index '%s' is out of bounds range 0..<%lld, got %.*s", expr_str, max_count, LIT(idx_str));
|
||||
gb_string_free(expr_str);
|
||||
return false;
|
||||
}
|
||||
@@ -4019,6 +4058,7 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
|
||||
|
||||
if (cl->elems[0]->kind == Ast_FieldValue) {
|
||||
if (is_type_struct(node->tav.type)) {
|
||||
bool found = false;
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
if (elem->kind != Ast_FieldValue) {
|
||||
@@ -4030,9 +4070,14 @@ ExactValue get_constant_field_single(CheckerContext *c, ExactValue value, i32 in
|
||||
defer (array_free(&sub_sel.index));
|
||||
if (sub_sel.index[0] == index) {
|
||||
value = fv->value->tav.value;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Use the zero value if it is not found
|
||||
value = {};
|
||||
}
|
||||
} else if (is_type_array(node->tav.type) || is_type_enumerated_array(node->tav.type)) {
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
@@ -4674,7 +4719,7 @@ Entity *check_selector(CheckerContext *c, Operand *operand, Ast *node, Type *typ
|
||||
|
||||
switch (entity->kind) {
|
||||
case Entity_Constant:
|
||||
operand->value = entity->Constant.value;
|
||||
operand->value = entity->Constant.value;
|
||||
operand->mode = Addressing_Constant;
|
||||
if (operand->value.kind == ExactValue_Procedure) {
|
||||
Entity *proc = strip_entity_wrapping(operand->value.value_procedure);
|
||||
@@ -7359,6 +7404,14 @@ ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *t
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.mode == Addressing_Type || y.mode == Addressing_Type) {
|
||||
Ast *type_expr = (x.mode == Addressing_Type) ? x.expr : y.expr;
|
||||
gbString type_string = expr_to_string(type_expr);
|
||||
error(node, "Type %s is invalid operand for ternary if expression", type_string);
|
||||
gb_string_free(type_string);
|
||||
return kind;
|
||||
}
|
||||
|
||||
if (x.type == nullptr || x.type == t_invalid ||
|
||||
y.type == nullptr || y.type == t_invalid) {
|
||||
return kind;
|
||||
@@ -7395,6 +7448,7 @@ ExprKind check_ternary_if_expr(CheckerContext *c, Operand *o, Ast *node, Type *t
|
||||
check_cast_internal(c, &y, type_hint)) {
|
||||
convert_to_typed(c, o, type_hint);
|
||||
update_untyped_expr_type(c, node, type_hint, !is_type_untyped(type_hint));
|
||||
o->type = type_hint;
|
||||
}
|
||||
}
|
||||
return kind;
|
||||
@@ -9052,7 +9106,20 @@ ExprKind check_slice_expr(CheckerContext *c, Operand *o, Ast *node, Type *type_h
|
||||
o->type = t->RelativeSlice.slice_type;
|
||||
if (o->mode != Addressing_Variable) {
|
||||
gbString str = expr_to_string(node);
|
||||
error(node, "Cannot relative slice '%s', value is not addressable", str);
|
||||
error(node, "Cannot relative slice '%s', as value is not addressable", str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
return kind;
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_EnumeratedArray:
|
||||
{
|
||||
gbString str = expr_to_string(o->expr);
|
||||
gbString type_str = type_to_string(o->type);
|
||||
error(o->expr, "Cannot slice '%s' of type '%s', as enumerated arrays cannot be sliced", str, type_str);
|
||||
gb_string_free(type_str);
|
||||
gb_string_free(str);
|
||||
o->mode = Addressing_Invalid;
|
||||
o->expr = node;
|
||||
@@ -9574,6 +9641,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
||||
case Ast_MapType:
|
||||
case Ast_BitSetType:
|
||||
case Ast_MatrixType:
|
||||
case Ast_RelativeType:
|
||||
o->mode = Addressing_Type;
|
||||
o->type = check_type(c, node);
|
||||
break;
|
||||
|
||||
+6
-7
@@ -1397,10 +1397,11 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) {
|
||||
}
|
||||
|
||||
bool check_expr_is_stack_variable(Ast *expr) {
|
||||
/*
|
||||
expr = unparen_expr(expr);
|
||||
Entity *e = entity_of_node(expr);
|
||||
if (e && e->kind == Entity_Variable) {
|
||||
if (e->flags & (EntityFlag_Static|EntityFlag_Using)) {
|
||||
if (e->flags & (EntityFlag_Static|EntityFlag_Using|EntityFlag_ImplicitReference|EntityFlag_ForValue)) {
|
||||
// okay
|
||||
} else if (e->Variable.thread_local_model.len != 0) {
|
||||
// okay
|
||||
@@ -1410,6 +1411,7 @@ bool check_expr_is_stack_variable(Ast *expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1941,13 +1943,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
if (found == nullptr) {
|
||||
entity = alloc_entity_variable(ctx->scope, token, type, EntityState_Resolved);
|
||||
entity->flags |= EntityFlag_ForValue;
|
||||
entity->flags |= EntityFlag_Value;
|
||||
if (i == addressable_index) {
|
||||
if (use_by_reference_for_value) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
} else {
|
||||
entity->flags |= EntityFlag_ForValue;
|
||||
}
|
||||
if (i == addressable_index && use_by_reference_for_value) {
|
||||
entity->flags &= ~EntityFlag_Value;
|
||||
}
|
||||
if (is_soa) {
|
||||
if (i == 0) {
|
||||
|
||||
+13
-14
@@ -1643,8 +1643,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
bool valid = false;
|
||||
if (is_type_proc(op.type)) {
|
||||
Entity *proc_entity = entity_from_expr(op.expr);
|
||||
valid = proc_entity != nullptr;
|
||||
poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr);
|
||||
valid = (proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure);
|
||||
if (valid) {
|
||||
poly_const = exact_value_procedure(proc_entity->identifier.load() ? proc_entity->identifier.load() : op.expr);
|
||||
}
|
||||
}
|
||||
if (!valid) {
|
||||
if (op.mode == Addressing_Constant) {
|
||||
@@ -2004,22 +2006,21 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pt->tags & ProcTag_optional_second) {
|
||||
if (pt->tags & ProcTag_optional_allocator_error) {
|
||||
if (optional_ok) {
|
||||
error(proc_type_node, "A procedure type cannot have both an #optional_ok tag and #optional_second");
|
||||
error(proc_type_node, "A procedure type cannot have both an #optional_ok tag and #optional_allocator_error");
|
||||
}
|
||||
optional_ok = true;
|
||||
if (result_count != 2) {
|
||||
error(proc_type_node, "A procedure type with the #optional_second tag requires 2 return values, got %td", result_count);
|
||||
error(proc_type_node, "A procedure type with the #optional_allocator_error tag requires 2 return values, got %td", result_count);
|
||||
} else {
|
||||
bool ok = false;
|
||||
AstFile *file = proc_type_node->file();
|
||||
if (file && file->pkg) {
|
||||
ok = file->pkg->scope == ctx->info->runtime_package->scope;
|
||||
}
|
||||
init_mem_allocator(c->checker);
|
||||
|
||||
if (!ok) {
|
||||
error(proc_type_node, "A procedure type with the #optional_second may only be allowed within 'package runtime'");
|
||||
Type *type = results->Tuple.variables[1]->type;
|
||||
if (!are_types_identical(type, t_allocator_error)) {
|
||||
gbString t = type_to_string(type);
|
||||
error(proc_type_node, "A procedure type with the #optional_allocator_error expects a `runtime.Allocator_Error`, got '%s'", t);
|
||||
gb_string_free(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2210,7 +2211,6 @@ void init_map_internal_types(Type *type) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
init_map_entry_type(type);
|
||||
if (type->Map.internal_type != nullptr) return;
|
||||
if (type->Map.generated_struct_type != nullptr) return;
|
||||
|
||||
Type *key = type->Map.key;
|
||||
Type *value = type->Map.value;
|
||||
@@ -2238,7 +2238,6 @@ void init_map_internal_types(Type *type) {
|
||||
generated_struct_type->Struct.fields = fields;
|
||||
type_set_offsets(generated_struct_type);
|
||||
|
||||
type->Map.generated_struct_type = generated_struct_type;
|
||||
type->Map.internal_type = generated_struct_type;
|
||||
type->Map.lookup_result_type = make_optional_ok_type(value);
|
||||
}
|
||||
|
||||
+10
-29
@@ -938,6 +938,7 @@ void init_universal(void) {
|
||||
add_global_string_constant("ODIN_VENDOR", bc->ODIN_VENDOR);
|
||||
add_global_string_constant("ODIN_VERSION", bc->ODIN_VERSION);
|
||||
add_global_string_constant("ODIN_ROOT", bc->ODIN_ROOT);
|
||||
add_global_string_constant("ODIN_BUILD_PROJECT_NAME", bc->ODIN_BUILD_PROJECT_NAME);
|
||||
|
||||
{
|
||||
GlobalEnumValue values[TargetOs_COUNT] = {
|
||||
@@ -1921,7 +1922,7 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
||||
init_map_internal_types(bt);
|
||||
add_type_info_type_internal(c, bt->Map.key);
|
||||
add_type_info_type_internal(c, bt->Map.value);
|
||||
add_type_info_type_internal(c, bt->Map.generated_struct_type);
|
||||
add_type_info_type_internal(c, bt->Map.internal_type);
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -2143,7 +2144,7 @@ void add_min_dep_type_info(Checker *c, Type *t) {
|
||||
init_map_internal_types(bt);
|
||||
add_min_dep_type_info(c, bt->Map.key);
|
||||
add_min_dep_type_info(c, bt->Map.value);
|
||||
add_min_dep_type_info(c, bt->Map.generated_struct_type);
|
||||
add_min_dep_type_info(c, bt->Map.internal_type);
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
@@ -2808,17 +2809,9 @@ void init_mem_allocator(Checker *c) {
|
||||
if (t_allocator != nullptr) {
|
||||
return;
|
||||
}
|
||||
AstPackage *pkg = get_core_package(&c->info, str_lit("runtime"));
|
||||
|
||||
String name = str_lit("Allocator");
|
||||
Entity *e = scope_lookup_current(pkg->scope, name);
|
||||
if (e == nullptr) {
|
||||
compiler_error("Could not find type declaration for '%.*s'\n", LIT(name));
|
||||
// NOTE(bill): This will exit the program as it's cannot continue without it!
|
||||
}
|
||||
|
||||
t_allocator = e->type;
|
||||
t_allocator = find_core_type(c, str_lit("Allocator"));
|
||||
t_allocator_ptr = alloc_type_pointer(t_allocator);
|
||||
t_allocator_error = find_core_type(c, str_lit("Allocator_Error"));
|
||||
}
|
||||
|
||||
void init_core_context(Checker *c) {
|
||||
@@ -2826,7 +2819,6 @@ void init_core_context(Checker *c) {
|
||||
return;
|
||||
}
|
||||
t_context = find_core_type(c, str_lit("Context"));
|
||||
GB_ASSERT(t_context != nullptr);
|
||||
t_context_ptr = alloc_type_pointer(t_context);
|
||||
}
|
||||
|
||||
@@ -2839,23 +2831,12 @@ void init_core_source_code_location(Checker *c) {
|
||||
}
|
||||
|
||||
void init_core_map_type(Checker *c) {
|
||||
if (t_map_hash == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Hash"));
|
||||
if (e->state == EntityState_Unresolved) {
|
||||
check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
|
||||
}
|
||||
t_map_hash = e->type;
|
||||
GB_ASSERT(t_map_hash != nullptr);
|
||||
}
|
||||
|
||||
if (t_map_header == nullptr) {
|
||||
Entity *e = find_core_entity(c, str_lit("Map_Header"));
|
||||
if (e->state == EntityState_Unresolved) {
|
||||
check_entity_decl(&c->builtin_ctx, e, nullptr, nullptr);
|
||||
}
|
||||
t_map_header = e->type;
|
||||
GB_ASSERT(t_map_header != nullptr);
|
||||
if (t_map_hash != nullptr) {
|
||||
return;
|
||||
}
|
||||
t_map_hash = find_core_type(c, str_lit("Map_Hash"));
|
||||
t_map_header = find_core_type(c, str_lit("Map_Header"));
|
||||
t_map_header_table = find_core_type(c, str_lit("Map_Header_Table"));
|
||||
}
|
||||
|
||||
void init_preload(Checker *c) {
|
||||
|
||||
@@ -200,6 +200,8 @@ BuiltinProc__type_begin,
|
||||
BuiltinProc_type_core_type,
|
||||
BuiltinProc_type_elem_type,
|
||||
|
||||
BuiltinProc_type_convert_variants_to_pointers,
|
||||
|
||||
BuiltinProc__type_simple_boolean_begin,
|
||||
BuiltinProc_type_is_boolean,
|
||||
BuiltinProc_type_is_integer,
|
||||
@@ -492,6 +494,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
{STR_LIT("type_base_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_core_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_elem_type"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_convert_variants_to_pointers"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
{STR_LIT(""), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("type_is_boolean"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
|
||||
@@ -38,6 +38,10 @@ i64 next_pow2(i64 n);
|
||||
isize next_pow2_isize(isize n);
|
||||
void debugf(char const *fmt, ...);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS) && defined(GB_ARCH_32_BIT)
|
||||
#error Odin on Windows requires a 64-bit build-system. The 'Developer Command Prompt' for VS still defaults to 32-bit shell. The 64-bit shell can be found under the name 'x64 Native Tools Command Prompt' for VS. For more information, please see https://odin-lang.org/docs/install/#for-windows
|
||||
#endif
|
||||
|
||||
#include "threading.cpp"
|
||||
#include "unicode.cpp"
|
||||
#include "array.cpp"
|
||||
|
||||
+1
-1
@@ -639,7 +639,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
doc_type.polmorphic_params = odin_doc_type(w, type->Union.polymorphic_params);
|
||||
}
|
||||
|
||||
if (type->Union.node) {
|
||||
if (type->Union.node && type->Union.node->kind == Ast_UnionType) {
|
||||
ast_node(ut, UnionType, type->Union.node);
|
||||
if (ut->align) {
|
||||
doc_type.custom_align = odin_doc_expr_string(w, ut->align);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#include <math.h>
|
||||
|
||||
// TODO(bill): Big numbers
|
||||
// IMPORTANT TODO(bill): This needs to be completely fixed!!!!!!!!
|
||||
|
||||
gb_global BlockingMutex hash_exact_value_mutex;
|
||||
|
||||
struct Ast;
|
||||
|
||||
+83
-52
@@ -500,52 +500,51 @@ lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, A
|
||||
return value;
|
||||
}
|
||||
|
||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type) {
|
||||
GB_ASSERT_MSG(is_type_pointer(map_val_ptr.type), "%s", type_to_string(map_val_ptr.type));
|
||||
lbAddr h = lb_add_local_generated(p, t_map_header, false); // all the values will be initialzed later
|
||||
lbValue lb_gen_map_header_table_internal(lbProcedure *p, Type *map_type) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
map_type = base_type(map_type);
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
|
||||
Type *key_type = map_type->Map.key;
|
||||
Type *val_type = map_type->Map.value;
|
||||
gb_unused(val_type);
|
||||
lbAddr *found = map_get(&m->map_header_table_map, map_type);
|
||||
if (found) {
|
||||
return lb_addr_load(p, *found);
|
||||
}
|
||||
|
||||
GB_ASSERT(map_type->Map.entry_type->kind == Type_Struct);
|
||||
map_type->Map.entry_type->cached_size = -1;
|
||||
map_type->Map.entry_type->Struct.are_offsets_set = false;
|
||||
|
||||
i64 entry_size = type_size_of (map_type->Map.entry_type);
|
||||
i64 entry_align = type_align_of (map_type->Map.entry_type);
|
||||
|
||||
|
||||
i64 key_offset = type_offset_of(map_type->Map.entry_type, 2);
|
||||
i64 key_size = type_size_of (map_type->Map.key);
|
||||
|
||||
i64 value_offset = type_offset_of(map_type->Map.entry_type, 3);
|
||||
i64 value_size = type_size_of (map_type->Map.value);
|
||||
|
||||
|
||||
Type *map_header_base = base_type(t_map_header);
|
||||
GB_ASSERT(map_header_base->Struct.fields.count == 8);
|
||||
Type *raw_map_ptr_type = map_header_base->Struct.fields[0]->type;
|
||||
LLVMValueRef const_values[8] = {};
|
||||
const_values[0] = LLVMConstNull(lb_type(p->module, raw_map_ptr_type));
|
||||
const_values[1] = lb_get_equal_proc_for_type(p->module, key_type) .value;
|
||||
const_values[2] = lb_const_int(p->module, t_int, entry_size) .value;
|
||||
const_values[3] = lb_const_int(p->module, t_int, entry_align) .value;
|
||||
const_values[4] = lb_const_int(p->module, t_uintptr, key_offset) .value;
|
||||
const_values[5] = lb_const_int(p->module, t_int, key_size) .value;
|
||||
const_values[6] = lb_const_int(p->module, t_uintptr, value_offset).value;
|
||||
const_values[7] = lb_const_int(p->module, t_int, value_size) .value;
|
||||
|
||||
LLVMValueRef const_value = llvm_const_named_struct(p->module, t_map_header, const_values, gb_count_of(const_values));
|
||||
LLVMBuildStore(p->builder, const_value, h.addr.value);
|
||||
|
||||
// NOTE(bill): Removes unnecessary allocation if split gep
|
||||
lbValue gep0 = lb_emit_struct_ep(p, h.addr, 0);
|
||||
lbValue m = lb_emit_conv(p, map_val_ptr, type_deref(gep0.type));
|
||||
lb_emit_store(p, gep0, m);
|
||||
|
||||
return lb_addr_load(p, h);
|
||||
Type *key_type = map_type->Map.key;
|
||||
Type *val_type = map_type->Map.value;
|
||||
gb_unused(val_type);
|
||||
|
||||
Type *st = base_type(t_map_header_table);
|
||||
GB_ASSERT(st->Struct.fields.count == 7);
|
||||
|
||||
LLVMValueRef const_values[7] = {};
|
||||
const_values[0] = lb_get_equal_proc_for_type(m, key_type) .value;
|
||||
const_values[1] = lb_const_int(m, t_int, entry_size) .value;
|
||||
const_values[2] = lb_const_int(m, t_int, entry_align) .value;
|
||||
const_values[3] = lb_const_int(m, t_uintptr, key_offset) .value;
|
||||
const_values[4] = lb_const_int(m, t_int, key_size) .value;
|
||||
const_values[5] = lb_const_int(m, t_uintptr, value_offset).value;
|
||||
const_values[6] = lb_const_int(m, t_int, value_size) .value;
|
||||
|
||||
LLVMValueRef llvm_res = llvm_const_named_struct(m, t_map_header_table, const_values, gb_count_of(const_values));
|
||||
lbValue res = {llvm_res, t_map_header_table};
|
||||
|
||||
lbAddr addr = lb_add_global_generated(m, t_map_header_table, res, nullptr);
|
||||
lb_make_global_private_const(addr);
|
||||
|
||||
map_set(&m->map_header_table_map, map_type, addr);
|
||||
return lb_addr_load(p, addr);
|
||||
}
|
||||
|
||||
lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||
@@ -595,14 +594,12 @@ lbValue lb_const_hash(lbModule *m, lbValue key, Type *key_type) {
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
||||
lbAddr v = lb_add_local_generated(p, t_map_hash, true);
|
||||
lbValue vp = lb_addr_get_ptr(p, v);
|
||||
key = lb_emit_conv(p, key, key_type);
|
||||
|
||||
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_) {
|
||||
lbValue key_ptr = lb_address_from_load_or_generate_local(p, key);
|
||||
key_ptr = lb_emit_conv(p, key_ptr, t_rawptr);
|
||||
|
||||
if (key_ptr_) *key_ptr_ = key_ptr;
|
||||
|
||||
lbValue hashed_key = lb_const_hash(p->module, key, key_type);
|
||||
if (hashed_key.value == nullptr) {
|
||||
lbValue hasher = lb_get_hasher_proc_for_type(p->module, key_type);
|
||||
@@ -613,32 +610,62 @@ lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type) {
|
||||
hashed_key = lb_emit_call(p, hasher, args);
|
||||
}
|
||||
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 0), hashed_key);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, vp, 1), key_ptr);
|
||||
|
||||
return lb_addr_load(p, v);
|
||||
return hashed_key;
|
||||
}
|
||||
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type,
|
||||
lbValue map_key, lbValue map_value, Ast *node) {
|
||||
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key) {
|
||||
Type *map_type = base_type(type_deref(map_ptr.type));
|
||||
|
||||
lbValue key_ptr = {};
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, map_type);
|
||||
args[2] = lb_gen_map_key_hash(p, key, map_type->Map.key, &key_ptr);
|
||||
args[3] = key_ptr;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
|
||||
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
||||
}
|
||||
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type,
|
||||
lbValue const &map_key, lbValue const &map_value, Ast *node) {
|
||||
map_type = base_type(map_type);
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, map_key, map_type->Map.key);
|
||||
lbValue key_ptr = {};
|
||||
lbValue key_hash = lb_gen_map_key_hash(p, map_key, map_type->Map.key, &key_ptr);
|
||||
lbValue v = lb_emit_conv(p, map_value, map_type->Map.value);
|
||||
|
||||
lbAddr value_addr = lb_add_local_generated(p, v.type, false);
|
||||
lb_addr_store(p, value_addr, v);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
args[2] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
||||
args[3] = lb_emit_source_code_location(p, node);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 6);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, map_type);
|
||||
args[2] = key_hash;
|
||||
args[3] = key_ptr;
|
||||
args[4] = lb_emit_conv(p, value_addr.addr, t_rawptr);
|
||||
args[5] = lb_emit_source_code_location(p, node);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_set", args);
|
||||
}
|
||||
|
||||
void lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos) {
|
||||
GB_ASSERT(!build_context.no_dynamic_literals);
|
||||
|
||||
String proc_name = {};
|
||||
if (p->entity) {
|
||||
proc_name = p->entity->token.string;
|
||||
}
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 4);
|
||||
args[0] = lb_emit_conv(p, map_ptr, t_rawptr);
|
||||
args[1] = lb_gen_map_header_table_internal(p, type_deref(map_ptr.type));
|
||||
args[2] = lb_const_int(p->module, t_int, capacity);
|
||||
args[3] = lb_emit_source_code_location(p, proc_name, pos);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
|
||||
}
|
||||
|
||||
|
||||
struct lbGlobalVariable {
|
||||
lbValue var;
|
||||
@@ -780,6 +807,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
|
||||
var->init = init;
|
||||
} else if (lb_is_const_or_global(init)) {
|
||||
if (!var->is_initialized) {
|
||||
if (is_type_proc(init.type)) {
|
||||
init.value = LLVMConstPointerCast(init.value, lb_type(p->module, init.type));
|
||||
}
|
||||
LLVMSetInitializer(var->var.value, init.value);
|
||||
var->is_initialized = true;
|
||||
continue;
|
||||
@@ -1420,7 +1450,7 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
LLVMBool split_debug_inlining = false;
|
||||
LLVMBool split_debug_inlining = build_context.build_mode == BuildMode_Assembly;
|
||||
LLVMBool debug_info_for_profiling = false;
|
||||
|
||||
m->debug_compile_unit = LLVMDIBuilderCreateCompileUnit(m->debug_builder, LLVMDWARFSourceLanguageC99,
|
||||
@@ -1615,6 +1645,7 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
if (is_foreign) {
|
||||
LLVMSetLinkage(g.value, LLVMExternalLinkage);
|
||||
LLVMSetDLLStorageClass(g.value, LLVMDLLImportStorageClass);
|
||||
LLVMSetExternallyInitialized(g.value, true);
|
||||
lb_add_foreign_library_path(m, e->Variable.foreign_library);
|
||||
|
||||
|
||||
@@ -159,6 +159,8 @@ struct lbModule {
|
||||
|
||||
StringMap<lbAddr> objc_classes;
|
||||
StringMap<lbAddr> objc_selectors;
|
||||
|
||||
PtrMap<Type *, lbAddr> map_header_table_map;
|
||||
};
|
||||
|
||||
struct lbGenerator {
|
||||
@@ -443,9 +445,11 @@ String lb_get_const_string(lbModule *m, lbValue value);
|
||||
|
||||
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
lbValue lb_gen_map_header(lbProcedure *p, lbValue map_val_ptr, Type *map_type);
|
||||
lbValue lb_gen_map_hash(lbProcedure *p, lbValue key, Type *key_type);
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbAddr addr, Type *map_type, lbValue map_key, lbValue map_value, Ast *node);
|
||||
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||
|
||||
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
|
||||
void lb_insert_dynamic_map_key_and_value(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
|
||||
void lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
|
||||
|
||||
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
||||
lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
|
||||
|
||||
+17
-11
@@ -297,12 +297,16 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_
|
||||
}
|
||||
|
||||
if (!is_const) {
|
||||
LLVMTypeRef llvm_elem_type = lb_type(m, elem_type);
|
||||
lbProcedure *p = m->curr_procedure;
|
||||
GB_ASSERT(p != nullptr);
|
||||
lbAddr v = lb_add_local_generated(p, type, false);
|
||||
lbValue ptr = lb_addr_get_ptr(p, v);
|
||||
for (isize i = 0; i < count; i++) {
|
||||
lbValue elem = lb_emit_array_epi(p, ptr, i);
|
||||
if (is_type_proc(elem_type)) {
|
||||
values[i] = LLVMConstPointerCast(values[i], llvm_elem_type);
|
||||
}
|
||||
LLVMBuildStore(p->builder, values[i], elem.value);
|
||||
}
|
||||
return lb_addr_load(p, v).value;
|
||||
@@ -348,7 +352,7 @@ LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)(sz+7/8), cast(u64 *)rop);
|
||||
LLVMValueRef value = LLVMConstIntOfArbitraryPrecision(lb_type(m, original_type), cast(unsigned)((sz+7)/8), cast(u64 *)rop);
|
||||
if (big_int_is_neg(a)) {
|
||||
value = LLVMConstNeg(value);
|
||||
}
|
||||
@@ -377,12 +381,20 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
|
||||
}
|
||||
|
||||
if (value.kind == ExactValue_Procedure) {
|
||||
lbValue res = {};
|
||||
Ast *expr = unparen_expr(value.value_procedure);
|
||||
if (expr->kind == Ast_ProcLit) {
|
||||
return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
|
||||
res = lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
|
||||
|
||||
} else {
|
||||
Entity *e = entity_from_expr(expr);
|
||||
res = lb_find_procedure_value_from_entity(m, e);
|
||||
}
|
||||
Entity *e = entity_from_expr(expr);
|
||||
return lb_find_procedure_value_from_entity(m, e);
|
||||
GB_ASSERT(res.value != nullptr);
|
||||
GB_ASSERT(LLVMGetValueKind(res.value) == LLVMFunctionValueKind);
|
||||
|
||||
res.value = LLVMConstPointerCast(res.value, lb_type(m, res.type));
|
||||
return res;
|
||||
}
|
||||
|
||||
bool is_local = allow_local && m->curr_procedure != nullptr;
|
||||
@@ -1137,13 +1149,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
|
||||
}
|
||||
break;
|
||||
case ExactValue_Procedure:
|
||||
{
|
||||
Ast *expr = value.value_procedure;
|
||||
GB_ASSERT(expr != nullptr);
|
||||
if (expr->kind == Ast_ProcLit) {
|
||||
return lb_generate_anonymous_proc_lit(m, str_lit("_proclit"), expr);
|
||||
}
|
||||
}
|
||||
GB_PANIC("handled earlier");
|
||||
break;
|
||||
case ExactValue_Typeid:
|
||||
return lb_typeid(m, value.value_typeid);
|
||||
|
||||
@@ -980,8 +980,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
|
||||
}
|
||||
|
||||
|
||||
void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block) {
|
||||
void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -1042,7 +1041,15 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
// NOTE(bill, 2022-02-01): For parameter values, you must insert them at the end of the decl block
|
||||
// The reason is that if the parameter is at index 0 and a pointer, there is not such things as an
|
||||
// instruction "before" it.
|
||||
LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
switch (arg_kind) {
|
||||
case lbArg_Direct:
|
||||
LLVMDIBuilderInsertDbgValueAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
break;
|
||||
case lbArg_Indirect:
|
||||
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block->block);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+34
-30
@@ -1,4 +1,4 @@
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise=false);
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||
|
||||
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
lbModule *m = p->module;
|
||||
@@ -987,7 +987,6 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
|
||||
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
|
||||
|
||||
|
||||
if (op == Token_Mul && !component_wise) {
|
||||
Type *xt = base_type(lhs.type);
|
||||
Type *yt = base_type(rhs.type);
|
||||
@@ -1001,8 +1000,22 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
|
||||
} else if (is_type_array_like(xt)) {
|
||||
GB_ASSERT(yt->kind == Type_Matrix);
|
||||
return lb_emit_vector_mul_matrix(p, lhs, rhs, type);
|
||||
}
|
||||
} else {
|
||||
GB_ASSERT(xt->kind == Type_Basic);
|
||||
GB_ASSERT(yt->kind == Type_Matrix);
|
||||
GB_ASSERT(is_type_matrix(type));
|
||||
|
||||
Type *array_type = alloc_type_array(yt->Matrix.elem, matrix_type_total_internal_elems(yt));
|
||||
GB_ASSERT(type_size_of(array_type) == type_size_of(yt));
|
||||
|
||||
lbValue array_lhs = lb_emit_conv(p, lhs, array_type);
|
||||
lbValue array_rhs = rhs;
|
||||
array_rhs.type = array_type;
|
||||
|
||||
lbValue array = lb_emit_arith(p, op, array_lhs, array_rhs, array_type);
|
||||
array.type = type;
|
||||
return array;
|
||||
}
|
||||
} else {
|
||||
if (is_type_matrix(lhs.type)) {
|
||||
rhs = lb_emit_conv(p, rhs, lhs.type);
|
||||
@@ -1047,7 +1060,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
|
||||
if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) {
|
||||
return lb_emit_arith_array(p, op, lhs, rhs, type);
|
||||
} else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) {
|
||||
return lb_emit_arith_matrix(p, op, lhs, rhs, type);
|
||||
return lb_emit_arith_matrix(p, op, lhs, rhs, type, false);
|
||||
} else if (is_type_complex(type)) {
|
||||
lhs = lb_emit_conv(p, lhs, type);
|
||||
rhs = lb_emit_conv(p, rhs, type);
|
||||
@@ -1320,7 +1333,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
if (is_type_matrix(be->left->tav.type) || is_type_matrix(be->right->tav.type)) {
|
||||
lbValue left = lb_build_expr(p, be->left);
|
||||
lbValue right = lb_build_expr(p, be->right);
|
||||
return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type));
|
||||
return lb_emit_arith_matrix(p, be->op.kind, left, right, default_type(tv.type), false);
|
||||
}
|
||||
|
||||
|
||||
@@ -1410,15 +1423,9 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
switch (rt->kind) {
|
||||
case Type_Map:
|
||||
{
|
||||
lbValue addr = lb_address_from_load_or_generate_local(p, right);
|
||||
lbValue h = lb_gen_map_header(p, addr, rt);
|
||||
lbValue key = lb_gen_map_hash(p, left, rt->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
lbValue map_ptr = lb_address_from_load_or_generate_local(p, right);
|
||||
lbValue key = left;
|
||||
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, map_ptr, key);
|
||||
if (be->op.kind == Token_in) {
|
||||
return lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||
} else {
|
||||
@@ -3663,16 +3670,14 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
|
||||
if (is_type_map(t)) {
|
||||
lbAddr map_addr = lb_build_addr(p, ie->expr);
|
||||
lbValue map_val = lb_addr_load(p, map_addr);
|
||||
if (deref) {
|
||||
map_val = lb_emit_load(p, map_val);
|
||||
}
|
||||
|
||||
lbValue key = lb_build_expr(p, ie->index);
|
||||
key = lb_emit_conv(p, key, t->Map.key);
|
||||
|
||||
Type *result_type = type_of_expr(expr);
|
||||
lbValue map_ptr = lb_address_from_load_or_generate_local(p, map_val);
|
||||
lbValue map_ptr = lb_addr_get_ptr(p, map_addr);
|
||||
if (is_type_pointer(type_deref(map_ptr.type))) {
|
||||
map_ptr = lb_emit_load(p, map_ptr);
|
||||
}
|
||||
return lb_addr_map(map_ptr, key, t, result_type);
|
||||
}
|
||||
|
||||
@@ -3712,8 +3717,11 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
ExactValue idx = exact_value_sub(index_tv.value, *t->EnumeratedArray.min_value);
|
||||
index = lb_const_value(p->module, index_type, idx);
|
||||
} else {
|
||||
index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
|
||||
index = lb_emit_arith(p, Token_Sub, index, lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value), index_type);
|
||||
index = lb_emit_arith(p, Token_Sub,
|
||||
lb_build_expr(p, ie->index),
|
||||
lb_const_value(p->module, index_type, *t->EnumeratedArray.min_value),
|
||||
index_type);
|
||||
index = lb_emit_conv(p, index, t_int);
|
||||
}
|
||||
} else {
|
||||
index = lb_emit_conv(p, lb_build_expr(p, ie->index), t_int);
|
||||
@@ -4123,20 +4131,16 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
break;
|
||||
}
|
||||
GB_ASSERT(!build_context.no_dynamic_literals);
|
||||
{
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 3);
|
||||
args[0] = lb_gen_map_header(p, v.addr, type);
|
||||
args[1] = lb_const_int(p->module, t_int, 2*cl->elems.count);
|
||||
args[2] = lb_emit_source_code_location(p, proc_name, pos);
|
||||
lb_emit_runtime_call(p, "__dynamic_map_reserve", args);
|
||||
}
|
||||
|
||||
lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
|
||||
|
||||
for_array(field_index, cl->elems) {
|
||||
Ast *elem = cl->elems[field_index];
|
||||
ast_node(fv, FieldValue, elem);
|
||||
|
||||
lbValue key = lb_build_expr(p, fv->field);
|
||||
lbValue value = lb_build_expr(p, fv->value);
|
||||
lb_insert_dynamic_map_key_and_value(p, v, type, key, value, elem);
|
||||
lb_insert_dynamic_map_key_and_value(p, v.addr, type, key, value, elem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,9 @@ void lb_init_module(lbModule *m, Checker *c) {
|
||||
|
||||
string_map_init(&m->objc_classes, a);
|
||||
string_map_init(&m->objc_selectors, a);
|
||||
|
||||
map_init(&m->map_header_table_map, a, 0);
|
||||
|
||||
}
|
||||
|
||||
bool lb_init_generator(lbGenerator *gen, Checker *c) {
|
||||
@@ -213,6 +216,17 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
|
||||
}
|
||||
|
||||
|
||||
void lb_make_global_private_const(LLVMValueRef global_data) {
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
}
|
||||
void lb_make_global_private_const(lbAddr const &addr) {
|
||||
lb_make_global_private_const(addr.addr.value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// This emits a GEP at 0, index
|
||||
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
|
||||
GB_ASSERT(is_type_pointer(value.type));
|
||||
@@ -390,19 +404,8 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
|
||||
}
|
||||
|
||||
switch (addr.kind) {
|
||||
case lbAddr_Map: {
|
||||
Type *map_type = base_type(addr.map.type);
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
|
||||
return lb_emit_conv(p, ptr, alloc_type_pointer(map_type->Map.value));
|
||||
}
|
||||
case lbAddr_Map:
|
||||
return lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||
|
||||
case lbAddr_RelativePointer: {
|
||||
Type *rel_ptr = base_type(lb_addr_type(addr));
|
||||
@@ -711,7 +714,7 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
|
||||
|
||||
return;
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
lb_insert_dynamic_map_key_and_value(p, addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||
lb_insert_dynamic_map_key_and_value(p, addr.addr, addr.map.type, addr.map.key, value, p->curr_stmt);
|
||||
return;
|
||||
} else if (addr.kind == lbAddr_Context) {
|
||||
lbAddr old_addr = lb_find_or_generate_context_ptr(p);
|
||||
@@ -877,18 +880,6 @@ bool lb_is_type_proc_recursive(Type *t) {
|
||||
case Type_Pointer:
|
||||
t = t->Pointer.elem;
|
||||
break;
|
||||
case Type_Array:
|
||||
t = t->Array.elem;
|
||||
break;
|
||||
case Type_EnumeratedArray:
|
||||
t = t->EnumeratedArray.elem;
|
||||
break;
|
||||
case Type_Slice:
|
||||
t = t->Slice.elem;
|
||||
break;
|
||||
case Type_DynamicArray:
|
||||
t = t->DynamicArray.elem;
|
||||
break;
|
||||
case Type_Proc:
|
||||
return true;
|
||||
default:
|
||||
@@ -938,19 +929,15 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
|
||||
return;
|
||||
} else if (LLVMIsConstant(value.value)) {
|
||||
lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
|
||||
LLVMValueRef global_data = addr.addr.value;
|
||||
// make it truly private data
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
lb_make_global_private_const(addr);
|
||||
|
||||
LLVMValueRef dst_ptr = ptr.value;
|
||||
LLVMValueRef src_ptr = global_data;
|
||||
LLVMValueRef src_ptr = addr.addr.value;
|
||||
src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
|
||||
|
||||
LLVMBuildMemMove(p->builder,
|
||||
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
|
||||
src_ptr, lb_try_get_alignment(global_data, 1),
|
||||
src_ptr, lb_try_get_alignment(src_ptr, 1),
|
||||
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
|
||||
return;
|
||||
}
|
||||
@@ -1071,16 +1058,11 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
|
||||
|
||||
|
||||
} else if (addr.kind == lbAddr_Map) {
|
||||
Type *map_type = base_type(addr.map.type);
|
||||
Type *map_type = base_type(type_deref(addr.addr.type));
|
||||
GB_ASSERT(map_type->kind == Type_Map);
|
||||
lbAddr v = lb_add_local_generated(p, map_type->Map.lookup_result_type, true);
|
||||
lbValue h = lb_gen_map_header(p, addr.addr, map_type);
|
||||
lbValue key = lb_gen_map_hash(p, addr.map.key, map_type->Map.key);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = h;
|
||||
args[1] = key;
|
||||
|
||||
lbValue ptr = lb_emit_runtime_call(p, "__dynamic_map_get", args);
|
||||
lbValue ptr = lb_internal_dynamic_map_get_ptr(p, addr.addr, addr.map.key);
|
||||
lbValue ok = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, ptr), t_bool);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, v.addr, 1), ok);
|
||||
|
||||
@@ -1525,6 +1507,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
|
||||
LLVMTypeRef ret = nullptr;
|
||||
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
|
||||
bool *params_by_ptr = gb_alloc_array(permanent_allocator(), bool, param_count);
|
||||
if (type->Proc.result_count != 0) {
|
||||
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
|
||||
ret = lb_type(m, single_ret);
|
||||
@@ -1550,9 +1533,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
}
|
||||
Type *e_type = reduce_tuple_to_single_type(e->type);
|
||||
|
||||
bool param_is_by_ptr = false;
|
||||
LLVMTypeRef param_type = nullptr;
|
||||
if (e->flags & EntityFlag_ByPtr) {
|
||||
param_type = lb_type(m, alloc_type_pointer(e_type));
|
||||
// it will become a pointer afterwards by making it indirect
|
||||
param_type = lb_type(m, e_type);
|
||||
param_is_by_ptr = true;
|
||||
} else if (is_type_boolean(e_type) &&
|
||||
type_size_of(e_type) <= 1) {
|
||||
param_type = LLVMInt1TypeInContext(m->ctx);
|
||||
@@ -1564,6 +1550,7 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
}
|
||||
}
|
||||
|
||||
params_by_ptr[param_index] = param_is_by_ptr;
|
||||
params[param_index++] = param_type;
|
||||
}
|
||||
}
|
||||
@@ -1589,6 +1576,12 @@ LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
|
||||
LLVMPrintTypeToString(ft->ret.type),
|
||||
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
|
||||
}
|
||||
for_array(j, ft->args) {
|
||||
if (params_by_ptr[j]) {
|
||||
// NOTE(bill): The parameter needs to be passed "indirectly", override it
|
||||
ft->args[j].kind = lbArg_Indirect;
|
||||
}
|
||||
}
|
||||
|
||||
map_set(&m->function_type_map, type, ft);
|
||||
LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
|
||||
@@ -1890,16 +1883,16 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
return LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
|
||||
|
||||
case Type_Array: {
|
||||
m->internal_type_level -= 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count);
|
||||
m->internal_type_level += 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count);
|
||||
m->internal_type_level -= 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
case Type_EnumeratedArray: {
|
||||
m->internal_type_level -= 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count);
|
||||
m->internal_type_level += 1;
|
||||
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->EnumeratedArray.elem), cast(unsigned)type->EnumeratedArray.count);
|
||||
m->internal_type_level -= 1;
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -2101,14 +2094,11 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
|
||||
}
|
||||
|
||||
case Type_Proc:
|
||||
// if (m->internal_type_level > 256) { // TODO HACK(bill): is this really enough?
|
||||
if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough?
|
||||
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
|
||||
} else {
|
||||
{
|
||||
LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type);
|
||||
return LLVMPointerType(proc_raw_type, 0);
|
||||
gb_unused(proc_raw_type);
|
||||
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
|
||||
}
|
||||
|
||||
break;
|
||||
case Type_BitSet:
|
||||
{
|
||||
@@ -2488,10 +2478,8 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
|
||||
string_map_set(&m->const_strings, key, ptr);
|
||||
@@ -2534,10 +2522,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
LLVMValueRef ptr = nullptr;
|
||||
if (str.len != 0) {
|
||||
@@ -2573,10 +2559,8 @@ lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String co
|
||||
LLVMTypeRef type = LLVMTypeOf(data);
|
||||
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
|
||||
LLVMSetInitializer(global_data, data);
|
||||
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
|
||||
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
|
||||
lb_make_global_private_const(global_data);
|
||||
LLVMSetAlignment(global_data, 1);
|
||||
LLVMSetGlobalConstant(global_data, true);
|
||||
|
||||
i64 data_len = str.len;
|
||||
LLVMValueRef ptr = nullptr;
|
||||
@@ -2684,6 +2668,7 @@ lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e) {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value, Entity **entity_) {
|
||||
GB_ASSERT(type != nullptr);
|
||||
type = default_type(type);
|
||||
|
||||
+17
-19
@@ -121,8 +121,8 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
p->branch_blocks.allocator = a;
|
||||
p->context_stack.allocator = a;
|
||||
p->scope_stack.allocator = a;
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
|
||||
if (p->is_foreign) {
|
||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||
@@ -379,7 +379,6 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
|
||||
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nonnull");
|
||||
lb_add_proc_attribute_at_index(p, offset+parameter_index, "nocapture");
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -552,7 +551,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
if (original_value != value && LLVMIsALoadInst(value)) {
|
||||
debug_storage_value = LLVMGetOperand(value, 0);
|
||||
}
|
||||
lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block);
|
||||
lb_add_debug_param_variable(p, debug_storage_value, e->type, e->token, param_index+1, block, arg_type->kind);
|
||||
}
|
||||
} else if (arg_type->kind == lbArg_Indirect) {
|
||||
if (e->token.string.len != 0 && !is_blank_ident(e->token.string)) {
|
||||
@@ -560,7 +559,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
ptr.value = LLVMGetParam(p->value, param_offset+param_index);
|
||||
ptr.type = alloc_type_pointer(e->type);
|
||||
lb_add_entity(p->module, e, ptr);
|
||||
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block);
|
||||
lb_add_debug_param_variable(p, ptr.value, e->type, e->token, param_index+1, p->decl_block, arg_type->kind);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -577,25 +576,21 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
if (e->token.string != "") {
|
||||
GB_ASSERT(!is_blank_ident(e->token));
|
||||
|
||||
lbAddr res = {};
|
||||
if (return_ptr_value.value) {
|
||||
lbValue ptr = return_ptr_value;
|
||||
if (results->variables.count != 1) {
|
||||
ptr = lb_emit_struct_ep(p, ptr, cast(i32)i);
|
||||
}
|
||||
|
||||
res = lb_addr(ptr);
|
||||
lb_add_entity(p->module, e, ptr);
|
||||
} else {
|
||||
res = lb_add_local(p, e->type, e);
|
||||
}
|
||||
|
||||
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
|
||||
// This will violate the defer rules if you do:
|
||||
// foo :: proc() -> (x, y: T) {
|
||||
// defer x = ... // defer is executed after the `defer`
|
||||
// return // the values returned should be zeroed
|
||||
// }
|
||||
lbAddr res = lb_add_local(p, e->type, e);
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
||||
lb_addr_store(p, res, c);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (p->type->Proc.calling_convention == ProcCC_Odin) {
|
||||
@@ -736,6 +731,9 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
}
|
||||
for_array(i, processed_args) {
|
||||
lbValue arg = processed_args[i];
|
||||
if (is_type_proc(arg.type)) {
|
||||
arg.value = LLVMBuildPointerCast(p->builder, arg.value, lb_type(p->module, arg.type), "");
|
||||
}
|
||||
args[arg_index++] = arg.value;
|
||||
}
|
||||
if (context_ptr.addr.value != nullptr) {
|
||||
@@ -887,7 +885,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
GB_ASSERT(param_count-1 <= args.count);
|
||||
param_count -= 1;
|
||||
} else {
|
||||
GB_ASSERT_MSG(param_count == args.count, "%td == %td", param_count, args.count);
|
||||
GB_ASSERT_MSG(param_count == args.count, "%td == %td (%s)", param_count, args.count, LLVMPrintValueToString(value.value));
|
||||
}
|
||||
|
||||
lbValue result = {};
|
||||
|
||||
@@ -1273,6 +1273,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
|
||||
lbValue parent = lb_build_expr(p, as->rhs[0]);
|
||||
bool is_parent_ptr = is_type_pointer(parent.type);
|
||||
Type *parent_base_type = type_deref(parent.type);
|
||||
|
||||
TypeSwitchKind switch_kind = check_valid_type_switch_type(parent.type);
|
||||
GB_ASSERT(switch_kind != TypeSwitch_Invalid);
|
||||
@@ -1288,8 +1289,11 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
lbValue union_data = {};
|
||||
if (switch_kind == TypeSwitch_Union) {
|
||||
union_data = lb_emit_conv(p, parent_ptr, t_rawptr);
|
||||
if (is_type_union_maybe_pointer(type_deref(parent_ptr.type))) {
|
||||
Type *union_type = type_deref(parent_ptr.type);
|
||||
if (is_type_union_maybe_pointer(union_type)) {
|
||||
tag = lb_emit_conv(p, lb_emit_comp_against_nil(p, Token_NotEq, union_data), t_int);
|
||||
} else if (union_tag_size(union_type) == 0) {
|
||||
tag = {}; // there is no tag for a zero sized union
|
||||
} else {
|
||||
lbValue tag_ptr = lb_emit_union_tag_ptr(p, parent_ptr);
|
||||
tag = lb_emit_load(p, tag_ptr);
|
||||
@@ -1318,8 +1322,15 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT(tag.value != nullptr);
|
||||
LLVMValueRef switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||
|
||||
LLVMValueRef switch_instr = nullptr;
|
||||
if (type_size_of(parent_base_type) == 0) {
|
||||
GB_ASSERT(tag.value == nullptr);
|
||||
switch_instr = LLVMBuildSwitch(p->builder, lb_const_bool(p->module, t_llvm_bool, false).value, else_block->block, cast(unsigned)num_cases);
|
||||
} else {
|
||||
GB_ASSERT(tag.value != nullptr);
|
||||
switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||
}
|
||||
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
|
||||
@@ -612,6 +612,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
|
||||
LLVMValueRef value_init = llvm_const_array(lb_type(m, t_type_info_enum_value), value_values, cast(unsigned)fields.count);
|
||||
LLVMSetInitializer(name_array.value, name_init);
|
||||
LLVMSetInitializer(value_array.value, value_init);
|
||||
LLVMSetGlobalConstant(name_array.value, true);
|
||||
LLVMSetGlobalConstant(value_array.value, true);
|
||||
|
||||
lbValue v_count = lb_const_int(m, t_int, fields.count);
|
||||
|
||||
@@ -787,7 +789,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
|
||||
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
|
||||
init_map_internal_types(t);
|
||||
|
||||
lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
|
||||
lbValue gst = lb_type_info(m, t->Map.internal_type);
|
||||
|
||||
LLVMValueRef vals[5] = {
|
||||
lb_type_info(m, t->Map.key).value,
|
||||
|
||||
@@ -225,6 +225,20 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
if (is_type_simd_vector(src) && is_type_simd_vector(dst)) {
|
||||
res.value = LLVMBuildBitCast(p->builder, value.value, lb_type(p->module, t), "");
|
||||
return res;
|
||||
} else if (is_type_array_like(src) && is_type_simd_vector(dst)) {
|
||||
unsigned align = cast(unsigned)gb_max(type_align_of(src), type_align_of(dst));
|
||||
lbValue ptr = lb_address_from_load_or_generate_local(p, value);
|
||||
if (lb_try_update_alignment(ptr, align)) {
|
||||
LLVMTypeRef result_type = lb_type(p->module, t);
|
||||
res.value = LLVMBuildPointerCast(p->builder, ptr.value, LLVMPointerType(result_type, 0), "");
|
||||
res.value = LLVMBuildLoad2(p->builder, result_type, res.value, "");
|
||||
return res;
|
||||
}
|
||||
lbAddr addr = lb_add_local_generated(p, t, false);
|
||||
lbValue ap = lb_addr_get_ptr(p, addr);
|
||||
ap = lb_emit_conv(p, ap, alloc_type_pointer(value.type));
|
||||
lb_emit_store(p, ap, value);
|
||||
return lb_addr_load(p, addr);
|
||||
}
|
||||
|
||||
if (lb_is_type_aggregate(src) || lb_is_type_aggregate(dst)) {
|
||||
@@ -1116,7 +1130,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
case Type_Map:
|
||||
{
|
||||
init_map_internal_types(t);
|
||||
Type *gst = t->Map.generated_struct_type;
|
||||
Type *gst = t->Map.internal_type;
|
||||
switch (index) {
|
||||
case 0: result_type = get_struct_field_type(gst, 0); break;
|
||||
case 1: result_type = get_struct_field_type(gst, 1); break;
|
||||
|
||||
+43
-43
@@ -288,11 +288,15 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
|
||||
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
|
||||
if (!build_context.use_lld) { // msvc
|
||||
String res_path = {};
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
if (build_context.has_resource) {
|
||||
String temp_res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]);
|
||||
res_path = concatenate3_strings(heap_allocator(), str_lit("\""), temp_res_path, str_lit("\""));
|
||||
gb_free(heap_allocator(), temp_res_path.text);
|
||||
|
||||
String rc_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RC]);
|
||||
String res_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_RES]);
|
||||
defer (gb_free(heap_allocator(), rc_path.text));
|
||||
defer (gb_free(heap_allocator(), res_path.text));
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
|
||||
@@ -304,42 +308,25 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s \"%.*s\" -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
} else {
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
subsystem_str,
|
||||
LIT(build_context.link_flags),
|
||||
LIT(build_context.extra_linker_flags),
|
||||
lib_str
|
||||
);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
} else { // lld
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
@@ -590,8 +577,8 @@ void usage(String argv0) {
|
||||
print_usage_line(1, "version print version");
|
||||
print_usage_line(1, "report print information useful to reporting a bug");
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(0, "For further details on a command, use -help after the command name");
|
||||
print_usage_line(1, "e.g. odin build -help");
|
||||
print_usage_line(0, "For further details on a command, invoke command help:");
|
||||
print_usage_line(1, "e.g. `odin build -help` or `odin help build`");
|
||||
}
|
||||
|
||||
enum BuildFlagKind {
|
||||
@@ -1963,13 +1950,13 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(2, "Parse and type check .odin file(s) and then remove unneeded semicolons from the entire project");
|
||||
}
|
||||
|
||||
bool doc = command == "doc";
|
||||
bool build = command == "build";
|
||||
bool run_or_build = command == "run" || command == "build" || command == "test";
|
||||
bool test_only = command == "test";
|
||||
bool doc = command == "doc";
|
||||
bool build = command == "build";
|
||||
bool run_or_build = command == "run" || command == "build" || command == "test";
|
||||
bool test_only = command == "test";
|
||||
bool strip_semicolon = command == "strip-semicolon";
|
||||
bool check_only = command == "check" || strip_semicolon;
|
||||
bool check = run_or_build || check_only;
|
||||
bool check_only = command == "check" || strip_semicolon;
|
||||
bool check = run_or_build || check_only;
|
||||
|
||||
print_usage_line(0, "");
|
||||
print_usage_line(1, "Flags");
|
||||
@@ -2085,7 +2072,7 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(3, "-build-mode:shared Build as a dynamically linked library");
|
||||
print_usage_line(3, "-build-mode:obj Build as an object file");
|
||||
print_usage_line(3, "-build-mode:object Build as an object file");
|
||||
print_usage_line(3, "-build-mode:assembly Build as an object file");
|
||||
print_usage_line(3, "-build-mode:assembly Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:assembler Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:asm Build as an assembly file");
|
||||
print_usage_line(3, "-build-mode:llvm-ir Build as an LLVM IR file");
|
||||
@@ -2701,6 +2688,14 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
build_context.command_kind = Command_bug_report;
|
||||
print_bug_report_help();
|
||||
return 0;
|
||||
} else if (command == "help") {
|
||||
if (args.count <= 2) {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
} else {
|
||||
print_show_help(args[0], args[2]);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
@@ -2727,7 +2722,12 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
|
||||
if (!single_file_package) {
|
||||
gb_printf_err("ERROR: `%.*s %.*s` takes a package as its first argument.\n", LIT(args[0]), LIT(command));
|
||||
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
|
||||
if (init_filename == "-file") {
|
||||
gb_printf_err("Did you mean `%.*s %.*s <filename.odin> -file`?\n", LIT(args[0]), LIT(command));
|
||||
} else {
|
||||
gb_printf_err("Did you mean `%.*s %.*s %.*s -file`?\n", LIT(args[0]), LIT(command), LIT(init_filename));
|
||||
}
|
||||
|
||||
gb_printf_err("The `-file` flag tells it to treat a file as a self-contained package.\n");
|
||||
return 1;
|
||||
} else {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user