we can actually run (very simple) programs! AMAZING
authorcassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 04:28:15 +0000 (21:28 -0700)
committercassowarii <cassowary@cassowary.me>
Tue, 30 Jun 2026 04:28:15 +0000 (21:28 -0700)
12 files changed:
Makefile
src/compile/emit.c
src/compile/ir.c
src/compile/ir.h
src/data/operations.c
src/data/operations.h
src/data/value.c
src/data/value.h
src/main.c
src/vm/bytecode.h
src/vm/exec.c
src/vm/exec.h

index a40b929..a58e1c1 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 CC=gcc
 CFLAGS=-Wall -g -DDEBUG -fsanitize=undefined
-#CFLAGS=-Wall -O3 -flto -DGLEW_STATIC -DDEBUG -fsanitize=undefined
+#CFLAGS=-Wall -O3 -flto
 LIBS=
 
 SRC := src
@@ -14,10 +14,13 @@ build/a.out: $(OBJECTS)
        @mkdir -p $(dir $@)
        $(CC) $(CFLAGS) -I$(SRC) $(OBJECTS) $(LIBS) -o $@
 
-.PHONY: parsedebug
+.PHONY: parsedebug optimized
 parsedebug: CFLAGS += -DPARSEDEBUG
 parsedebug: build/a.out
 
+optimized: CFLAGS=-Wall -O3 -flto
+optimized: build/a.out
+
 $(OBJ)/%.o: $(SRC)/%.c
        @mkdir -p $(dir $@)
        $(CC) $(CFLAGS) $(LIBS) -I$(SRC) -c $< -o $@
index 66b18cc..209c8c0 100644 (file)
@@ -30,32 +30,10 @@ void sbEmit_compile_program(sbVmProgram *vp, sbIrProgram *ir) {
   sbVmCompiler_deinitialize(&cm);
 }
 
