Added initial version of globals
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 1 Jul 2020 03:40:32 +0000 (22:40 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 1 Jul 2020 03:40:32 +0000 (22:40 -0500)
More work will be needed; also, might remove the pointer to code style
in the WASM compilation step

include/onyxmsgs.h
include/onyxwasm.h
onyx
progs/test.onyx
src/onyx.c
src/onyxmsgs.c
src/onyxsymres.c
src/onyxtypecheck.c
src/onyxwasm.c

index ff268f45a0238d958e5ce3dd264e84c20e292100..f30c5b46ebe87b2672182fab305734a16b66ca2b 100644 (file)
@@ -16,9 +16,10 @@ typedef enum OnyxMessageType {
     ONYX_MESSAGE_TYPE_NOT_LVAL,
     ONYX_MESSAGE_TYPE_ASSIGN_CONST,
     ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL,
-    ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
+    ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
     ONYX_MESSAGE_TYPE_BINOP_MISMATCH_TYPE,
     ONYX_MESSAGE_TYPE_ASSIGNMENT_TYPE_MISMATCH,
+    ONYX_MESSAGE_TYPE_GLOBAL_TYPE_MISMATCH,
     ONYX_MESSAGE_TYPE_EXPECTED_EXPRESSION,
     ONYX_MESSAGE_TYPE_CALL_NON_FUNCTION,
 
index b86e2c5a9aad00d9218d18f149cc1141c6a55461..327b08b71dcfebad4e778cfa660cc1215c144b28 100644 (file)
@@ -4,6 +4,7 @@
 #include "bh.h"
 
 #include "onyxparser.h"
+#include "onyxmsgs.h"
 
 typedef u8 WasmType;
 
@@ -249,6 +250,12 @@ typedef struct WasmFunc {
     bh_arr(WasmInstruction) code;
 } WasmFunc;
 
+typedef struct WasmGlobal {
+    WasmType type;
+    u8 mutable;
+    bh_arr(WasmInstruction) initial_value;
+} WasmGlobal;
+
 typedef enum WasmForeignKind {
     WASM_FOREIGN_FUNCTION   = 0x00,
     WASM_FOREIGN_TABLE      = 0x01,
@@ -269,9 +276,11 @@ typedef struct WasmImport {
 
 typedef struct OnyxWasmModule {
     bh_allocator allocator;
+    OnyxMessages* msgs;
 
     // NOTE: Mapping from local ast node ptrs to indicies
     bh_imap local_map;
+    bh_imap global_map;
 
     bh_arr(u8) structured_jump_target;
 
@@ -288,13 +297,17 @@ typedef struct OnyxWasmModule {
 
     bh_arr(WasmImport) imports;
 
-    i32 next_type_idx;
-    i32 next_func_idx;
-    i32 next_import_func_idx;
-    i32 export_count;
+    bh_arr(WasmGlobal) globals;
+
+    u16 next_type_idx;
+    u16 next_func_idx;
+    u16 next_import_func_idx;
+    u16 next_global_idx;
+    u16 next_import_global_idx;
+    u16 export_count;
 } OnyxWasmModule;
 
-OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc);
+OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs);
 void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program);
 void onyx_wasm_module_free(OnyxWasmModule* module);
 void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file);
diff --git a/onyx b/onyx
index b186232adac92ad907a8b23da4511e362ccbdb4d..58c12bc7527a5e1e8d8915fb9b5ba72aae880c16 100755 (executable)
Binary files a/onyx and b/onyx differ
index a0a8af2fc5f2c22e35517baa2ac45886cb26c1ee..2cc07c3e70ab1768a5ebaf01a1311a9ef186196c 100644 (file)
@@ -22,10 +22,14 @@ something_else :: proc (n i32) -> i32 {
 // symbol := 5                  Global mutable variable
 // symbol : i32                 Global mutable i32 (defaults to 0 initial value)
 
-global_value := 5 + 6;
+global_value := 5;
+foreign_global :: foreign "dummy" "global" i32
 
 // This is the entry point
 export main :: proc {
+    print_i32(global_value);
+    print_i32(foreign_global);
+
     i := 0;
     while i < 10 {
         res :: fib(i);
index ec1d942057c73f7cc3df6317a89128081c66aa01..c63b3178d7368ff305d162a191f5be9a910e0661 100644 (file)
@@ -167,17 +167,12 @@ i32 onyx_compile(OnyxCompileOptions* opts, CompilerState* compiler_state) {
     OnyxSemPassState sp_state = onyx_sempass_create(compiler_state->sp_alloc, compiler_state->ast_alloc, &compiler_state->msgs);
     onyx_sempass(&sp_state, root_file);
 
-    if (opts->print_ast) {
-        onyx_ast_print((OnyxAstNode *) root_file, 0);
-        bh_printf("\n");
-    }
-
     if (onyx_message_has_errors(&compiler_state->msgs)) {
         return ONYX_COMPILER_PROGRESS_FAILED_SEMPASS;
     }
 
     bh_printf("Creating WASM code\n");
-    compiler_state->wasm_mod = onyx_wasm_module_create(opts->allocator);
+    compiler_state->wasm_mod = onyx_wasm_module_create(opts->allocator, &compiler_state->msgs);
     onyx_wasm_module_compile(&compiler_state->wasm_mod, root_file);
 
     if (onyx_message_has_errors(&compiler_state->msgs)) {
index abffedd49d0ffa86e79e56eba2f0fb014983686b..b05432a26fd815c0d509f07595256ee50eebe877 100644 (file)
@@ -9,9 +9,10 @@ static const char* msg_formats[] = {
     "expected lval '%b'",
     "attempt to assign to constant '%b'",
     "unknown symbol '%s'",
-    "redefinition of function '%s'",
+    "conflicting declarations of global '%s'",
     "mismatched types for binary operator, '%s', '%s'",
     "mismatched types on assignment, expected '%s', got '%s'",
+    "mismatched types for global '%b'; expected '%s', got '%s'",
     "expected expression, got '%s'",
     "attempt to call non-function, '%b'",
 
index 130b61cbae3ff1ad2eac81c74eb5383b34fd701f..636f05b6e9bb84d6a22a6a93ab7019c5bd6f384d 100644 (file)
@@ -2,11 +2,11 @@
 #include "onyxsempass.h"
 
 static void symbol_introduce(OnyxSemPassState* state, OnyxAstNode* symbol);
+static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxAstNode* symbol);
 static void symbol_remove(OnyxSemPassState* state, OnyxAstNode* symbol);
 static OnyxAstNode* symbol_resolve(OnyxSemPassState* state, OnyxAstNode* symbol);
 static void scope_enter(OnyxSemPassState* state, OnyxAstNodeScope* scope);
 static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state);
-static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func);
 static void symres_local(OnyxSemPassState* state, OnyxAstNodeLocal** local);
 static void symres_call(OnyxSemPassState* state, OnyxAstNode* call);
 static void symres_expression(OnyxSemPassState* state, OnyxAstNode** expr);
@@ -91,27 +91,27 @@ static OnyxAstNodeScope* scope_leave(OnyxSemPassState* state) {
     return state->curr_scope;
 }
 
-static b32 define_function(OnyxSemPassState* state, OnyxAstNodeFuncDef* func) {
-    onyx_token_null_toggle(*func->token);
+static b32 symbol_unique_introduce(OnyxSemPassState* state, OnyxAstNode* symbol) {
+    onyx_token_null_toggle(*symbol->token);
 
     // NOTE: If the function hasn't already been defined
-    if (!bh_table_has(SemPassSymbol *, state->symbols, func->token->token)) {
+    if (!bh_table_has(SemPassSymbol *, state->symbols, symbol->token->token)) {
         SemPassSymbol* sp_sym = bh_alloc_item(state->allocator, SemPassSymbol);
-        sp_sym->node = (OnyxAstNode *) func;
+        sp_sym->node = symbol;
         sp_sym->shadowed = NULL;
-        bh_table_put(SemPassSymbol *, state->symbols, func->token->token, sp_sym);
+        bh_table_put(SemPassSymbol *, state->symbols, symbol->token->token, sp_sym);
     } else {
         onyx_message_add(state->msgs,
-                ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION,
-                func->token->pos,
-                func->token->token);
+                ONYX_MESSAGE_TYPE_CONFLICTING_GLOBALS,
+                symbol->token->pos,
+                symbol->token->token);
 
         // NOTE: I really wish C had defer...
-        onyx_token_null_toggle(*func->token);
+        onyx_token_null_toggle(*symbol->token);
         return 0;
     }
 
-    onyx_token_null_toggle(*func->token);
+    onyx_token_null_toggle(*symbol->token);
     return 1;
 }
 
@@ -259,12 +259,14 @@ void onyx_resolve_symbols(OnyxSemPassState* state, OnyxAstNodeFile* root_node) {
         while (walker) {
             switch (walker->kind) {
                 case ONYX_AST_NODE_KIND_FUNCDEF:
-                    if (!define_function(state, &walker->as_funcdef)) return;
+                case ONYX_AST_NODE_KIND_GLOBAL:
+                    if (!symbol_unique_introduce(state, walker)) return;
                     break;
 
                 case ONYX_AST_NODE_KIND_FOREIGN:
-                    if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) {
-                        if (!define_function(state, &walker->as_foreign.import->as_funcdef)) return;
+                    if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF
+                            || walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_GLOBAL) {
+                        if (!symbol_unique_introduce(state, walker->as_foreign.import)) return;
                     }
                     break;
 
index ad23ea67767890e0aeb47da02e93e48036b82a89..7730a486f30e3b34332f79b2f446e0949a490b8b 100644 (file)
@@ -11,6 +11,7 @@ static void typecheck_if(OnyxSemPassState* state, OnyxAstNodeIf* ifnode);
 static void typecheck_while(OnyxSemPassState* state, OnyxAstNodeWhile* whilenode);
 static void typecheck_call(OnyxSemPassState* state, OnyxAstNodeCall* call);
 static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr);
+static void typecheck_global(OnyxSemPassState* state, OnyxAstNodeGlobal* global);
 
 static void typecheck_assignment(OnyxSemPassState* state, OnyxAstNode* assign) {
     if (assign->left->kind == ONYX_AST_NODE_KIND_SYMBOL) {
@@ -233,6 +234,15 @@ static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr) {
             }
             break;
 
+        case ONYX_AST_NODE_KIND_GLOBAL:
+            if (!expr->type->is_known) {
+                onyx_message_add(state->msgs,
+                        ONYX_MESSAGE_TYPE_LITERAL,
+                        expr->token->pos,
+                        "global with unknown type");
+            }
+            break;
+
         case ONYX_AST_NODE_KIND_ARGUMENT:
             typecheck_expression(state, expr->left);
             expr->type = expr->left->type;
@@ -250,6 +260,34 @@ static void typecheck_expression(OnyxSemPassState* state, OnyxAstNode* expr) {
     }
 }
 
+static void typecheck_global(OnyxSemPassState* state, OnyxAstNodeGlobal* global) {
+    if (global->initial_value) {
+        typecheck_expression(state, global->initial_value);
+
+        if (global->type->is_known) {
+            if (global->type != global->initial_value->type) {
+                onyx_message_add(state->msgs,
+                        ONYX_MESSAGE_TYPE_GLOBAL_TYPE_MISMATCH,
+                        global->token->pos,
+                        global->token->token, global->token->length,
+                        global->type->name, global->initial_value->type);
+                return;
+            }
+        } else {
+            if (global->initial_value->type)
+                global->type = global->initial_value->type;
+        }
+
+    } else {
+        if (!global->type || !global->type->is_known) {
+            onyx_message_add(state->msgs,
+                    ONYX_MESSAGE_TYPE_LITERAL,
+                    global->token->pos,
+                    "global variable with unknown type");
+        }
+    }
+}
+
 static void typecheck_statement(OnyxSemPassState* state, OnyxAstNode* stmt) {
     switch (stmt->kind) {
         case ONYX_AST_NODE_KIND_ASSIGNMENT: typecheck_assignment(state, stmt); break;
@@ -310,8 +348,30 @@ static void typecheck_function_defintion(OnyxSemPassState* state, OnyxAstNodeFun
 }
 
 void onyx_type_check(OnyxSemPassState* state, OnyxAstNodeFile* root_node) {
+    // TODO: This code is very ugly, but the types of globals need to
+    // be resolved before any function can use them
+
     OnyxAstNode* walker;
     OnyxAstNodeFile* top_walker = root_node;
+    while (top_walker) {
+
+        walker = top_walker->contents;
+        while (walker) {
+            switch (walker->kind) {
+                case ONYX_AST_NODE_KIND_GLOBAL:
+                    typecheck_global(state, &walker->as_global);
+                    break;
+
+                default: break;
+            }
+
+            walker = walker->next;
+        }
+
+        top_walker = top_walker->next;
+    }
+
+    top_walker = root_node;
     while (top_walker) {
 
         walker = top_walker->contents;
@@ -320,6 +380,7 @@ void onyx_type_check(OnyxSemPassState* state, OnyxAstNodeFile* root_node) {
                 case ONYX_AST_NODE_KIND_FUNCDEF:
                     typecheck_function_defintion(state, &walker->as_funcdef);
                     break;
+
                 default: break;
             }
 
index 01c369f0d47d8b19d747d4833481c0a5cb9647d8..55af1186b25874cbf8cc8ad6273c3e9f63a61c97 100644 (file)
@@ -1,5 +1,6 @@
 #define BH_DEBUG
 #include "onyxwasm.h"
+#include "onyxutils.h"
 
 // NOTE: Allows easier testing of types since most of the characters
 // corresponding to these values are not printable
@@ -208,40 +209,50 @@ static WasmType onyx_type_to_wasm_type(OnyxTypeInfo* type) {
     return WASM_TYPE_VOID;
 }
 
-static void compile_function_body(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeFuncDef* fd);
-static void compile_block(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBlock* block);
-static void compile_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* stmt);
-static void compile_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval);
-static void compile_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign);
-static void compile_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node);
-static void compile_while(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeWhile* while_node);
-static void compile_binop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBinOp* binop);
-static void compile_unaryop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* unop);
-static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr);
-static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* cast);
-static void compile_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret);
-
-static void compile_function_body(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeFuncDef* fd) {
+static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeFuncDef* fd);
+static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeBlock* block);
+static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* stmt);
+static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* lval);
+static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* assign);
+static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeIf* if_node);
+static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeWhile* while_node);
+static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeBinOp* binop);
+static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeUnaryOp* unop);
+static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* expr);
+static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeUnaryOp* cast);
+static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* ret);
+
+static void compile_function_body(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeFuncDef* fd) {
     if (fd->body == NULL) return;
 
+    bh_arr(WasmInstruction) code = *pcode;
+
     forll (OnyxAstNode, stmt, fd->body->body, next) {
-        compile_statement(mod, func, stmt);
+        compile_statement(mod, &code, stmt);
     }
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+
+    *pcode = code;
 }
 
