Converted to using a proper stack system; many improvements will be needed but it...
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 7 Aug 2020 18:55:14 +0000 (13:55 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 7 Aug 2020 18:55:14 +0000 (13:55 -0500)
Makefile
docs/plan
include/onyxastnodes.h
include/onyxwasm.h
onyx
progs/stack_based.onyx [new file with mode: 0644]
src/onyx.c
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index 0e514db6108e81017afbacf2eac82318593c4738..6a575b282e20f57fc1e2e7133d374497dbadb4ff 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-RELEASE=1
+RELEASE=0
 
 OBJ_FILES=\
        build/onyxlex.o \
index 25846cec17a548faec6c54ef0d205bdde89f30bc..b26d4beb1cdf6097f5d6217f184000367ec0d8e4 100644 (file)
--- a/docs/plan
+++ b/docs/plan
@@ -144,6 +144,14 @@ HOW:
 
         [X] #file_contents
 
+        [X] Convert to using a proper stack based system
+
+        [ ] Be smart about when to use the stack versus use the wasm locals
+
+        [ ] Array literals
+
+        [ ] Properly checking binary operators
+
         [ ] Better checking for casts
 
         [ ] All code paths return correct value
index 3f03c4e299002717cc7a60d4268228ae7c7199ac..63a1f95d94dedf8e7dac70e5a0fa1ad0dc24e9c9 100644 (file)
@@ -129,27 +129,32 @@ typedef enum AstKind {
 // only 32-bits of flags to play with
 typedef enum AstFlags {
     // Top-level flags
-    Ast_Flag_Exported         = BH_BIT(0),
-    Ast_Flag_Foreign          = BH_BIT(1),
-    Ast_Flag_Const            = BH_BIT(2),
-    Ast_Flag_Comptime         = BH_BIT(3),
-    Ast_Flag_Private_Package  = BH_BIT(4),
+    Ast_Flag_Exported          = BH_BIT(0),
+    Ast_Flag_Foreign           = BH_BIT(1),
+    Ast_Flag_Const             = BH_BIT(2),
+    Ast_Flag_Comptime          = BH_BIT(3),
+    Ast_Flag_Private_Package   = BH_BIT(4),
+
+    // Global flags
+    Ast_Flag_Global_Stack_Top  = BH_BIT(8),
+    Ast_Flag_Global_Stack_Base = BH_BIT(9),
 
     // Function flags
-    Ast_Flag_Inline           = BH_BIT(8),
-    Ast_Flag_Intrinsic        = BH_BIT(9),
-    Ast_Flag_Function_Used    = BH_BIT(10),
+    Ast_Flag_Inline            = BH_BIT(8),
+    Ast_Flag_Intrinsic         = BH_BIT(9),
+    Ast_Flag_Function_Used     = BH_BIT(10),
+    Ast_Flag_No_Stack          = BH_BIT(11),
 
     // Expression flags
-    Ast_Flag_Expr_Ignored     = BH_BIT(8),
-    Ast_Flag_Param_Splatted   = BH_BIT(9),
-    Ast_Flag_Param_Use        = BH_BIT(10),
+    Ast_Flag_Expr_Ignored      = BH_BIT(8),
+    Ast_Flag_Param_Splatted    = BH_BIT(9),
+    Ast_Flag_Param_Use         = BH_BIT(10),
 
     // Type flags
-    Ast_Flag_Type_Is_Resolved = BH_BIT(8),
+    Ast_Flag_Type_Is_Resolved  = BH_BIT(8),
 
     // Enum flags
-    Ast_Flag_Enum_Is_Flags    = BH_BIT(11),
+    Ast_Flag_Enum_Is_Flags     = BH_BIT(11),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -475,6 +480,8 @@ extern AstBasicType basic_type_f64;
 extern AstBasicType basic_type_rawptr;
 
 extern AstNumLit builtin_heap_start;
+extern AstGlobal builtin_stack_base;
+extern AstGlobal builtin_stack_top;
 
 typedef struct BuiltinSymbol {
     char*    sym;
index a42d78ac61ccb85b4041483446262815b206c4a1..4ef2ea3897df0c38c83f9f5e26e611871cdecf6d 100644 (file)
@@ -258,7 +258,7 @@ typedef struct WasmFunc {
 
 typedef struct WasmGlobal {
     WasmType type;
-    u8 mutable;
+    u32 mutable : 1;
     bh_arr(WasmInstruction) initial_value;
 } WasmGlobal;
 
@@ -296,7 +296,7 @@ typedef struct OnyxWasmModule {
     // NOTE: Mapping ptrs to function / global indicies
     bh_imap index_map;
 
-    // NOTE: Mapping from local ast node ptrs to indicies
+    // NOTE: Mapping from local ast node ptrs to indicies or offsets, depending on the mode
     bh_imap local_map;
 
     // NOTE: Mapping ptrs to elements
@@ -329,6 +329,8 @@ typedef struct OnyxWasmModule {
     u32 next_foreign_global_idx;
     u32 next_datum_offset;
     u32 next_elem_idx;
+
+    u32 *stack_top_ptr, *stack_base_ptr;
 } OnyxWasmModule;
 
 OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc);
diff --git a/onyx b/onyx
index 0210d24e20ff7011972b018e66bfeaf1e2d7cc26..8a908bc8b4819ce7a7d153424cc8909528907acc 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/progs/stack_based.onyx b/progs/stack_based.onyx
new file mode 100644 (file)
index 0000000..52e495f
--- /dev/null
@@ -0,0 +1,28 @@
+package main
+
+use "progs/print_funcs"
+
+use package printing
+
+ret_val :: proc (x: i32, y: i32) -> i32 {
+    big_arr : [128] i32;
+    big_arr[127] = 1234;
+    return big_arr[127] + x + y;
+}
+
+main :: proc #export {
+    print("Hello, World!");
+    print(cast(i32) __heap_start);
+    a := 12345;
+
+    arr : [5] i32;
+    arr[0] = 10;
+    arr[1] = 20;
+    arr[2] = 30;
+    arr[3] = 40;
+    arr[4] = 50;
+
+    print(ret_val(10, 4));
+    
+    for i: 0, 5 do print(arr[i]);
+}
\ No newline at end of file
index ba454ddae6da5ba89db6b79af92f611cf394b9cb..6be4e6f089fae0113eaa5e7de599b2540b3b457b 100644 (file)
@@ -267,11 +267,6 @@ static void merge_parse_results(CompilerState* compiler_state, ParseResults* res
             }
         }
     }
-
-    qsort(compiler_state->prog_info.entities,
-            bh_arr_length(compiler_state->prog_info.entities),
-            sizeof(Entity),
-            sort_entities);
 }
 
 static CompilerProgress process_source_file(CompilerState* compiler_state, char* filename) {
@@ -318,6 +313,28 @@ static i32 onyx_compile(CompilerState* compiler_state) {
         bh_arr_fastdelete(compiler_state->queued_files, 0);
     }
 
+    // Add builtin one-time entities
+    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
+        .type = Entity_Type_Global_Header,
+        .global = &builtin_stack_base
+    }));
+    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
+        .type = Entity_Type_Global_Header,
+        .global = &builtin_stack_top
+    }));
+    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
+        .type = Entity_Type_Global,
+        .global = &builtin_stack_base
+    }));
+    bh_arr_push(compiler_state->prog_info.entities, ((Entity) {
+        .type = Entity_Type_Global,
+        .global = &builtin_stack_top
+    }));
+
+    qsort(compiler_state->prog_info.entities,
+            bh_arr_length(compiler_state->prog_info.entities),
+            sizeof(Entity),
+            sort_entities);
 
     // NOTE: Check types and semantic rules
     if (compiler_state->options->verbose_output)
