Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm: support more vendor libraries #4208

Merged
merged 1 commit into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/bytes/bytes.odin
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
index_byte :: proc(s: []byte, c: byte) -> (index: int) #no_bounds_check {
index_byte :: proc "contextless" (s: []byte, c: byte) -> (index: int) #no_bounds_check {
i, l := 0, len(s)

// Guard against small strings. On modern systems, it is ALWAYS
Expand Down Expand Up @@ -469,7 +469,7 @@ Inputs:
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
last_index_byte :: proc(s: []byte, c: byte) -> int #no_bounds_check {
last_index_byte :: proc "contextless" (s: []byte, c: byte) -> int #no_bounds_check {
i := len(s)

// Guard against small strings. On modern systems, it is ALWAYS
Expand Down
78 changes: 78 additions & 0 deletions core/mem/allocators.odin
Original file line number Diff line number Diff line change
Expand Up @@ -1137,3 +1137,81 @@ buddy_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,

return nil, nil
}

// An allocator that keeps track of allocation sizes and passes it along to resizes.
// This is useful if you are using a library that needs an equivalent of `realloc` but want to use
// the Odin allocator interface.
//
// You want to wrap your allocator into this one if you are trying to use any allocator that relies
// on the old size to work.
//
// The overhead of this allocator is an extra max(alignment, size_of(Header)) bytes allocated for each allocation, these bytes are
// used to store the size and original pointer.
Compat_Allocator :: struct {
parent: Allocator,
}

compat_allocator_init :: proc(rra: ^Compat_Allocator, allocator := context.allocator) {
rra.parent = allocator
}

compat_allocator :: proc(rra: ^Compat_Allocator) -> Allocator {
return Allocator{
data = rra,
procedure = compat_allocator_proc,
}
}

compat_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
size, old_size := size, old_size

Header :: struct {
size: int,
ptr: rawptr,
}

rra := (^Compat_Allocator)(allocator_data)
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
a := max(alignment, size_of(Header))
size += a
assert(size >= 0, "overflow")

allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location) or_return
#no_bounds_check data = allocation[a:]
gingerBill marked this conversation as resolved.
Show resolved Hide resolved

([^]Header)(raw_data(data))[-1] = {
laytan marked this conversation as resolved.
Show resolved Hide resolved
size = size,
ptr = raw_data(allocation),
}
return

case .Free:
header := ([^]Header)(old_memory)[-1]
return rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location)

case .Resize, .Resize_Non_Zeroed:
header := ([^]Header)(old_memory)[-1]

a := max(alignment, size_of(header))
size += a
assert(size >= 0, "overflow")

allocation := rra.parent.procedure(rra.parent.data, mode, size, alignment, header.ptr, header.size, location) or_return
#no_bounds_check data = allocation[a:]

([^]Header)(raw_data(data))[-1] = {
size = size,
ptr = raw_data(allocation),
}
return

case .Free_All, .Query_Info, .Query_Features:
return rra.parent.procedure(rra.parent.data, mode, size, alignment, old_memory, old_size, location)

case: unreachable()
}
}
89 changes: 19 additions & 70 deletions core/os/os_js.odin
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,38 @@ package os

import "base:runtime"

foreign import "odin_env"

@(require_results)
is_path_separator :: proc(c: byte) -> bool {
return c == '/' || c == '\\'
}

Handle :: distinct u32

stdout: Handle = 1
stderr: Handle = 2

@(require_results)
open :: proc(path: string, mode: int = O_RDONLY, perm: int = 0) -> (Handle, Error) {
unimplemented("core:os procedure not supported on JS target")
}

close :: proc(fd: Handle) -> Error {
unimplemented("core:os procedure not supported on JS target")
return nil
}

flush :: proc(fd: Handle) -> (err: Error) {
unimplemented("core:os procedure not supported on JS target")
return nil
}



write :: proc(fd: Handle, data: []byte) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}

@(private="file")
read_console :: proc(handle: Handle, b: []byte) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
foreign odin_env {
@(link_name="write")
_write :: proc "contextless" (fd: Handle, p: []byte) ---
}
_write(fd, data)
return len(data), nil
}

