cleaned: implementation details of closures
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 14 Feb 2024 05:21:28 +0000 (23:21 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 14 Feb 2024 05:21:28 +0000 (23:21 -0600)
This change reduces the complexity of function closure by removing the `closure_size` property on functions, and instead moves this information into the first 8 bytes of the closure block that is allocated. This means that closure blocks are slightly larger, but this extra field that pushes complexity to the end user is eliminated. Net win.

compiler/src/checker.c
compiler/src/types.c
compiler/src/wasm_emit.c
compiler/src/wasm_type_table.h
core/alloc/alloc.onyx
core/runtime/platform/wasi/platform.onyx
core/runtime/platform/wasi/wasi_defs.onyx
core/runtime/platform/wasi/wasi_fs.onyx
core/runtime/platform/wasi/wasix_net.onyx
runtime/src/ort_threads.h

index 1760594a1f7af066f3e613dfc5c472b832b6af69..57d436c5f97f2db395de4fa5003f95ade5875228 100644 (file)
@@ -2761,7 +2761,9 @@ CheckStatus check_directive_export_name(AstDirectiveExportName *ename) {
 }
 
 CheckStatus check_capture_block(AstCaptureBlock *block) {
-    block->total_size_in_bytes = 0;
+    //
+    // Reserve 8 bytes at the beginning of the closure block for the size of the closure.
+    block->total_size_in_bytes = 8;
 
     bh_arr_each(AstCaptureLocal *, capture, block->captures) {
         CHECK(expression, (AstTyped **) capture);
index 93080800a90931da26d046d5402a8759cca33c28..d886c66a764e0777593d37daa4e9d37e6f77b634 100644 (file)
@@ -259,13 +259,13 @@ u32 type_size_of(Type* type) {
         case Type_Kind_Basic:    return type->Basic.size;
         case Type_Kind_MultiPointer:
         case Type_Kind_Pointer:  return POINTER_SIZE;
-        case Type_Kind_Function: return 3 * POINTER_SIZE;
+        case Type_Kind_Function: return 2 * POINTER_SIZE;
         case Type_Kind_Array:    return type->Array.size;
         case Type_Kind_Struct:   return type->Struct.size;
         case Type_Kind_Enum:     return type_size_of(type->Enum.backing);
         case Type_Kind_Slice:    return POINTER_SIZE * 2; // HACK: These should not have to be 16 bytes in size, they should only have to be 12,
         case Type_Kind_VarArgs:  return POINTER_SIZE * 2; // but there are alignment issues right now with that so I decided to not fight it and just make them 16 bytes in size.
-        case Type_Kind_DynArray: return POINTER_SIZE + 8 + 8 + 2 * POINTER_SIZE; // data (8), count (4), capacity (4), allocator { func (4 + 4 + 8), data (8) }
+        case Type_Kind_DynArray: return POINTER_SIZE * 3 + POINTER_SIZE * 2 + POINTER_SIZE; // data (8), count (4), capacity (4), allocator { func (4 + 4 + 8), data (8) }
         case Type_Kind_Compound: return type->Compound.size;
         case Type_Kind_Distinct: return type_size_of(type->Distinct.base_type);
         case Type_Kind_Union:    return type->Union.size;
@@ -1444,7 +1444,6 @@ static const StructMember array_members[] = {
 static const StructMember func_members[] = {
     { 0,                0, &basic_types[Basic_Kind_U32],    "__funcidx",    NULL, NULL, -1, 0, 0 },
     { POINTER_SIZE,     1, &basic_types[Basic_Kind_Rawptr], "closure",      NULL, NULL, -1, 0, 0 },
-    { 2 * POINTER_SIZE, 2, &basic_types[Basic_Kind_U32],    "closure_size", NULL, NULL, -1, 0, 0 },
 };
 
 static const StructMember union_members[] = {
@@ -1550,7 +1549,7 @@ b32 type_lookup_member_by_idx(Type* type, i32 idx, StructMember* smem) {
         }
 
         case Type_Kind_Function: {
-            if (idx > 2) return 0;
+            if (idx > 1) return 0;
 
             *smem = func_members[idx];
             return 1;
@@ -1581,7 +1580,7 @@ i32 type_linear_member_count(Type* type) {
     switch (type->kind) {
         case Type_Kind_Slice:
         case Type_Kind_VarArgs:  return 2;
-        case Type_Kind_Function: return 3;
+        case Type_Kind_Function: return 2;
         case Type_Kind_Compound: return bh_arr_length(type->Compound.linear_members);
         case Type_Kind_Distinct: return type_linear_member_count(type->Distinct.base_type);
         default: return 1;
@@ -1637,10 +1636,6 @@ b32 type_linear_member_lookup(Type* type, i32 idx, TypeWithOffset* two) {
                 two->type = &basic_types[Basic_Kind_Rawptr];
                 two->offset = POINTER_SIZE;
             }
-            if (idx == 2) {
-                two->type = &basic_types[Basic_Kind_U32];
-                two->offset = 2 * POINTER_SIZE;
-            }
             return 1;
 
         default: {
@@ -1682,7 +1677,6 @@ i32 type_get_idx_of_linear_member_with_offset(Type* type, u32 offset) {
         case Type_Kind_Function: {
             if (offset == 0) return 0;
             if (offset == POINTER_SIZE) return 1;
-            if (offset == POINTER_SIZE * 2) return 2;
             return -1;
         }
         default:
@@ -1828,7 +1822,7 @@ u32 type_structlike_mem_count(Type* type) {
         case Type_Kind_Struct:   return type->Struct.mem_count;
         case Type_Kind_Slice:    return 2;
         case Type_Kind_VarArgs:  return 2;
-        case Type_Kind_Function: return 3;
+        case Type_Kind_Function: return 2;
         case Type_Kind_DynArray: return 4;
         case Type_Kind_Distinct: return type_structlike_mem_count(type->Distinct.base_type);
         case Type_Kind_Union:    return 2;
index addef11400a58a003c3608ebcbd2c2bf019570ed..0c067fe287104baf3317f0cb2af97e9872272446 100644 (file)
@@ -1536,13 +1536,10 @@ EMIT_FUNC(for_iterator, AstFor* for_node, u64 iter_local, i64 index_local) {
     u64 iterator_remove_func = local_raw_allocate(mod->local_alloc, WASM_TYPE_FUNC);
     u64 iterator_done_bool   = local_raw_allocate(mod->local_alloc, WASM_TYPE_INT32);
     WI(for_node->token, WI_DROP);
-    WI(for_node->token, WI_DROP);
     WIL(for_node->token, WI_LOCAL_SET, iterator_remove_func);
     WI(for_node->token, WI_DROP);
-    WI(for_node->token, WI_DROP);
     WIL(for_node->token, WI_LOCAL_SET, iterator_close_func);
     WI(for_node->token, WI_DROP);
-    WI(for_node->token, WI_DROP);
     WIL(for_node->token, WI_LOCAL_SET, iterator_next_func);
     WIL(for_node->token, WI_LOCAL_SET, iterator_data_ptr);
 
@@ -2044,14 +2041,12 @@ EMIT_FUNC(binop, AstBinaryOp* binop) {
     }
 
     emit_expression(mod, &code, binop->left);
-    if (binop->left->type->kind == Type_Kind_Function) { // nocheckin
-        WI(NULL, WI_DROP);
+    if (binop->left->type->kind == Type_Kind_Function) {
         WI(NULL, WI_DROP);
     }
 
     emit_expression(mod, &code, binop->right);
-    if (binop->right->type->kind == Type_Kind_Function) { // nocheckin
-        WI(NULL, WI_DROP);
+    if (binop->right->type->kind == Type_Kind_Function) {
         WI(NULL, WI_DROP);
     }
 
@@ -2367,7 +2362,6 @@ EMIT_FUNC(call, AstCall* call) {
         emit_expression(mod, &code, call->callee);
 
         u64 global_closure_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_closure_base);
-        WI(NULL, WI_DROP);
         WIL(NULL, WI_GLOBAL_SET, global_closure_base_idx);
 
         i32 type_idx = generate_type_idx(mod, call->callee->type);
@@ -3666,7 +3660,6 @@ EMIT_FUNC(expression, AstTyped* expr) {
             WID(NULL, WI_I32_CONST, elemidx);
             if (!func->captures) {
                 WIL(NULL, WI_PTR_CONST, 0);
-                WIL(NULL, WI_I32_CONST, 0);
                 break;
             }
 
@@ -3686,6 +3679,10 @@ EMIT_FUNC(expression, AstTyped* expr) {
             u64 capture_block_ptr = local_raw_allocate(mod->local_alloc, WASM_TYPE_PTR);
             WIL(NULL, WI_LOCAL_TEE, capture_block_ptr);
 
+            WIL(NULL, WI_LOCAL_GET, capture_block_ptr);
+            WIL(NULL, WI_I32_CONST, func->captures->total_size_in_bytes);
+            emit_store_instruction(mod, &code, &basic_types[Basic_Kind_U32], 0);
+
             // Populate the block
             bh_arr_each(AstCaptureLocal *, capture, func->captures->captures) {
                 WIL(NULL, WI_LOCAL_GET, capture_block_ptr);
@@ -3699,9 +3696,6 @@ EMIT_FUNC(expression, AstTyped* expr) {
                 emit_store_instruction(mod, &code, (*capture)->type, (*capture)->offset);
             }
 
-            local_raw_free(mod->local_alloc, WASM_TYPE_PTR);
-
-            WIL(NULL, WI_I32_CONST, func->captures->total_size_in_bytes);
             break;
         }
 
@@ -4120,7 +4114,6 @@ EMIT_FUNC(cast, AstUnaryOp* cast) {
     }
 
     if (to->kind == Type_Kind_Basic && from->kind == Type_Kind_Function) {
-        WI(NULL, WI_DROP);
         WI(NULL, WI_DROP);
         *pcode = code;
         return;
@@ -4342,7 +4335,6 @@ EMIT_FUNC(zero_value_for_type, Type* type, OnyxToken* where, AstTyped *alloc_nod
     } else if (type->kind == Type_Kind_Function) {
         WID(NULL, WI_I32_CONST, mod->null_proc_func_idx);
         WIL(NULL, WI_I32_CONST, 0);
-        WIL(NULL, WI_I32_CONST, 0);
 
     } else if (type->kind == Type_Kind_Distinct) {
         emit_zero_value_for_type(mod, &code, type->Distinct.base_type, where, alloc_node);
@@ -4951,7 +4943,6 @@ static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset) {
         AstFunction* func = (AstFunction *) node;
         CE(u32, 0) = get_element_idx(ctx->module, func);
         CE(u32, 4) = 0;
-        CE(u32, 8) = 0;
         break;
     }
 
index f72e1b58f18b754074a9bedb2038e48e1ca5bb3e..9ed96a3d177c2f830b3118e0d45723be544b72e8 100644 (file)
@@ -415,7 +415,6 @@ static u64 build_type_table(OnyxWasmModule* module) {
                         u32 func_idx = get_element_idx(module, node);
                         bh_buffer_write_u32(&table_buffer, func_idx);
                         bh_buffer_write_u32(&table_buffer, 0);
-                        bh_buffer_write_u32(&table_buffer, 0);
                         
                         bh_arr_push(method_data, ((StructMethodData) {
                             .name_loc = name_loc,
@@ -679,7 +678,6 @@ static u64 build_type_table(OnyxWasmModule* module) {
                         u32 func_idx = 0; // get_element_idx(module, node);
                         bh_buffer_write_u32(&table_buffer, func_idx);
                         bh_buffer_write_u32(&table_buffer, 0);
-                        bh_buffer_write_u32(&table_buffer, 0);
                         
                         bh_arr_push(method_data, ((StructMethodData) {
                             .name_loc = name_loc,
@@ -1129,7 +1127,6 @@ static u64 build_tagged_procedures(OnyxWasmModule *module) {
 
         bh_buffer_write_u32(&tag_proc_buffer, get_element_idx(module, func));
         bh_buffer_write_u32(&tag_proc_buffer, 0);
-        bh_buffer_write_u32(&tag_proc_buffer, 0);
         bh_buffer_write_u32(&tag_proc_buffer, func->type->id);
         WRITE_SLICE(tag_array_base, tag_count);
         bh_buffer_write_u32(&tag_proc_buffer, func->entity->package->id);
index 4b5ab07f116c331076b77d5fecbf78833e577f81..0e0908c4a66fa508328155ecebc9f6af7f0ce47e 100644 (file)
@@ -78,10 +78,13 @@ on_temp :: macro (v: $V) -> &V {
 copy_closure :: (f: $F/type_is_function, a: Allocator) -> F {
     if !f.closure do return f;
 
-    new_closure := raw_alloc(a, f.closure_size);
-    memory.copy(new_closure, f.closure, f.closure_size);
+    //
+    // The size of the closure block is stored at offset 0 inside of the closure data.
+    closure_size := *cast(&u32, f.closure);
+    new_closure := raw_alloc(a, closure_size);
+    memory.copy(new_closure, f.closure, closure_size);
 
-    return F.{ f.__funcidx, new_closure, f.closure_size };
+    return F.{ f.__funcidx, new_closure };
 }
 
 TEMPORARY_ALLOCATOR_SIZE :: 1 << 16; // 16Kb
index 17bc1757995e676a81f8729f88d74e0e49b0a4fd..918392e73765af6657bc7226df9416dc87e7e6f8 100644 (file)
@@ -152,7 +152,7 @@ __random_get :: (buf: [] u8) {
 
 PollDescription :: struct {
     fd: wasi.FileDescriptor;
-    in: core.io.PollEvent;
+    input: core.io.PollEvent;
     out: core.io.PollEvent;
 }
 
@@ -169,7 +169,7 @@ __poll :: (fds: [] PollDescription, timeout: i32) -> void {
     subs := core.alloc.array_from_stack(wasi.Subscription, count);
     for i in fds.count {
         subs[i].userdata = ~~ i;
-        subs[i].u.tag = switch fds[i].in {
+        subs[i].u.tag = switch fds[i].input {
             case .None => .FDRead;
             case .Read => .FDRead;
             case .Write => .FDWrite;
@@ -199,7 +199,7 @@ __poll :: (fds: [] PollDescription, timeout: i32) -> void {
         if ev.type !=.Clock {
             if ev.fd_readwrite.nbytes > 0 {
                 i := cast(i32) ev.userdata;
-                fds[i].out = fds[i].in;
+                fds[i].out = fds[i].input;
             }
 
             if ev.fd_readwrite.flags & .ReadWriteHangUp {
index abd1517a98a79c61620d83ed681d26f45669fdd4..16688d93fe752d6170b49df290a2d5d5fa3306b2 100644 (file)
@@ -422,7 +422,7 @@ path_rename  :: (fd: FileDescriptor, old_path: str, new_fd: FileDescriptor, new_
 path_symlink :: (old_path: &u8, old_path_len: Size, fd: FileDescriptor, new_path: str) -> Errno #foreign WASI_VERSION "path_symlink" ---
 path_unlink_file :: (fd: FileDescriptor, path: str) -> Errno #foreign WASI_VERSION "path_unlink_file" ---
 
-poll_oneoff :: (in: &Subscription, out: &Event, nsubscriptions: Size, nevents: &Size) -> Errno #foreign WASI_VERSION "poll_oneoff" ---
+poll_oneoff :: (input: &Subscription, out: &Event, nsubscriptions: Size, nevents: &Size) -> Errno #foreign WASI_VERSION "poll_oneoff" ---
 
 proc_exit  :: (rval: ExitCode) -> void #foreign WASI_VERSION "proc_exit" ---
 proc_raise :: (sig: Signal) -> Errno #foreign WASI_VERSION "proc_raise" ---
index ba6f0b8654f03dcfc0200d2b149808004c1f1f1b..09300f6a407fb902b14e9b17f34209d7c0dff061 100644 (file)
@@ -265,7 +265,7 @@ __file_stream_vtable := io.Stream_Vtable.{
     poll = (use fs: &os.File, ev: io.PollEvent, timeout: i32) -> (io.Error, bool) {
         p: [1] PollDescription = .[.{
             fd = data.fd,
-            in = ev,
+            input = ev,
         }];
 
         runtime.platform.__poll(p, timeout);
index ee47f6d8cdc270fff829dbf8e73e31a3c310e4fd..612ca9a46d6e567defc21e746e7d7a745639d90a 100644 (file)
@@ -181,8 +181,8 @@ __net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
 
 
 #package {
-    socket_addr_to_wasix_addr :: (in: &SocketAddress, out: &wasi.AddrPort) {
-        switch *in {
+    socket_addr_to_wasix_addr :: (input: &SocketAddress, out: &wasi.AddrPort) {
+        switch *innput {
             case .Unix as &path {
                 *out = .{ Unix = .{ *cast(&[108] u8) path } };
             }
@@ -200,8 +200,8 @@ __net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
         }
     }
 
-    wasi_addr_to_socket_address :: (in: &wasi.AddrPort, out: &SocketAddress) {
-        switch *in {
+    wasi_addr_to_socket_address :: (input: &wasi.AddrPort, out: &SocketAddress) {
+        switch *input {
             case .Unspec ---
 
             case .Ipv4 as &inet {
@@ -218,4 +218,4 @@ __net_resolve :: (host: str, port: u16, out_addrs: [] SocketAddress) -> i32 {
             }
         }
     }
-}
\ No newline at end of file
+}
index 7dc470b31ba6225c7c48c0dd181b7f690fdea820..0cbdcf22bdc655b87cba33d5c99a8770f6f7cc6c 100644 (file)
@@ -46,13 +46,12 @@ static i32 onyx_run_thread(void *data) {
     i32 thread_id = thread->id;
 
     { // Call the _thread_start procedure
-        wasm_val_t args[7]    = {
+        wasm_val_t args[6]    = {
             WASM_I32_VAL(thread_id),
             WASM_I32_VAL(thread->tls_base),
             WASM_I32_VAL(thread->stack_base),
             WASM_I32_VAL(thread->funcidx),
             WASM_I32_VAL(thread->closureptr),
-            WASM_I32_VAL(0),
             WASM_I32_VAL(thread->dataptr)
         };
         wasm_val_vec_t results = { 0, 0 };
@@ -78,7 +77,7 @@ static i32 onyx_run_thread(void *data) {
     return 0;
 }
 
-ONYX_DEF(__spawn_thread, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(__spawn_thread, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     if (threads == NULL) bh_arr_new(bh_heap_allocator(), threads, 128);
     bh_arr_insert_end(threads, 1);
     OnyxThread *thread = &bh_arr_last(threads);
@@ -88,7 +87,7 @@ ONYX_DEF(__spawn_thread, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM
     thread->stack_base = params->data[2].of.i32;
     thread->funcidx    = params->data[3].of.i32;
     thread->closureptr = params->data[4].of.i32;
-    thread->dataptr    = params->data[6].of.i32;
+    thread->dataptr    = params->data[5].of.i32;
 
     wasm_trap_t* traps = NULL;
     thread->instance = runtime->wasm_instance_new(runtime->wasm_store, runtime->wasm_module, &runtime->wasm_imports, &traps);