-static void compile_block(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBlock* block) {
-    bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
+static void compile_block(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeBlock* block) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    bh_arr_push(code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
 
     forll (OnyxAstNode, stmt, block->body, next) {
-        compile_statement(mod, func, stmt);
+        compile_statement(mod, &code, stmt);
     }
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+
+    *pcode = code;
 }
 
-static void compile_structured_jump(OnyxWasmModule* mod, WasmFunc* func, b32 jump_backward) {
+static void compile_structured_jump(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, b32 jump_backward) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     i32 labelidx = 0;
     u8 wanted = jump_backward ? 2 : 1;
     b32 success = 0;
@@ -257,41 +268,59 @@ static void compile_structured_jump(OnyxWasmModule* mod, WasmFunc* func, b32 jum
     }
 
     if (success) {
-        bh_arr_push(func->code, ((WasmInstruction){ WI_JUMP, labelidx }));
+        bh_arr_push(code, ((WasmInstruction){ WI_JUMP, labelidx }));
     } else {
         assert(("Invalid structured jump", 0));
     }
+
+    *pcode = code;
 }
 
-static void compile_statement(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* stmt) {
+static void compile_statement(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* stmt) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     switch (stmt->kind) {
         case ONYX_AST_NODE_KIND_SCOPE: break;
-        case ONYX_AST_NODE_KIND_RETURN: compile_return(mod, func, stmt); break;
-        case ONYX_AST_NODE_KIND_ASSIGNMENT: compile_assignment(mod, func, stmt); break;
-        case ONYX_AST_NODE_KIND_IF: compile_if(mod, func, (OnyxAstNodeIf *) stmt); break;
-        case ONYX_AST_NODE_KIND_WHILE: compile_while(mod, func, (OnyxAstNodeWhile *) stmt); break;
-        case ONYX_AST_NODE_KIND_BREAK: compile_structured_jump(mod, func, 0); break;
-        case ONYX_AST_NODE_KIND_CONTINUE: compile_structured_jump(mod, func, 1); break;
-        case ONYX_AST_NODE_KIND_CALL: compile_expression(mod, func, stmt); break;
-        case ONYX_AST_NODE_KIND_BLOCK: compile_block(mod, func, (OnyxAstNodeBlock *) stmt); break;
+        case ONYX_AST_NODE_KIND_RETURN: compile_return(mod, &code, stmt); break;
+        case ONYX_AST_NODE_KIND_ASSIGNMENT: compile_assignment(mod, &code, stmt); break;
+        case ONYX_AST_NODE_KIND_IF: compile_if(mod, &code, (OnyxAstNodeIf *) stmt); break;
+        case ONYX_AST_NODE_KIND_WHILE: compile_while(mod, &code, (OnyxAstNodeWhile *) stmt); break;
+        case ONYX_AST_NODE_KIND_BREAK: compile_structured_jump(mod, &code, 0); break;
+        case ONYX_AST_NODE_KIND_CONTINUE: compile_structured_jump(mod, &code, 1); break;
+        case ONYX_AST_NODE_KIND_CALL: compile_expression(mod, &code, stmt); break;
+        case ONYX_AST_NODE_KIND_BLOCK: compile_block(mod, &code, (OnyxAstNodeBlock *) stmt); break;
 
         default: break;
     }
+
+    *pcode = code;
 }
 
-static void compile_assign_lval(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* lval) {
+static void compile_assign_lval(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* lval) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     if (lval->kind == ONYX_AST_NODE_KIND_LOCAL || lval->kind == ONYX_AST_NODE_KIND_PARAM) {
         i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) lval);
 
-        bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_SET, localidx }));
+        bh_arr_push(code, ((WasmInstruction){ WI_LOCAL_SET, localidx }));
+
+    } else if (lval->kind == ONYX_AST_NODE_KIND_GLOBAL) {
+        i32 globalidx = (i32) bh_imap_get(&mod->global_map, (u64) lval);
+
+        bh_arr_push(code, ((WasmInstruction){ WI_GLOBAL_SET, globalidx }));
+
     } else {
         assert(("Invalid lval", 0));
     }
