mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-14 15:11:25 -07:00
Begin work on Atomics for wasm32 (wait and notify intrinsics)
This commit is contained in:
@@ -190,6 +190,15 @@ constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
|
||||
wasm_memory_grow :: proc(index, delta: uintptr) -> int ---
|
||||
wasm_memory_size :: proc(index: uintptr) -> int ---
|
||||
|
||||
// `timeout_ns` is maximum number of nanoseconds the calling thread will be blocked for
|
||||
// A negative value will be blocked forever
|
||||
// Return value:
|
||||
// 0 - indicates that the thread blocked and then was woken up
|
||||
// 1 - the loaded value from `ptr` did not match `expected`, the thread did not block
|
||||
// 2 - the thread blocked, but the timeout
|
||||
wasm_memory_atomic_wait32 :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -> u32 ---
|
||||
wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
|
||||
|
||||
|
||||
// Darwin targets only
|
||||
objc_object :: struct{}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
//+private
|
||||
//+build wasm32
|
||||
package sync
|
||||
|
||||
import "core:intrinsics"
|
||||
import "core:time"
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||
return s != 0
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||
return s != 0
|
||||
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||
if s >= 1 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||
if s >= 0 {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//+private
|
||||
//+build wasm32
|
||||
package sync
|
||||
|
||||
_current_thread_id :: proc "contextless" () -> int {
|
||||
// TODO(bill): _current_thread_id for wasm32
|
||||
return 0
|
||||
}
|
||||
@@ -4473,6 +4473,99 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
}
|
||||
break;
|
||||
|
||||
case BuiltinProc_wasm_memory_atomic_wait32:
|
||||
{
|
||||
if (!is_arch_wasm()) {
|
||||
error(call, "'%.*s' is only allowed on wasm targets", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
Operand ptr = {};
|
||||
Operand expected = {};
|
||||
Operand timeout = {};
|
||||
check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false;
|
||||
check_expr(c, &expected, ce->args[1]); if (expected.mode == Addressing_Invalid) return false;
|
||||
check_expr(c, &timeout, ce->args[2]); if (timeout.mode == Addressing_Invalid) return false;
|
||||
|
||||
Type *t_u32_ptr = alloc_type_pointer(t_u32);
|
||||
convert_to_typed(c, &ptr, t_u32_ptr); if (ptr.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &expected, t_u32); if (expected.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &timeout, t_i64); if (timeout.mode == Addressing_Invalid) return false;
|
||||
|
||||
if (!is_operand_value(ptr) || !check_is_assignable_to(c, &ptr, t_u32_ptr)) {
|
||||
gbString e = expr_to_string(ptr.expr);
|
||||
gbString t = type_to_string(ptr.type);
|
||||
error(ptr.expr, "'%.*s' expected ^u32 for the memory pointer, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_operand_value(expected) || !check_is_assignable_to(c, &expected, t_u32)) {
|
||||
gbString e = expr_to_string(expected.expr);
|
||||
gbString t = type_to_string(expected.type);
|
||||
error(expected.expr, "'%.*s' expected u32 for the 'expected' value, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_operand_value(timeout) || !check_is_assignable_to(c, &timeout, t_i64)) {
|
||||
gbString e = expr_to_string(timeout.expr);
|
||||
gbString t = type_to_string(timeout.type);
|
||||
error(timeout.expr, "'%.*s' expected i64 for the timeout, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t_u32;
|
||||
operand->value = {};
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_wasm_memory_atomic_notify32:
|
||||
{
|
||||
if (!is_arch_wasm()) {
|
||||
error(call, "'%.*s' is only allowed on wasm targets", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
Operand ptr = {};
|
||||
Operand waiters = {};
|
||||
check_expr(c, &ptr, ce->args[0]); if (ptr.mode == Addressing_Invalid) return false;
|
||||
check_expr(c, &waiters, ce->args[1]); if (waiters.mode == Addressing_Invalid) return false;
|
||||
|
||||
Type *t_u32_ptr = alloc_type_pointer(t_u32);
|
||||
convert_to_typed(c, &ptr, t_u32_ptr); if (ptr.mode == Addressing_Invalid) return false;
|
||||
convert_to_typed(c, &waiters, t_u32); if (waiters.mode == Addressing_Invalid) return false;
|
||||
|
||||
if (!is_operand_value(ptr) || !check_is_assignable_to(c, &ptr, t_u32_ptr)) {
|
||||
gbString e = expr_to_string(ptr.expr);
|
||||
gbString t = type_to_string(ptr.type);
|
||||
error(ptr.expr, "'%.*s' expected ^u32 for the memory pointer, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_operand_value(waiters) || !check_is_assignable_to(c, &waiters, t_u32)) {
|
||||
gbString e = expr_to_string(waiters.expr);
|
||||
gbString t = type_to_string(waiters.type);
|
||||
error(waiters.expr, "'%.*s' expected u32 for the 'waiters' value, got '%s' of type %s", LIT(builtin_name), e, t);
|
||||
gb_string_free(t);
|
||||
gb_string_free(e);
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->mode = Addressing_Value;
|
||||
operand->type = t_u32;
|
||||
operand->value = {};
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -218,6 +218,8 @@ BuiltinProc__type_end,
|
||||
|
||||
BuiltinProc_wasm_memory_grow,
|
||||
BuiltinProc_wasm_memory_size,
|
||||
BuiltinProc_wasm_memory_atomic_wait32,
|
||||
BuiltinProc_wasm_memory_atomic_notify32,
|
||||
|
||||
BuiltinProc_COUNT,
|
||||
};
|
||||
@@ -438,4 +440,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
|
||||
|
||||
{STR_LIT("wasm_memory_grow"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("wasm_memory_atomic_wait32"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
{STR_LIT("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
|
||||
};
|
||||
|
||||
@@ -2187,6 +2187,51 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
return res;
|
||||
}
|
||||
|
||||
case BuiltinProc_wasm_memory_atomic_wait32:
|
||||
{
|
||||
char const *name = "llvm.wasm.memory.atomic.wait32";
|
||||
LLVMTypeRef types[1] = {
|
||||
lb_type(p->module, t_u32),
|
||||
};
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
|
||||
|
||||
Type *t_u32_ptr = alloc_type_pointer(t_u32);
|
||||
|
||||
LLVMValueRef args[3] = {};
|
||||
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value;
|
||||
args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value;
|
||||
args[2] = lb_emit_conv(p, lb_build_expr(p, ce->args[2]), t_i64).value;
|
||||
|
||||
lbValue res = {};
|
||||
res.type = tv.type;
|
||||
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
|
||||
return res;
|
||||
}
|
||||
|
||||
case BuiltinProc_wasm_memory_atomic_notify32:
|
||||
{
|
||||
char const *name = "llvm.wasm.memory.atomic.notify";
|
||||
LLVMTypeRef types[1] = {
|
||||
lb_type(p->module, t_u32),
|
||||
};
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
|
||||
|
||||
Type *t_u32_ptr = alloc_type_pointer(t_u32);
|
||||
|
||||
LLVMValueRef args[2] = {};
|
||||
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value;
|
||||
args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value;
|
||||
|
||||
lbValue res = {};
|
||||
res.type = tv.type;
|
||||
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
|
||||
|
||||
Vendored
+29
-9
@@ -1176,10 +1176,31 @@ class WebGLInterface {
|
||||
function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
const MAX_INFO_CONSOLE_LINES = 512;
|
||||
let infoConsoleLines = new Array();
|
||||
let currentLine = "";
|
||||
|
||||
const addConsoleLine = (line) => {
|
||||
if (!line) {
|
||||
return;
|
||||
}
|
||||
if (!line.includes("\n")) {
|
||||
currentLine = currentLine.concat(line);
|
||||
} else {
|
||||
let printLast = line.endsWith("\n");
|
||||
let lines = line.split("\n");
|
||||
for (let i = 0; i < lines.length-1; i++) {
|
||||
let theLine = lines[i].trim("\r");
|
||||
currentLine = currentLine.concat(line);
|
||||
console.log(currentLine);
|
||||
currentLine = "";
|
||||
}
|
||||
console.log(lines);
|
||||
if (printLast) {
|
||||
console.log(lines[lines.length-1]);
|
||||
} else {
|
||||
currentLine = currentLine.concat(lines[lines.length-1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (line.endsWith("\n")) {
|
||||
line = line.substring(0, line.length-1);
|
||||
} else if (infoConsoleLines.length > 0) {
|
||||
@@ -1191,16 +1212,15 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement) {
|
||||
if (infoConsoleLines.length > MAX_INFO_CONSOLE_LINES) {
|
||||
infoConsoleLines.shift();
|
||||
}
|
||||
|
||||
let data = "";
|
||||
for (let i = 0; i < infoConsoleLines.length; i++) {
|
||||
if (i != 0) {
|
||||
data = data.concat("\n");
|
||||
}
|
||||
data = data.concat(infoConsoleLines[i]);
|
||||
}
|
||||
|
||||
if (consoleElement) {
|
||||
let data = "";
|
||||
for (let i = 0; i < infoConsoleLines.length; i++) {
|
||||
if (i != 0) {
|
||||
data = data.concat("\n");
|
||||
}
|
||||
data = data.concat(infoConsoleLines[i]);
|
||||
}
|
||||
|
||||
let info = consoleElement;
|
||||
info.innerHTML = data;
|
||||
info.scrollTop = info.scrollHeight;
|
||||
|
||||
Reference in New Issue
Block a user