read :: proc(fd: Handle, data: []byte) -> (int, Error) {
Expand All @@ -45,36 +50,13 @@ file_size :: proc(fd: Handle) -> (i64, Error) {
unimplemented("core:os procedure not supported on JS target")
}


@(private)
MAX_RW :: 1<<30

@(private)
pread :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}
@(private)
pwrite :: proc(fd: Handle, data: []byte, offset: i64) -> (int, Error) {
unimplemented("core:os procedure not supported on JS target")
}

read_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
write_at :: proc(fd: Handle, data: []byte, offset: i64) -> (n: int, err: Error) {
unimplemented("core:os procedure not supported on JS target")
}

stdout: Handle = 1
stderr: Handle = 2

@(require_results)
get_std_handle :: proc "contextless" (h: uint) -> Handle {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
}


@(require_results)
exists :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
Expand All @@ -90,9 +72,6 @@ is_dir :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
}

// NOTE(tetra): GetCurrentDirectory is not thread safe with SetCurrentDirectory and GetFullPathName
//@private cwd_lock := win32.SRWLOCK{} // zero is initialized

@(require_results)
get_current_directory :: proc(allocator := context.allocator) -> string {
unimplemented("core:os procedure not supported on JS target")
Expand All @@ -118,18 +97,6 @@ remove_directory :: proc(path: string) -> (err: Error) {
}



@(private, require_results)
is_abs :: proc(path: string) -> bool {
unimplemented("core:os procedure not supported on JS target")
}

@(private, require_results)
fix_long_path :: proc(path: string) -> string {
unimplemented("core:os procedure not supported on JS target")
}


link :: proc(old_name, new_name: string) -> (err: Error) {
unimplemented("core:os procedure not supported on JS target")
}
Expand Down Expand Up @@ -169,7 +136,6 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
unimplemented("core:os procedure not supported on JS target")
}

Handle :: distinct uintptr
File_Time :: distinct u64