+
+    *pcode = code;
 }
 
-static void compile_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_node) {
-    compile_expression(mod, func, if_node->cond);
-    bh_arr_push(func->code, ((WasmInstruction){ WI_IF_START, 0x40 }));
+static void compile_if(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeIf* if_node) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    compile_expression(mod, &code, if_node->cond);
+    bh_arr_push(code, ((WasmInstruction){ WI_IF_START, 0x40 }));
 
     bh_arr_push(mod->structured_jump_target, 0);
 
@@ -300,61 +329,71 @@ static void compile_if(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeIf* if_no
 
         if (if_node->true_block->kind == ONYX_AST_NODE_KIND_IF) {
             forll (OnyxAstNode, stmt, if_node->true_block, next) {
-                compile_statement(mod, func, stmt);
+                compile_statement(mod, &code, stmt);
             }
         } else if (if_node->true_block->kind == ONYX_AST_NODE_KIND_BLOCK) {
             forll (OnyxAstNode, stmt, if_node->true_block->as_block.body, next) {
-                compile_statement(mod, func, stmt);
+                compile_statement(mod, &code, stmt);
             }
         }
     }
 
     if (if_node->false_block) {
-        bh_arr_push(func->code, ((WasmInstruction){ WI_ELSE, 0x00 }));
+        bh_arr_push(code, ((WasmInstruction){ WI_ELSE, 0x00 }));
 
         if (if_node->false_block->kind == ONYX_AST_NODE_KIND_IF) {
             forll (OnyxAstNode, stmt, if_node->false_block, next) {
-                compile_statement(mod, func, stmt);
+                compile_statement(mod, &code, stmt);
             }
         } else if (if_node->false_block->kind == ONYX_AST_NODE_KIND_BLOCK) {
             forll (OnyxAstNode, stmt, if_node->false_block->as_block.body, next) {
-                compile_statement(mod, func, stmt);
+                compile_statement(mod, &code, stmt);
             }
         }
     }
 
     bh_arr_pop(mod->structured_jump_target);
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_IF_END, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_IF_END, 0x00 }));
+
+    *pcode = code;
 }
 