-void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) {
-  //sbVmCompiler_add_constant(&cm, &HVINT(5));
-  //sbVmCompiler_add_constant(&cm, &HVINT(9));
-
-  printf("\n--block--\n");
-
-  int nstmts = chunk->stmts.size / sizeof(sbIrStmt*);
-  for (int i = 0; i < nstmts; i++) {
-    sbIrStmt *stmt = ((sbIrStmt**)chunk->stmts.data)[i];
-
-    compile_stmt(cm, stmt);
-  }
-}
-
-/* when compiling one line at a time, we don't know the position
- * of labels we haven't seen yet. we leave a 4-byte slot for a blank
- * address, and say "please put the address of this label here later!" */
-void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) {
-  struct labelpos lp = {
-  };
-
-  sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos));
-}
+/* --- */
 
 void emit_arg(sbVmCompiler *cm, usize number) {
-  printf("  arg %zu\n", number);
+  printf("    arg %zu\n", number);
   u8 buf[9];
   if (number < 256) {
     buf[0] = number;
@@ -86,8 +64,40 @@ void emit_arg(sbVmCompiler *cm, usize number) {
   }
 }
 
+
+void compile_chunk(sbVmCompiler *cm, sbIrChunk *chunk) {
+  //sbVmCompiler_add_constant(&cm, &HVINT(5));
+  //sbVmCompiler_add_constant(&cm, &HVINT(9));
+
+  printf("\n--block %d--\n", chunk->id);
+
+  int nstmts = chunk->stmts.size / sizeof(sbIrStmt*);
+  if (chunk->id > 0) {
+    /* don't check args for initial block
+     * (note: when we have modules or whatever, this might
+     * be an incorrect way to do this) */
+    EMIT(BC_NUMARG);
+    EARG(chunk->num_args);
+  }
+  for (int i = 0; i < nstmts; i++) {
+    sbIrStmt *stmt = ((sbIrStmt**)chunk->stmts.data)[i];
+
+    compile_stmt(cm, stmt);
+  }
+}
+
+/* when compiling one line at a time, we don't know the position
+ * of labels we haven't seen yet. we leave a 4-byte slot for a blank
+ * address, and say "please put the address of this label here later!" */
+void record_labelpos(sbVmCompiler *cm, sbIrLabel *label, u32 offset) {
+  struct labelpos lp = {
+  };
+
+  sbBuffer_append(&cm->label_positions, &lp, sizeof(struct labelpos));
+}
+
 void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
-  printf("%zu ", sbVmCompiler_get_position(cm));
+  printf("%3zu ", sbVmCompiler_get_position(cm));
   switch (stmt->type) {
     case IR_S_EXPR:
       compile_expr(cm, stmt->expr);
@@ -115,6 +125,15 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
       stmt->label->block_position = sbVmCompiler_get_position(cm);
       printf("\n");
       break;
+    case IR_S_ASSIGN:
+      compile_expr(cm, stmt->assign.expr);
+      EMIT(BC_ST_VAR);
+      EARG(stmt->assign.var->slot_id);
+      break;
+    case IR_S_ARG:
+      EMIT(BC_ST_ARG);
+      EARG(stmt->arg.var->slot_id);
+      break;
     case IR_S_RETURN:
       if (stmt->expr) {
         compile_expr(cm, stmt->expr);
@@ -128,6 +147,8 @@ void compile_stmt(sbVmCompiler *cm, sbIrStmt *stmt) {
 
 void compile_op(sbVmCompiler *cm, sbAstOp op);
 void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
+  sbIrExpr *E1;
+  int count = 0;
   switch(expr->type) {
     case IR_E_OP:
       compile_expr(cm, expr->op.left);
@@ -136,6 +157,36 @@ void compile_expr(sbVmCompiler *cm, sbIrExpr *expr) {
       }
       compile_op(cm, expr->op.type);
       break;
+    case IR_E_CALL:
+      E1 = expr->call.param;
+      while (E1) {
+        count ++;
+        compile_expr(cm, E1->param.this);
+        E1 = E1->param.next;
+      }
+      EMIT(BC_LD_IMM);
+      EARG(count); /* calling convention: store argument count on stack */
+      compile_expr(cm, expr->call.func);
+      EMIT(BC_CALL);
+      break;
+    case IR_E_VAR:
+      EMIT(BC_LD_VAR);
+      EARG(expr->var->slot_id);
+      break;
+    case IR_E_FUNC:
+      EMIT(BC_LD_BLK);
+      EARG(expr->func->id);
+      break;
+    case IR_E_VALUE:
+      if (expr->value.type == IT_NIL) {
+        EMIT(BC_LD_NIL);
+      } else if (expr->value.type == IT_INTEGER) {
+        EMIT(BC_LD_IMM);
+        EARG(expr->value.integer);
+      } else {
+        printf("(some value)\n");
+      }
+      break;
     default:
       printf("(compile an expr)\n");
   }
@@ -145,6 +196,14 @@ void compile_op(sbVmCompiler *cm, sbAstOp op) {
   switch (op) {
     case AST_OP_ADD: EMIT(BC_OP_ADD); break;
     case AST_OP_SUB: EMIT(BC_OP_SUB); break;
+    case AST_OP_MUL: EMIT(BC_OP_MUL); break;
+    case AST_OP_FLDIV: EMIT(BC_OP_FLDIV); break;
+    case AST_OP_EQ: EMIT(BC_OP_EQ); break;
+    case AST_OP_NE: EMIT(BC_OP_EQ, BC_OP_NOT); break;
+    case AST_OP_LT: EMIT(BC_OP_LT); break;
+    case AST_OP_GT: EMIT(BC_OP_LE, BC_OP_NOT); break;
+    case AST_OP_LE: EMIT(BC_OP_LE); break;
+    case AST_OP_GE: EMIT(BC_OP_LT, BC_OP_NOT); break;
     default:
       printf("unknown operation!\n");
   }
index 4a3150c..8c931b9 100644 (file)
@@ -348,6 +348,7 @@ static sbIrChunk *compile_ast_function(hIrProgram ir, sbAst paramsAst, sbAst seq
     sbBuffer_append(&arg_vars, &v1, sizeof(sbIrVariable*));
     v1->initialized = TRUE;
     param_comma = param_comma->seq.right;
+    ck->num_args ++;
   }
 
   while (arg_vars.size > 0) {
index 719a34c..5b129e4 100644 (file)
@@ -117,6 +117,8 @@ struct sbIrProgram;
 typedef struct sbIrChunk {
   struct sbIrProgram *program;
   i32 id;
+  i16 num_args;
+  flag variadic;
   i32 label_count;
   i32 variable_count;
   i32 lowest_var_id;
index aca8317..ed117b9 100644 (file)
@@ -6,7 +6,7 @@ hV sbV_add(const hV *a, const hV *b) {
   if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
     return sbV_int(sbInteger_sum(a->integer, b->integer));
   } else {
-    PANIC("todo");
+    PANIC("todo (add type %llu and type %llu)", a->type, b->type);
   }
 }
 
@@ -57,3 +57,27 @@ hV sbV_eq(const hV *a, const hV *b) {
     return HVBOOL(FALSE);
   }
 }
+
+hV sbV_lt(const hV *a, const hV *b) {
+  if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
+    if (a->integer < b->integer) {
+      return HVBOOL(TRUE);
+    } else {
+      return HVBOOL(FALSE);
+    }
+  } else {
+    PANIC("todo");
+  }
+}
+
+hV sbV_le(const hV *a, const hV *b) {
+  if (a->type == IT_INTEGER && b->type == IT_INTEGER) {
+    if (a->integer <= b->integer) {
+      return HVBOOL(TRUE);
+    } else {
+      return HVBOOL(FALSE);
+    }
+  } else {
+    PANIC("todo");
+  }
+}
index ed97ea2..587411b 100644 (file)
@@ -13,3 +13,7 @@ hV sbV_incr(const hV *a);
 hV sbV_decr(const hV *a);
 
 hV sbV_eq(const hV *a, const hV *b);
+
+hV sbV_lt(const hV *a, const hV *b);
+
+hV sbV_le(const hV *a, const hV *b);
index 8fdb686..46ac7b9 100644 (file)
@@ -51,6 +51,13 @@ hV sbV_int(hInteger i) {
   };
 }
 
+hV sbV_function(u64 id) {
+  return (hV) {
+    .type = IT_FUNCTION,
+    .data = id,
+  };
+}
+
 flag sbV_c_eq(const hV *a, const hV *b) {
   if (a->type != b->type) return FALSE;
   if (a->type == ITX_TOMBSTONE || b->type == ITX_TOMBSTONE) return FALSE;
index 7526178..5cd07e1 100644 (file)
@@ -6,6 +6,7 @@
 #define HVINT(n) ((hV) { .type = IT_INTEGER, .integer = n })
 #define HVSTR(s) ((hV) { .type = IT_STRING, .string = OBJSL(s) })
 #define HVBOOL(b) ((hV) { .type = IT_BOOLEAN, .boolean = b })
+#define HVFUNC(i) ((hV) { .type = IT_FUNCTION, .data = i })
 
 typedef u64 hHash;
 typedef u64 hString;
@@ -37,6 +38,7 @@ typedef struct hV {
     hInteger integer;
     u64 boolean;
     double float_val;
+    u64 data;
   };
 } hV;
 
@@ -47,6 +49,7 @@ hV sbV_float(double fl);
 hV sbV_hash(hHash hash);
 hV sbV_int(hInteger i);
 hV sbV_boolean(flag b);
+hV sbV_function(u64 id);
 
 flag sbV_c_eq(const hV *a, const hV *b);
 flag sbV_c_falsy(const hV *a);
index 7490375..d653061 100644 (file)
@@ -9,7 +9,7 @@
 #include "vm/exec.h"
 
 int main(int argc, char **argv) {
-    if (argc == 2) {
+    if (argc >= 2) {
         sbString_sys_init();
         sbHash_sys_init();
         sbSymbol_sys_init();
@@ -17,13 +17,26 @@ int main(int argc, char **argv) {
         sbParser pr;
         sbParser_initialize(&pr);
 
-        sbAst parse_result = sbParser_parse_file(&pr, argv[1]);
+        const char *filename;
+        flag debugmode = FALSE;
+        if (argc == 3 && sbstrncmp(argv[1], "-D", 2) == 0) {
+          filename = argv[2];
+          debugmode = TRUE;
+        } else if (argc == 2) {
+          filename = argv[1];
+        } else {
+          printf("usage: %s [-D] <filename>\n", argv[0]);
+          printf("usage:    -D = bytecode debugger\n");
+          return 0;
+        }
+
+        sbAst parse_result = sbParser_parse_file(&pr, filename);
 
         if (parse_result == NULL) {
-          fprintf(stderr, "fatal error: Could not open script '%s'\n", argv[1]);
+          fprintf(stderr, "fatal error: Could not open script '%s'\n", filename);
           return -2;
         } else if (parse_result->type == AST_ERROR) {
-          fprintf(stderr, "fatal error: Could not run '%s' due to syntax errors.\n", argv[1]);
+          fprintf(stderr, "fatal error: Could not run '%s' due to syntax errors.\n", filename);
           return -1;
         }
 
@@ -39,7 +52,7 @@ int main(int argc, char **argv) {
         sbParser_deinitialize(&pr);
 
         if (ir.error_count > 0) {
-          fprintf(stderr, "Could not run '%s' due to errors.\n", argv[1]);
+          fprintf(stderr, "Could not run '%s' due to errors.\n", filename);
           return -3;
         } else {
           // print out program
@@ -53,70 +66,23 @@ int main(int argc, char **argv) {
 
         sbIrProgram_deinitialize(&ir);
 
+        sbVm vm = {0};
+        sbVm_initialize(&vm, 1048576, 1048576, debugmode);
+
+        sbVm_execute(&vm, &pm);
+
+        printf("Stack result: ");
+        for (u8 *p = vm.stack; p < vm.sp; p++) {
+          printf("%02X ", *p);
+        }
+        printf("\n");
+
         sbVmProgram_deinitialize(&pm);
+        sbVm_deinitialize(&vm);
         sbSymbol_sys_deinit();
         sbHash_sys_deinit();
         sbString_sys_deinit();
     } else {
         fprintf(stderr, "please provide a file as input\n");
     }
-
-    sbVm vm = {0};
-    sbVm_initialize(&vm, 1048576, 1048576);
-
-    sbVmProgram pm;
-    sbVmProgram_initialize(&pm, 65536);
-
-    sbVmCompiler pb = sbVmCompiler_create(4096, 4096);
-
-    u8 code1[] = {
-      BC_ALLOC_VARS, 0x02,           /* 0 1 */
-      BC_LD_IMM, 0x00,    /* var1 = 0   2 3 */
-      BC_ST_VAR, 0x01,    /* ...        4 5 */
-      BC_LD_CONST, 0x01,  /* var0 = 9   6 7 */
-      BC_ST_VAR, 0x00,    /* ...        8 9 */
-      BC_LD_CONST, 0x00,  /* (LABEL) var1 += 5 ; 10 11 */
-      BC_LD_VAR, 0x01,    /* ... */
-      BC_OP_ADD,          /* ... */
-      BC_ST_VAR, 0x01,    /* ... */
-      BC_LD_VAR, 0x00,    /* var0 = var0 - 1 */
-      BC_OP_DECR,         /* ... */
-      BC_ST_VAR, 0x00,    /* ... */
-      BC_LD_VAR, 0x00,    /* if var0 != 0 */
-      BC_LD_IMM, 0x00,    /* ... */
-      BC_OP_EQ,           /* ... */
-      BC_JF, 0x0A,        /* ...then goto LABEL */
-      BC_LD_VAR, 0x01,    /* return var1 */
-      BC_LD_IMM, 0x01,    /* ... */
-      BC_HALT,
-    };
-
-    sbVmCompiler_add_constant(&pb, &HVINT(5));
-    sbVmCompiler_add_constant(&pb, &HVINT(9));
-
-    sbVmCompiler_write_code(&pb, code1, sizeof(code1));
-    sbVmProgram_add_block(&pm, &pb);
-    sbVmCompiler_reset(&pb);
-
-    u8 code2[] = {
-      BC_LD_CONST, 0x00,
-      BC_OP_ADD,
-      BC_RET,
-    };
-
-    sbVmCompiler_add_constant(&pb, &HVINT(7));
-
-    sbVmCompiler_write_code(&pb, code2, sizeof(code2));
-    sbVmProgram_add_block(&pm, &pb);
-    sbVmCompiler_reset(&pb);
-
-    sbVmCompiler_deinitialize(&pb);
-
-    sbVm_execute(&vm, &pm);
-
-    printf("Stack result: ");
-    for (u8 *p = vm.stack; p < vm.sp; p++) {
-      printf("%02X ", *p);
-    }
-    printf("\n");
 }
index 299434d..ae42fe0 100644 (file)
@@ -10,17 +10,22 @@ typedef enum sbOpcode {
   BC_LD_CTX,            // look up key in context object and push result
   BC_LD_VAR,            // push value onto stack from variable
   BC_LD_UPVAL,          // push value onto stack from closure
+  BC_LD_BLK,            // push reference to function onto stack
+  BC_LD_NIL,            // push nil onto stack
   BC_ST_VAR,            // pop value from stack into variable
   BC_ST_UPVAL,          // pop value from stack into closure
-  BC_POP        = 0x08, // pop value from stack
-  BC_NPOP,              // pop value from stack
+  BC_ST_ARG,            // decrement TOS and store NOS in variable
+  BC_POP,               // pop value from stack
+  BC_NPOP,              // pop N values from stack given by top number
   BC_CALL,              // push return address and jump to new block
   BC_RET,               // return to calling block
+  BC_NUMARG,            // check number of function arguments = this
+  BC_MINARG,            // check number of function arguments > this
   BC_JMP,               // unconditional local jump inside current block
   BC_JT,                // jump if true
   BC_JF,                // jump if false
   BC_SEND,              // like call, but jump to object method
-  BC_OP_EQ      = 0x10, // ==
+  BC_OP_EQ,             // ==
   BC_OP_NOT,            // boolean not
   BC_OP_ADD,            // add
   BC_OP_SUB,            // subtract
@@ -28,11 +33,13 @@ typedef enum sbOpcode {
   BC_OP_DIV,            // true divide
   BC_OP_FLDIV,          // floor divide
   BC_OP_NEG,            // negative
-  BC_OP_MOD     = 0x18, // mod
+  BC_OP_MOD,            // mod
   BC_OP_POW,            // power
   BC_OP_INCR,           // increment
   BC_OP_DECR,           // decrement
   BC_OP_DEREF,          // dereference pointer
+  BC_OP_LT,             // less than
+  BC_OP_LE,             // less than or equal to
   BC_ALLOC_VARS,        // create space in rstack for local variables
   BC_LIST_GATHER,       // create list from count + list of values on stack
   BC_HASH_GATHER,       // create hash from count + list of pairs of keys/values on stack
index fef3fd1..ea50f2b 100644 (file)
@@ -5,7 +5,7 @@
 void call_block(hVm vm, usize block_id);
 void execute_instruction(hVm vm);
 
-void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize) {
+void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode) {
   *vm = (sbVm) {0};
   vm->stack = malloc(stacksize);
   vm->stacksize = stacksize;
@@ -15,6 +15,8 @@ void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize) {
   vm->sp = vm->stack;
   vm->fp = (sbVmStackFrame*)vm->rstack;
   vm->rp = vm->rstack;
+
+  vm->debugmode = debugmode;
 }
 
 void sbVm_deinitialize(hVm vm) {
@@ -33,6 +35,13 @@ sbVmStatus sbVm_execute(hVm vm, sbVmProgram *pm) {
 
   while (vm->running) {
     execute_instruction(vm);
+    if (vm->debugmode) {
+      printf("Stack: ");
+      for (u8 *p = vm->stack; p < vm->sp; p++) {
+        printf("%02X ", *p);
+      }
+      printf("\n");
+    }
   }
 
   return VM_STAT_SUCCESS;
@@ -62,9 +71,14 @@ void return_from_block(hVm vm) {
 
   sbVmStackFrame *frame = (sbVmStackFrame*)vm->fp;
 
-  vm->fp = frame->last_fp;
-  vm->rp = frame->last_rp;
-  vm->ip = frame->return_addr;
+  if (frame->return_addr == NULL) {
+    /* returning to address 0 means quit */
+    vm->running = FALSE;
+  } else {
+    vm->fp = frame->last_fp;
+    vm->rp = frame->last_rp;
+    vm->ip = frame->return_addr;
+  }
 }
 
 void debug_print_hv(const hV *value) {
@@ -177,6 +191,10 @@ void execute_instruction(hVm vm) {
     case BC_LD_UPVAL:
       /* Hey, was there upval in there? */
       PANIC("todo");
+    case BC_LD_BLK:
+      param = get_param(vm);
+      push_stack(vm, &HVFUNC(param));
+      return;
     case BC_ST_VAR:
       param = get_param(vm);
       v = peek_stack(vm, 0);
@@ -185,6 +203,22 @@ void execute_instruction(hVm vm) {
       return;
     case BC_ST_UPVAL:
       PANIC("todo");
+    case BC_ST_ARG:
+      param = get_param(vm);
+      v = pop_stack(vm); /* argument count */
+      if (v->type != IT_INTEGER) {
+        /* internal error! this should be generated correctly */
+        PANIC("calling convention violation: number of args should be an integer");
+      }
+      w = pop_stack(vm); /* argument value */
+      store_local(vm, param, w);
+      /* we track the number of arguments remaining, for variadic functions later */
+      v->integer --;
+      if (v->integer > 0) {
+        /* if last integer, don't put the 0 count back on the stack */
+        push_stack(vm, v);
+      }
+      return;
     case BC_POP:
       v = pop_stack(vm);
       return;
@@ -194,7 +228,25 @@ void execute_instruction(hVm vm) {
       return;
     case BC_CALL:
       v = pop_stack(vm);
-      call_block(vm, v->integer);
+      if (v->type != IT_FUNCTION) {
+        /* We need to figure out exception support or some such.
+         * User error should not panic. */
+        PANIC("attempt to call a non-function value");
+      }
+      call_block(vm, v->data);
+      return;
+    case BC_NUMARG:
+      param = get_param(vm);
+      v = pop_stack(vm);
+      if (v->type != IT_INTEGER) {
+        /* internal error! this should be generated correctly */
+        PANIC("calling convention violation: number of args should be an integer");
+      }
+      if (v->integer != param) {
+        /* This should be an exception. */
+        PANIC("wrong number of arguments passed to function.");
+      }
+      push_stack(vm, v);
       return;
     case BC_JMP:
       param = get_param(vm);
@@ -234,6 +286,20 @@ void execute_instruction(hVm vm) {
         push_stack(vm, &HVBOOL(FALSE));
       }
       return;
+    case BC_OP_LT:
+      v = peek_stack(vm, 1);
+      w = peek_stack(vm, 0);
+      res = sbV_lt(v, w);
+      npop_stack(vm, 2);
+      push_stack(vm, &res);
+      return;
+    case BC_OP_LE:
+      v = peek_stack(vm, 1);
+      w = peek_stack(vm, 0);
+      res = sbV_le(v, w);
+      npop_stack(vm, 2);
+      push_stack(vm, &res);
+      return;
     case BC_OP_ADD:
       v = peek_stack(vm, 1);
       w = peek_stack(vm, 0);
@@ -295,8 +361,8 @@ void execute_instruction(hVm vm) {
       PANIC("todo");
     case BC_LONG_NUM:
     case BC_VLONG_NUM:
-      PANIC("illegal opcode $%02X at position $%08zX\n", op, (usize)vm->ip);
+      PANIC("illegal opcode $%02X at position $%016zX", op, (usize)vm->ip);
     default:
-      PANIC("unrecognized opcode $%02X at position $%08zX\n", op, (usize)vm->ip);
+      PANIC("unrecognized opcode $%02X at position $%016zX", op, (usize)vm->ip);
   }
 }
index 6fa4406..295d756 100644 (file)
@@ -65,11 +65,12 @@ typedef struct sbVm {
 
   sbVmProgram *program;
   flag running;
+  flag debugmode;
 } sbVm;
 
 typedef sbVm *hVm;
 
-void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize);
+void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode);
 
 void sbVm_deinitialize(hVm vm);