_Platform_Error :: enum i32 {
Expand Down Expand Up @@ -254,12 +220,7 @@ WSAECONNRESET :: Platform_Error.WSAECONNRESET
ERROR_FILE_IS_PIPE :: General_Error.File_Is_Pipe
ERROR_FILE_IS_NOT_DIR :: General_Error.Not_Dir

// "Argv" arguments converted to Odin strings
args := _alloc_command_line_arguments()




args: []string

@(require_results)
last_write_time :: proc(fd: Handle) -> (File_Time, Error) {
Expand All @@ -279,26 +240,14 @@ get_page_size :: proc() -> int {

@(private, require_results)
_processor_core_count :: proc() -> int {
unimplemented("core:os procedure not supported on JS target")
return 1
}

exit :: proc "contextless" (code: int) -> ! {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
unimplemented_contextless("core:os procedure not supported on JS target")
}



@(require_results)
current_thread_id :: proc "contextless" () -> int {
context = runtime.default_context()
unimplemented("core:os procedure not supported on JS target")
return 0
}



@(require_results)
_alloc_command_line_arguments :: proc() -> []string {
return nil
}

14 changes: 7 additions & 7 deletions core/strings/strings.odin
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Inputs:
Returns:
- res: A string created from the null-terminated byte pointer and length
*/
string_from_null_terminated_ptr :: proc(ptr: [^]byte, len: int) -> (res: string) {
string_from_null_terminated_ptr :: proc "contextless" (ptr: [^]byte, len: int) -> (res: string) {
s := string(ptr[:len])
s = truncate_to_byte(s, 0)
return s
Expand Down Expand Up @@ -139,7 +139,7 @@ NOTE: Failure to find the byte results in returning the entire string.
Returns:
- res: The truncated string
*/
truncate_to_byte :: proc(str: string, b: byte) -> (res: string) {
truncate_to_byte :: proc "contextless" (str: string, b: byte) -> (res: string) {
n := index_byte(str, b)
if n < 0 {
n = len(str)
Expand Down Expand Up @@ -261,7 +261,7 @@ Inputs:
Returns:
- result: `-1` if `lhs` comes first, `1` if `rhs` comes first, or `0` if they are equal
*/
compare :: proc(lhs, rhs: string) -> (result: int) {
compare :: proc "contextless" (lhs, rhs: string) -> (result: int) {
return mem.compare(transmute([]byte)lhs, transmute([]byte)rhs)
}
/*
Expand Down Expand Up @@ -1447,7 +1447,7 @@ Output:
-1

*/
index_byte :: proc(s: string, c: byte) -> (res: int) {
index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.index_byte(transmute([]u8)s, c)
}
/*
Expand Down Expand Up @@ -1482,7 +1482,7 @@ Output:
-1

*/
last_index_byte :: proc(s: string, c: byte) -> (res: int) {
last_index_byte :: proc "contextless" (s: string, c: byte) -> (res: int) {
return #force_inline bytes.last_index_byte(transmute([]u8)s, c)
}
/*
Expand Down Expand Up @@ -1576,8 +1576,8 @@ Output:
-1

*/
index :: proc(s, substr: string) -> (res: int) {
hash_str_rabin_karp :: proc(s: string) -> (hash: u32 = 0, pow: u32 = 1) {
index :: proc "contextless" (s, substr: string) -> (res: int) {
hash_str_rabin_karp :: proc "contextless" (s: string) -> (hash: u32 = 0, pow: u32 = 1) {
for i := 0; i < len(s); i += 1 {
hash = hash*PRIME_RABIN_KARP + u32(s[i])
}
Expand Down
22 changes: 18 additions & 4 deletions vendor/box2d/box2d.odin
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@ package vendor_box2d
import "base:intrinsics"
import "core:c"

@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
@(private) VECTOR_EXT :: "_simd" when #config(VENDOR_BOX2D_ENABLE_SIMD128, intrinsics.has_target_feature("simd128")) else ""
} else {
@(private) VECTOR_EXT :: "avx2" when #config(VENDOR_BOX2D_ENABLE_AVX2, intrinsics.has_target_feature("avx2")) else "sse2"
}

when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_windows_amd64_" + VECTOR_EXT + ".lib"
Expand All @@ -13,6 +17,8 @@ when ODIN_OS == .Windows {
@(private) LIB_PATH :: "lib/box2d_darwin_amd64_" + VECTOR_EXT + ".a"
} else when ODIN_ARCH == .amd64 {
@(private) LIB_PATH :: "lib/box2d_other_amd64_" + VECTOR_EXT + ".a"
} else when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
@(private) LIB_PATH :: "lib/box2d_wasm" + VECTOR_EXT + ".o"
} else {
@(private) LIB_PATH :: "lib/box2d_other.a"
}
Expand All @@ -21,8 +27,16 @@ when !#exists(LIB_PATH) {
#panic("Could not find the compiled box2d libraries at \"" + LIB_PATH + "\", they can be compiled by running the `build.sh` script at `" + ODIN_ROOT + "vendor/box2d/build_box2d.sh\"`")
}

foreign import lib {
LIB_PATH,
when ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32 {
when VECTOR_EXT == "_simd" {
foreign import lib "lib/box2d_wasm_simd.o"
} else {
foreign import lib "lib/box2d_wasm.o"
}
} else {
foreign import lib {
LIB_PATH,
}
}


Expand Down Expand Up @@ -1520,4 +1534,4 @@ IsValid :: proc{
Joint_IsValid,

IsValidRay,
}
}
4 changes: 4 additions & 0 deletions vendor/box2d/box2d_wasm.odin
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//+build wasm32, wasm64p32
package vendor_box2d

@(require) import _ "vendor:libc"
2 changes: 2 additions & 0 deletions vendor/box2d/build_box2d.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,7 @@ esac

cd ..

make -f wasm.Makefile

rm -rf v3.0.0.tar.gz
rm -rf box2d-3.0.0
Binary file added vendor/box2d/lib/box2d_wasm.o
Binary file not shown.
Binary file added vendor/box2d/lib/box2d_wasm_simd.o
Binary file not shown.
Loading