-static void compile_while(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeWhile* while_node) {
-    bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
-    bh_arr_push(func->code, ((WasmInstruction){ WI_LOOP_START, 0x40 }));
+static void compile_while(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeWhile* while_node) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    bh_arr_push(code, ((WasmInstruction){ WI_BLOCK_START, 0x40 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_LOOP_START, 0x40 }));
 
-    compile_expression(mod, func, while_node->cond);
-    bh_arr_push(func->code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
-    bh_arr_push(func->code, ((WasmInstruction){ WI_COND_JUMP, 0x01 }));
+    compile_expression(mod, &code, while_node->cond);
+    bh_arr_push(code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_COND_JUMP, 0x01 }));
 
     bh_arr_push(mod->structured_jump_target, 1);
     bh_arr_push(mod->structured_jump_target, 2);
 
     forll (OnyxAstNode, stmt, while_node->body->body, next) {
-        compile_statement(mod, func, stmt);
+        compile_statement(mod, &code, stmt);
     }
 
     bh_arr_pop(mod->structured_jump_target);
     bh_arr_pop(mod->structured_jump_target);
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_JUMP, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_JUMP, 0x00 }));
+
+    bh_arr_push(code, ((WasmInstruction){ WI_LOOP_END, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_LOOP_END, 0x00 }));
-    bh_arr_push(func->code, ((WasmInstruction){ WI_BLOCK_END, 0x00 }));
+    *pcode = code;
 }
 