index 64390bcfed674be10392e8c7063467c16b3fb454..0b9a9c4107bdba2f28eaaed4b3b8253d0d7949f5 100644 (file)
@@ -576,7 +576,8 @@ CHECK(address_of, AstAddressOf* aof) {
     if (aof->expr->kind != Ast_Kind_Array_Access
             && aof->expr->kind != Ast_Kind_Dereference
             && aof->expr->kind != Ast_Kind_Field_Access
-            && aof->expr->kind != Ast_Kind_Memres) {
+            && aof->expr->kind != Ast_Kind_Memres
+            && aof->expr->kind != Ast_Kind_Local) {
         onyx_message_add(Msg_Type_Literal,
                 aof->token->pos,
                 "cannot take the address of this");
index e8097273235c071faaeffef37de42df20f46799f..2a7b53c42aa28f6c59034a25893f036664e8aca3 100644 (file)
@@ -1115,6 +1115,10 @@ static AstFunction* parse_function_definition(OnyxParser* parser) {
             }
         }
 
+        else if (parse_possible_directive(parser, "nostack")) {
+            func_def->flags |= Ast_Flag_No_Stack;
+        }
+
         else {
             OnyxToken* directive_token = expect_token(parser, '#');
             OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
index 5f0a28694c473ab53eb189768157771504da5a79..0320cab49a7e6b1e5cb1d740e2766d9012f6e6db 100644 (file)
@@ -19,7 +19,11 @@ AstBasicType basic_type_f64    = { { Ast_Kind_Basic_Type, 0, NULL, "f64"    }, &
 AstBasicType basic_type_rawptr = { { Ast_Kind_Basic_Type, 0, NULL, "rawptr" }, &basic_types[Basic_Kind_Rawptr] };
 
 static OnyxToken builtin_heap_start_token = { Token_Type_Symbol, 12, "__heap_start ", { 0 } };
+static OnyxToken builtin_stack_base_token = { Token_Type_Symbol, 12, "__stack_base ", { 0 } };
+static OnyxToken builtin_stack_top_token  = { Token_Type_Symbol, 11, "__stack_top ",  { 0 } };
 AstNumLit builtin_heap_start = { Ast_Kind_NumLit, Ast_Flag_Const, &builtin_heap_start_token, NULL, (AstType *) &basic_type_rawptr, NULL, 0 };
+AstGlobal builtin_stack_base = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Base, &builtin_stack_base_token, NULL, (AstType *) &basic_type_rawptr, NULL };
+AstGlobal builtin_stack_top  = { Ast_Kind_Global, Ast_Flag_Const | Ast_Flag_Global_Stack_Top,  &builtin_stack_top_token,  NULL, (AstType *) &basic_type_rawptr, NULL };
 
 const BuiltinSymbol builtin_symbols[] = {
     { "void",       (AstNode *) &basic_type_void },
@@ -37,6 +41,8 @@ const BuiltinSymbol builtin_symbols[] = {
     { "rawptr",     (AstNode *) &basic_type_rawptr },
 
     { "__heap_start", (AstNode *) &builtin_heap_start },
+    { "__stack_base", (AstNode *) &builtin_stack_base },
+    { "__stack_top",  (AstNode *) &builtin_stack_top },
 
     { NULL, NULL },
 };
@@ -524,8 +530,10 @@ void onyx_resolve_symbols() {
     }
 
     bh_arr_each(Entity, entity, semstate.program->entities) {
-        scope_enter(entity->package->private_scope);
-        semstate.curr_package = entity->package;
+        if (entity->package) {
+            scope_enter(entity->package->private_scope);
+            semstate.curr_package = entity->package;
+        }
 
         switch (entity->type) {
             case Entity_Type_Use_Package:         symres_use_package(entity->use_package); break;
@@ -540,6 +548,6 @@ void onyx_resolve_symbols() {
             default: break;
         }
 
-        scope_leave();
+        if (entity->package) scope_leave();
     }
 }
index 6c24c76a5213effc44b316b134df1d45729ab7ad..ad0d7811c8fd8e459d6d7910ede1c88f0734db65 100644 (file)
@@ -263,9 +263,12 @@ COMPILE_FUNC(call,                  AstCall* call);
 COMPILE_FUNC(intrinsic_call,        AstIntrinsicCall* call);
 COMPILE_FUNC(array_access_location, AstArrayAccess* aa, u64* offset_return);
 COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return);
+COMPILE_FUNC(local_location,        AstLocal* local, u64* offset_return);
 COMPILE_FUNC(expression,            AstTyped* expr);
 COMPILE_FUNC(cast,                  AstUnaryOp* cast);
 COMPILE_FUNC(return,                AstReturn* ret);
+COMPILE_FUNC(stack_enter,           u64 stacksize);
+COMPILE_FUNC(stack_leave,           u32 unused);
 
 COMPILE_FUNC(function_body, AstFunction* fd) {
     if (fd->body == NULL) return;
@@ -278,8 +281,6 @@ COMPILE_FUNC(function_body, AstFunction* fd) {
 
     compile_deferred_stmts(mod, &code, (AstNode *) fd);
 
-    WI(WI_BLOCK_END);
-
     *pcode = code;
 }
 
@@ -354,10 +355,10 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
     AstTyped* lval = assign->left;
 
     if (lval->kind == Ast_Kind_Local) {
-        i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) lval);
-
+        u64 offset = 0;
+        compile_local_location(mod, &code, (AstLocal *) lval, &offset);
         compile_expression(mod, &code, assign->right);
-        WID(WI_LOCAL_SET, localidx);
+        compile_store_instruction(mod, &code, lval->type, type_get_alignment_log2(lval->type), offset);
 
     } else if (lval->kind == Ast_Kind_Global) {
         i32 globalidx = (i32) bh_imap_get(&mod->index_map, (u64) lval);
@@ -557,10 +558,15 @@ COMPILE_FUNC(while, AstWhile* while_node) {
 COMPILE_FUNC(for, AstFor* for_node) {
     bh_arr(WasmInstruction) code = *pcode;
 
-    i32 it_idx = (i32) bh_imap_get(&mod->local_map, (u64) for_node->var);
+    // i32 it_idx = (i32) bh_imap_get(&mod->local_map, (u64) for_node->var);
 
+    AstLocal* var = for_node->var;
+
+    u64 offset = 0;
+    compile_local_location(mod, &code, var, &offset);
     compile_expression(mod, &code, for_node->start);
-    WID(WI_LOCAL_SET, it_idx);
+    compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+    //WID(WI_LOCAL_SET, it_idx);
 
     WID(WI_BLOCK_START, 0x40);
     WID(WI_LOOP_START, 0x40);
@@ -568,7 +574,10 @@ COMPILE_FUNC(for, AstFor* for_node) {
     bh_arr_push(mod->structured_jump_target, 1);
     bh_arr_push(mod->structured_jump_target, 2);
 
-    WID(WI_LOCAL_GET, it_idx);
+    offset = 0;
+    compile_local_location(mod, &code, var, &offset);
+    compile_load_instruction(mod, &code, var->type, offset);
+    // WID(WI_LOCAL_GET, it_idx);
     compile_expression(mod, &code, for_node->end);
     WI(WI_I32_GE_S);
     WID(WI_COND_JUMP, 0x01);
@@ -577,13 +586,19 @@ COMPILE_FUNC(for, AstFor* for_node) {
         compile_statement(mod, &code, stmt);
     }
 
+    offset = 0;
+    compile_local_location(mod, &code, var, &offset);
+    offset = 0;
+    compile_local_location(mod, &code, var, &offset);
+    compile_load_instruction(mod, &code, var->type, offset);
     if (for_node->step == NULL)
         WID(WI_I32_CONST, 0x01);
     else
         compile_expression(mod, &code, for_node->step);
-    WID(WI_LOCAL_GET, it_idx);
+    // WID(WI_LOCAL_GET, it_idx);
     WI(WI_I32_ADD);
-    WID(WI_LOCAL_SET, it_idx);
+    compile_store_instruction(mod, &code, var->type, type_get_alignment_log2(var->type), offset);
+    //WID(WI_LOCAL_SET, it_idx);
 
     compile_deferred_stmts(mod, &code, (AstNode *) for_node);
 
@@ -623,7 +638,7 @@ COMPILE_FUNC(deferred_stmts, AstNode* node) {
 // NOTE: These need to be in the same order as
 // the OnyxBinaryOp enum
 static const WasmInstructionType binop_map[][4] = {
-    //          I32           I64           F32         F64
+    //           I32           I64           F32         F64
     /* ADD */  { WI_I32_ADD,   WI_I64_ADD,   WI_F32_ADD, WI_F64_ADD },
     /* SUB */  { WI_I32_SUB,   WI_I64_SUB,   WI_F32_SUB, WI_F64_SUB },
     /* MUL */  { WI_I32_MUL,   WI_I64_MUL,   WI_F32_MUL, WI_F64_MUL },
@@ -856,6 +871,9 @@ COMPILE_FUNC(array_access_location, AstArrayAccess* aa, u64* offset_return) {
     } else if (aa->addr->kind == Ast_Kind_Field_Access
         && aa->addr->type->kind == Type_Kind_Array) {
         compile_field_access_location(mod, &code, (AstFieldAccess *) aa->addr, &offset);
+    } else if (aa->addr->kind == Ast_Kind_Local
+        && aa->addr->type->kind == Type_Kind_Array) {
+        compile_local_location(mod, &code, (AstLocal *) aa->addr, &offset);
     } else {
         compile_expression(mod, &code, aa->addr);
     }
@@ -882,6 +900,11 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
         u64 o2 = 0;
         compile_array_access_location(mod, &code, (AstArrayAccess *) source_expr, &o2);
         offset += o2;
+    } else if (source_expr->kind == Ast_Kind_Local
+        && source_expr->type->kind != Type_Kind_Pointer) {
+        u64 o2 = 0;
+        compile_local_location(mod, &code, (AstLocal *) source_expr, &o2);
+        offset += o2;
     } else {
         compile_expression(mod, &code, source_expr);
     }
@@ -891,11 +914,23 @@ COMPILE_FUNC(field_access_location, AstFieldAccess* field, u64* offset_return) {
     *pcode = code;
 }
 
+COMPILE_FUNC(local_location, AstLocal* local, u64* offset_return) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    i32 stack_base_idx = (i32) bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
+    i32 local_offset = (i32) bh_imap_get(&mod->local_map, (u64) local);
+
+    WID(WI_GLOBAL_GET, stack_base_idx);
+
+    *offset_return += local_offset;
+
+    *pcode = code;
+}
+
 COMPILE_FUNC(expression, AstTyped* expr) {
     bh_arr(WasmInstruction) code = *pcode;
 
     switch (expr->kind) {
-        case Ast_Kind_Local:
         case Ast_Kind_Param: {
             i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) expr);
 
@@ -903,6 +938,13 @@ COMPILE_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Local: {
+            u64 offset = 0;
+            compile_local_location(mod, &code, (AstLocal *) expr, &offset);
+            compile_load_instruction(mod, &code, expr->type, offset);
+            break;
+        }
+
         case Ast_Kind_Global: {
             i32 globalidx = (i32) bh_imap_get(&mod->index_map, (u64) expr);
 
@@ -954,6 +996,14 @@ COMPILE_FUNC(expression, AstTyped* expr) {
             AstAddressOf* aof = (AstAddressOf *) expr;
 
             switch (aof->expr->kind) {
+                case Ast_Kind_Local: {
+                    u64 offset = 0;
+                    compile_local_location(mod, &code, (AstLocal *) aof->expr, &offset);
+                    WID(WI_I32_CONST, offset);
+                    WI(WI_I32_ADD);
+                    break;
+                }
+
                 case Ast_Kind_Dereference: {
                     compile_expression(mod, &code, ((AstDereference *) aof->expr)->expr);
                     break;
@@ -1206,11 +1256,57 @@ COMPILE_FUNC(return, AstReturn* ret) {
         } 
     }
 
+    compile_stack_leave(mod, &code, 0);
+
     WI(WI_RETURN);
 
     *pcode = code;
 }
 
+COMPILE_FUNC(stack_enter, u64 stacksize) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    u32 stack_top_idx  = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top);
+    u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
+
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_GLOBAL_GET, stack_base_idx);
+    WID(WI_I32_STORE, ((WasmInstructionData) { 2, 0 }));
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_I32_CONST, 4);
+    WI(WI_I32_ADD);
+    WID(WI_GLOBAL_SET, stack_top_idx);
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_GLOBAL_SET, stack_base_idx);
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_I32_CONST, stacksize);
+    WI(WI_I32_ADD);
+    WID(WI_GLOBAL_SET, stack_top_idx);
+
+    *pcode = code;
+}
+
+COMPILE_FUNC(stack_leave, u32 unused) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    u32 stack_top_idx  = bh_imap_get(&mod->index_map, (u64) &builtin_stack_top);
+    u32 stack_base_idx = bh_imap_get(&mod->index_map, (u64) &builtin_stack_base);
+
+    WID(WI_GLOBAL_GET, stack_base_idx);
+    WID(WI_GLOBAL_SET, stack_top_idx);
+
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_I32_CONST, 4);
+    WI(WI_I32_SUB);
+    WID(WI_GLOBAL_SET, stack_top_idx);
+
+    WID(WI_GLOBAL_GET, stack_top_idx);
+    WID(WI_I32_LOAD, ((WasmInstructionData) { 2, 0 }));
+    WID(WI_GLOBAL_SET, stack_base_idx);
+
+    *pcode = code;
+}
+
 static i32 generate_type_idx(OnyxWasmModule* mod, Type* ft) {
     if (ft->kind != Type_Kind_Function) return -1;
 
@@ -1337,37 +1433,51 @@ static void compile_function(OnyxWasmModule* mod, AstFunction* fd) {
 
     // If there is no body then don't process the code
     if (fd->body != NULL) {
-        // NOTE: Generate the local map
+        // // NOTE: Generate the local map
         i32 localidx = 0;
         for (AstLocal *param = fd->params; param != NULL; param = (AstLocal *) param->next) {
             bh_imap_put(&mod->local_map, (u64) param, localidx++);
         }
 
-        static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
+        // static const WasmType local_types[4] = { WASM_TYPE_INT32, WASM_TYPE_INT64, WASM_TYPE_FLOAT32, WASM_TYPE_FLOAT64 };
 
-        // HACK: This assumes that the order of the count members
-        // is the same as the order of the local_types above
-        u8* count = &wasm_func.locals.i32_count;
-        fori (ti, 0, 3) {
-            bh_arr_each(AstLocal *, local, fd->locals) {
-                if (onyx_type_to_wasm_type((*local)->type) == local_types[ti]) {
-                    bh_imap_put(&mod->local_map, (u64) *local, localidx++);
+        // // HACK: This assumes that the order of the count members
+        // // is the same as the order of the local_types above
+        // u8* count = &wasm_func.locals.i32_count;
+        // fori (ti, 0, 3) {
+        //     bh_arr_each(AstLocal *, local, fd->locals) {
+        //         if (onyx_type_to_wasm_type((*local)->type) == local_types[ti]) {
+        //             bh_imap_put(&mod->local_map, (u64) *local, localidx++);
 
-                    (*count)++;
-                }
-            }
+        //             (*count)++;
+        //         }
+        //     }
+
+        //     count++;
+        // }
 
-            count++;
+        i32 offset = 0;
+        bh_arr_each(AstLocal *, local, fd->locals) {
+            u32 size  = type_size_of((*local)->type);
+            u32 align = type_alignment_of((*local)->type);
+            if (offset % align != 0)
+                offset += align - (offset % align);
+
+            bh_imap_put(&mod->local_map, (u64) *local, offset);
+            offset += size;
         }
 
+        if (offset % 16 != 0)
+            offset += 16 - (offset % 16);
+
         // Generate code
+        compile_stack_enter(mod, &wasm_func.code, (u64) offset);
         compile_function_body(mod, &wasm_func.code, fd);
-
-    } else {
-        // NOTE: Empty bodies still need a block end instruction
-        bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+        compile_stack_leave(mod, &wasm_func.code, 0);
     }
 
+    bh_arr_push(wasm_func.code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+
     bh_arr_push(mod->funcs, wasm_func);
 
     // NOTE: Clear the local map on exit of generating this function
@@ -1422,6 +1532,12 @@ static void compile_global(OnyxWasmModule* module, AstGlobal* global) {
     }
 
     bh_arr_push(module->globals, glob);
+
+    if (global->flags & Ast_Flag_Global_Stack_Top)
+        module->stack_top_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1;
+    if (global->flags & Ast_Flag_Global_Stack_Base)
+        module->stack_base_ptr = &bh_arr_last(module->globals).initial_value[0].data.i1;
+
 }
 
 static void compile_string_literal(OnyxWasmModule* mod, AstStrLit* strlit) {
@@ -1527,6 +1643,8 @@ static void compile_file_contents(OnyxWasmModule* mod, AstFileContents* fc) {
 
     bh_arr_push(mod->data, datum);
 
+    mod->next_datum_offset = offset + length;
+
     token_toggle_end(fc->filename);
 }
 
@@ -1558,6 +1676,9 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
         .next_elem_idx = 0,
 
         .structured_jump_target = NULL,
+
+        .stack_top_ptr = NULL,
+        .stack_base_ptr = NULL,
     };
 
     bh_arr_new(alloc, module.types, 4);
@@ -1597,12 +1718,21 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, ProgramInfo* program) {
 
     bh_arr_each(Entity, entity, program->entities) {
 
-        // HACK: To put this here
-        // NOTE: Round up to the nearest multiple of 16
-        builtin_heap_start.value.i =
-            (module->next_datum_offset & 15)
-            ? ((module->next_datum_offset >> 4) + 1) << 4
-            : module->next_datum_offset;
+        if (module->stack_base_ptr) {
+            *module->stack_base_ptr = module->next_datum_offset;
+
+            if (*module->stack_base_ptr % 16 != 0) {
+                *module->stack_base_ptr += 16 - (*module->stack_base_ptr % 16);
+            }
+
+            if (module->stack_top_ptr)
+                *module->stack_top_ptr = *module->stack_base_ptr;
+
+            builtin_heap_start.value.i = *module->stack_base_ptr + (1 << 16);
+            if (builtin_heap_start.value.i % 16 != 0) {
+                builtin_heap_start.value.i += 16 - (builtin_heap_start.value.i % 16);
+            }
+        }
 
         switch (entity->type) {
             case Entity_Type_Function_Header: {
@@ -1833,7 +1963,7 @@ static i32 output_memorysection(OnyxWasmModule* module, bh_buffer* buff) {
     u8* leb = uint_to_uleb128((u64) 1, &leb_len);
     bh_buffer_append(&vec_buff, leb, leb_len);
 
-    output_limits(4, -1, &vec_buff);
+    output_limits(256, -1, &vec_buff);
 
     leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);
     bh_buffer_append(buff, leb, leb_len);
@@ -1857,7 +1987,7 @@ static i32 output_globalsection(OnyxWasmModule* module, bh_buffer* buff) {
 
     bh_arr_each(WasmGlobal, global, module->globals) {
         bh_buffer_write_byte(&vec_buff, global->type);
-        bh_buffer_write_byte(&vec_buff, global->mutable ? 0x01 : 0x00);
+        bh_buffer_write_byte(&vec_buff, 0x01);
 
         bh_arr_each(WasmInstruction, instr, global->initial_value)
             output_instruction(instr, &vec_buff);