-static void compile_assignment(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* assign) {
-    compile_expression(mod, func, assign->right);
-    compile_assign_lval(mod, func, assign->left);
+static void compile_assignment(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* assign) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    compile_expression(mod, &code, assign->right);
+    compile_assign_lval(mod, &code, assign->left);
+
+    *pcode = code;
 }
 
 // NOTE: These need to be in the same order as
@@ -375,7 +414,9 @@ static const WasmInstructionType binop_map[][4] = {
     /* GTE */ { WI_I32_GE_S,  WI_I64_GE_S,  WI_F32_GE,  WI_F64_GE },
 };
 
-static void compile_binop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBinOp* binop) {
+static void compile_binop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeBinOp* binop) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     b32 is_sign_significant = 0;
 
     switch (binop->operation) {
@@ -412,58 +453,66 @@ static void compile_binop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeBinOp*
         }
     }
 
-    compile_expression(mod, func, binop->left);
-    compile_expression(mod, func, binop->right);
+    compile_expression(mod, &code, binop->left);
+    compile_expression(mod, &code, binop->right);
 
-    bh_arr_push(func->code, ((WasmInstruction){ binop_instr, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ binop_instr, 0x00 }));
+
+    *pcode = code;
 }
 
-static void compile_unaryop(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* unop) {
+static void compile_unaryop(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeUnaryOp* unop) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     switch (unop->operation) {
         case ONYX_UNARY_OP_NEGATE:
             {
                 OnyxTypeInfoKind type_kind = unop->type->kind;
 
                 if (type_kind == ONYX_TYPE_INFO_KIND_INT32) {
-                    bh_arr_push(func->code, ((WasmInstruction){ WI_I32_CONST, 0x00 }));
-                    compile_expression(mod, func, unop->left);
-                    bh_arr_push(func->code, ((WasmInstruction){ WI_I32_SUB, 0x00 }));
+                    bh_arr_push(code, ((WasmInstruction){ WI_I32_CONST, 0x00 }));
+                    compile_expression(mod, &code, unop->left);
+                    bh_arr_push(code, ((WasmInstruction){ WI_I32_SUB, 0x00 }));
 
                 } else if (type_kind == ONYX_TYPE_INFO_KIND_INT64) {
-                    bh_arr_push(func->code, ((WasmInstruction){ WI_I64_CONST, 0x00 }));
-                    compile_expression(mod, func, unop->left);
-                    bh_arr_push(func->code, ((WasmInstruction){ WI_I64_SUB, 0x00 }));
+                    bh_arr_push(code, ((WasmInstruction){ WI_I64_CONST, 0x00 }));
+                    compile_expression(mod, &code, unop->left);
+                    bh_arr_push(code, ((WasmInstruction){ WI_I64_SUB, 0x00 }));
 
                 } else {
-                    compile_expression(mod, func, unop->left);
+                    compile_expression(mod, &code, unop->left);
 
                     if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT32)
-                        bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
+                        bh_arr_push(code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
 
                     if (type_kind == ONYX_TYPE_INFO_KIND_FLOAT64)
-                        bh_arr_push(func->code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
+                        bh_arr_push(code, ((WasmInstruction){ WI_F32_NEG, 0x00 }));
                 }
 
                 break;
             }
 
         case ONYX_UNARY_OP_NOT:
-            compile_expression(mod, func, unop->left);
-            bh_arr_push(func->code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
+            compile_expression(mod, &code, unop->left);
+            bh_arr_push(code, ((WasmInstruction){ WI_I32_EQZ, 0x00 }));
             break;
 
-        case ONYX_UNARY_OP_CAST: compile_cast(mod, func, unop); break;
+        case ONYX_UNARY_OP_CAST: compile_cast(mod, &code, unop); break;
     }
+
+    *pcode = code;
 }
 
-static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* expr) {
+static void compile_expression(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* expr) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     switch (expr->kind) {
         case ONYX_AST_NODE_KIND_BIN_OP:
-            compile_binop(mod, func, &expr->as_binop);
+            compile_binop(mod, &code, &expr->as_binop);
             break;
 
         case ONYX_AST_NODE_KIND_UNARY_OP:
-            compile_unaryop(mod, func, &expr->as_unaryop);
+            compile_unaryop(mod, &code, &expr->as_unaryop);
             break;
 
         case ONYX_AST_NODE_KIND_LOCAL:
@@ -471,7 +520,15 @@ static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode*
             {
                 i32 localidx = (i32) bh_imap_get(&mod->local_map, (u64) expr);
 
-                bh_arr_push(func->code, ((WasmInstruction){ WI_LOCAL_GET, localidx }));
+                bh_arr_push(code, ((WasmInstruction){ WI_LOCAL_GET, localidx }));
+                break;
+            }
+
+        case ONYX_AST_NODE_KIND_GLOBAL:
+            {
+                i32 globalidx = (i32) bh_imap_get(&mod->global_map, (u64) expr);
+
+                bh_arr_push(code, ((WasmInstruction){ WI_GLOBAL_GET, globalidx }));
                 break;
             }
 
@@ -495,21 +552,21 @@ static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode*
                     instr.data.d = lit->value.d;
                 }
 
-                bh_arr_push(func->code, instr);
+                bh_arr_push(code, instr);
                 break;
             }
 
-        case ONYX_AST_NODE_KIND_BLOCK: compile_block(mod, func, (OnyxAstNodeBlock *) expr); break;
+        case ONYX_AST_NODE_KIND_BLOCK: compile_block(mod, &code, (OnyxAstNodeBlock *) expr); break;
 
         case ONYX_AST_NODE_KIND_CALL:
             {
                 OnyxAstNodeCall* call = &expr->as_call;
                 forll (OnyxAstNode, arg, call->arguments, next) {
-                    compile_expression(mod, func, arg->left);
+                    compile_expression(mod, &code, arg->left);
                 }
 
                 i32 func_idx = (i32) bh_imap_get(&mod->func_map, (u64) call->callee);
-                bh_arr_push(func->code, ((WasmInstruction){ WI_CALL, func_idx }));
+                bh_arr_push(code, ((WasmInstruction){ WI_CALL, func_idx }));
 
                 break;
             }
@@ -519,6 +576,8 @@ static void compile_expression(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode*
             bh_printf("Unhandled case: %d\n", expr->kind);
             assert(0);
     }
+
+    *pcode = code;
 }
 
 static const WasmInstructionType cast_map[][6] = {
@@ -531,8 +590,10 @@ static const WasmInstructionType cast_map[][6] = {
     /* F64 */ { WI_I32_FROM_F64_S, WI_I32_FROM_F64_U, WI_I64_FROM_F64_S, WI_I64_FROM_F64_U, WI_F32_FROM_F64,   WI_NOP,           },
 };
 
-static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp* cast) {
-    compile_expression(mod, func, cast->left);
+static void compile_cast(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNodeUnaryOp* cast) {
+    bh_arr(WasmInstruction) code = *pcode;
+
+    compile_expression(mod, &code, cast->left);
 
     OnyxTypeInfo* from = cast->left->type;
     OnyxTypeInfo* to = cast->type;
@@ -560,16 +621,22 @@ static void compile_cast(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNodeUnaryOp
 
     WasmInstructionType cast_op = cast_map[fromidx][toidx];
     if (cast_op != WI_NOP) {
-        bh_arr_push(func->code, ((WasmInstruction){ cast_op, 0x00 }));
+        bh_arr_push(code, ((WasmInstruction){ cast_op, 0x00 }));
     }
+
+    *pcode = code;
 }
 
-static void compile_return(OnyxWasmModule* mod, WasmFunc* func, OnyxAstNode* ret) {
+static void compile_return(OnyxWasmModule* mod, bh_arr(WasmInstruction)* pcode, OnyxAstNode* ret) {
+    bh_arr(WasmInstruction) code = *pcode;
+
     if (ret->left) {
-        compile_expression(mod, func, ret->left);
+        compile_expression(mod, &code, ret->left);
     }
 
-    bh_arr_push(func->code, ((WasmInstruction){ WI_RETURN, 0x00 }));
+    bh_arr_push(code, ((WasmInstruction){ WI_RETURN, 0x00 }));
+
+    *pcode = code;
 }
 
 static i32 generate_type_idx(OnyxWasmModule* mod, OnyxAstNodeFuncDef* fd) {
@@ -628,6 +695,8 @@ static void compile_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef*
         .code = NULL,
     };
 
+    bh_arr_new(mod->allocator, wasm_func.code, 4);
+
     if (fd->flags & ONYX_AST_FLAG_EXPORTED) {
         onyx_token_null_toggle(*fd->token);
 
@@ -669,7 +738,8 @@ static void compile_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef*
         }
 
         // Generate code
-        compile_function_body(mod, &wasm_func, fd);
+        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 }));
@@ -681,6 +751,25 @@ static void compile_function_definition(OnyxWasmModule* mod, OnyxAstNodeFuncDef*
     bh_imap_clear(&mod->local_map);
 }
 
+static void compile_global_declaration(OnyxWasmModule* module, OnyxAstNodeGlobal* global) {
+    WasmGlobal glob = {
+        .type = onyx_type_to_wasm_type(global->type),
+        .mutable = (global->flags & ONYX_AST_FLAG_CONST) == 0,
+        .initial_value = NULL,
+    };
+
+    if (!global->initial_value) {
+        onyx_message_add(module->msgs,
+                ONYX_MESSAGE_TYPE_LITERAL,
+                global->token->pos,
+                "global without initial value");
+        return;
+    }
+
+    compile_expression(module, &glob.initial_value, global->initial_value);
+    bh_arr_push(module->globals, glob);
+}
+
 static void compile_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign) {
     if (foreign->import->kind == ONYX_AST_NODE_KIND_FUNCDEF) {
         i32 type_idx = generate_type_idx(module, &foreign->import->as_funcdef);
@@ -694,6 +783,18 @@ static void compile_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign)
 
         bh_arr_push(module->imports, import);
 
+    } else if (foreign->import->kind == ONYX_AST_NODE_KIND_GLOBAL) {
+        WasmType global_type = onyx_type_to_wasm_type(foreign->import->type);
+
+        WasmImport import = {
+            .kind = WASM_FOREIGN_GLOBAL,
+            .idx = global_type,
+            .mod = foreign->mod_token,
+            .name = foreign->name_token,
+        };
+
+        bh_arr_push(module->imports, import);
+
     } else {
         DEBUG_HERE;
         // NOTE: Invalid foreign
@@ -701,9 +802,10 @@ static void compile_foreign(OnyxWasmModule* module, OnyxAstNodeForeign* foreign)
     }
 }
 
-OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
+OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc, OnyxMessages* msgs) {
     OnyxWasmModule module = {
         .allocator = alloc,
+        .msgs = msgs,
 
         .type_map = NULL,
         .next_type_idx = 0,
@@ -717,6 +819,10 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
 
         .imports = NULL,
         .next_import_func_idx = 0,
+        .next_import_global_idx = 0,
+
+        .globals = NULL,
+        .next_global_idx = 0,
 
         .structured_jump_target = NULL,
     };
@@ -724,16 +830,18 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_arr_new(alloc, module.functypes, 4);
     bh_arr_new(alloc, module.funcs, 4);
     bh_arr_new(alloc, module.imports, 4);
+    bh_arr_new(alloc, module.globals, 4);
 
     // NOTE: 16 is probably needlessly large
-    bh_arr_new(bh_heap_allocator(), module.structured_jump_target, 16);
+    bh_arr_new(global_heap_allocator, module.structured_jump_target, 16);
     bh_arr_set_length(module.structured_jump_target, 0);
 
-    bh_table_init(bh_heap_allocator(), module.type_map, 61);
-    bh_table_init(bh_heap_allocator(), module.exports, 61);
+    bh_table_init(global_heap_allocator, module.type_map, 61);
+    bh_table_init(global_heap_allocator, module.exports, 61);
 
-    bh_imap_init(&module.local_map, bh_heap_allocator());
-    bh_imap_init(&module.func_map, bh_heap_allocator());
+    bh_imap_init(&module.local_map,  global_heap_allocator);
+    bh_imap_init(&module.func_map,   global_heap_allocator);
+    bh_imap_init(&module.global_map, global_heap_allocator);
 
     return module;
 }
@@ -745,9 +853,12 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program)
 
         walker = top_walker->contents;
         while (walker) {
-            if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN
-                && walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF) {
-                module->next_func_idx++;
+            if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN) {
+                if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_FUNCDEF)
+                    module->next_func_idx++;
+
+                if (walker->as_foreign.import->kind == ONYX_AST_NODE_KIND_GLOBAL)
+                    module->next_global_idx++;
             }
 
             walker = walker->next;
@@ -766,6 +877,11 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program)
                 bh_imap_put(&module->func_map, (u64) walker, func_idx);
             }
 
+            if (walker->kind == ONYX_AST_NODE_KIND_GLOBAL) {
+                i32 global_idx = module->next_global_idx++;
+                bh_imap_put(&module->global_map, (u64) walker, global_idx);
+            }
+
             if (walker->kind == ONYX_AST_NODE_KIND_FOREIGN) {
                 OnyxAstNodeForeign* foreign = &walker->as_foreign;
 
@@ -773,6 +889,11 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program)
                     i32 func_idx = module->next_import_func_idx++;
                     bh_imap_put(&module->func_map, (u64) foreign->import, func_idx);
                 }
+
+                if (foreign->import->kind == ONYX_AST_NODE_KIND_GLOBAL) {
+                    i32 global_idx = module->next_import_global_idx++;
+                    bh_imap_put(&module->global_map, (u64) foreign->import, global_idx);
+                }
             }
 
             walker = walker->next;
@@ -790,9 +911,15 @@ void onyx_wasm_module_compile(OnyxWasmModule* module, OnyxAstNodeFile* program)
                 case ONYX_AST_NODE_KIND_FUNCDEF:
                     compile_function_definition(module, &walker->as_funcdef);
                     break;
+
+                case ONYX_AST_NODE_KIND_GLOBAL:
+                    compile_global_declaration(module, &walker->as_global);
+                    break;
+
                 case ONYX_AST_NODE_KIND_FOREIGN:
                     compile_foreign(module, &walker->as_foreign);
                     break;
+
                 default: break;
             }
 
@@ -836,6 +963,8 @@ typedef i32 vector_func(void*, bh_buffer*);
 static const u8 WASM_MAGIC_STRING[] = { 0x00, 0x61, 0x73, 0x6D };
 static const u8 WASM_VERSION[] = { 0x01, 0x00, 0x00, 0x00 };
 
+static void output_instruction(WasmInstruction* instr, bh_buffer* buff);
+
 static i32 output_vector(void** arr, i32 stride, i32 arrlen, vector_func elem, bh_buffer* vec_buff) {
     i32 len;
     u8* leb = uint_to_uleb128((u64) arrlen, &len);
@@ -928,6 +1057,37 @@ static i32 output_funcsection(OnyxWasmModule* module, bh_buffer* buff) {
     return buff->length - prev_len;
 }
 
+static i32 output_globalsection(OnyxWasmModule* module, bh_buffer* buff) {
+    i32 prev_len = buff->length;
+    bh_buffer_write_byte(buff, WASM_SECTION_ID_GLOBAL);
+
+    bh_buffer vec_buff;
+    bh_buffer_init(&vec_buff, buff->allocator, 128);
+
+    i32 leb_len;
+    u8* leb = uint_to_uleb128((u64) (bh_arr_length(module->globals)), &leb_len);
+    bh_buffer_append(&vec_buff, leb, leb_len);
+
+    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_arr_each(WasmInstruction, instr, global->initial_value)
+            output_instruction(instr, &vec_buff);
+
+        // NOTE: Initial value expression terminator
+        bh_buffer_write_byte(&vec_buff, (u8) WI_BLOCK_END);
+    }
+
+    leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);
+    bh_buffer_append(buff, leb, leb_len);
+
+    bh_buffer_concat(buff, vec_buff);
+    bh_buffer_free(&vec_buff);
+
+    return buff->length - prev_len;
+}
+
 static i32 output_importsection(OnyxWasmModule* module, bh_buffer* buff) {
     i32 prev_len = buff->length;
     bh_buffer_write_byte(buff, WASM_SECTION_ID_IMPORT);
@@ -946,6 +1106,11 @@ static i32 output_importsection(OnyxWasmModule* module, bh_buffer* buff) {
 
         leb = uint_to_uleb128((u64) import->idx, &leb_len);
         bh_buffer_append(&vec_buff, leb, leb_len);
+
+        if (import->kind == WASM_FOREIGN_GLOBAL) {
+            // NOTE: All foreign globals are mutable
+            bh_buffer_write_byte(&vec_buff, 0x01);
+        }
     }
 
     leb = uint_to_uleb128((u64) (vec_buff.length), &leb_len);
@@ -1062,6 +1227,8 @@ static void output_instruction(WasmInstruction* instr, bh_buffer* buff) {
     switch (instr->type) {
         case WI_LOCAL_GET:
         case WI_LOCAL_SET:
+        case WI_GLOBAL_GET:
+        case WI_GLOBAL_SET:
         case WI_CALL:
         case WI_BLOCK_START:
         case WI_LOOP_START:
@@ -1141,13 +1308,14 @@ static i32 output_codesection(OnyxWasmModule* module, bh_buffer* buff) {
 
 void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file) {
     bh_buffer master_buffer;
-    bh_buffer_init(&master_buffer, bh_heap_allocator(), 128);
+    bh_buffer_init(&master_buffer, global_heap_allocator, 128);
     bh_buffer_append(&master_buffer, WASM_MAGIC_STRING, 4);
     bh_buffer_append(&master_buffer, WASM_VERSION, 4);
 
     output_typesection(module, &master_buffer);
     output_importsection(module, &master_buffer);
     output_funcsection(module, &master_buffer);
+    output_globalsection(module, &master_buffer);
     output_exportsection(module, &master_buffer);
     output_startsection(module, &master_buffer);
     output_codesection(module, &master_buffer);