mcode->mach

This commit is contained in:
2026-02-12 04:28:14 -06:00
parent 8a84be65e1
commit 3a8a17ab60
19 changed files with 635 additions and 4320 deletions

BIN
fold.mach

Binary file not shown.

BIN
fold_new.mach Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -46,7 +46,6 @@ src += [ # core
'miniz.c',
'runtime.c',
'mach.c',
'mcode.c',
'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.c'
]

View File

@@ -65,7 +65,7 @@ var parse = function(tokens, src, filename, tokenizer) {
var errors = []
var error_count = 0
var function_nr = 1
var fn_counter = 1
var ast_node = function(kind, token) {
return {
@@ -422,8 +422,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = meth_old_cd
_control_type = meth_old_ct
_expecting_body = meth_old_eb
fn.function_nr = function_nr
function_nr = function_nr + 1
fn.function_nr = fn_counter
fn_counter = fn_counter + 1
ast_node_end(fn)
pair.right = fn
} else if (is_ident && (tok.kind == "," || tok.kind == "}")) {
@@ -918,8 +918,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = old_cd
_control_type = old_ct
_expecting_body = old_eb
node.function_nr = function_nr
function_nr = function_nr + 1
node.function_nr = fn_counter
fn_counter = fn_counter + 1
ast_node_end(node)
return node
}
@@ -1008,8 +1008,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = old_cd
_control_type = old_ct
_expecting_body = old_eb
node.function_nr = function_nr
function_nr = function_nr + 1
node.function_nr = fn_counter
fn_counter = fn_counter + 1
ast_node_end(node)
return node
}

Binary file not shown.

BIN
qbe.mach

Binary file not shown.

Binary file not shown.

View File

@@ -6,6 +6,8 @@ var json = use("json")
var tokenize = use("tokenize")
var parse = use("parse")
var fold = use("fold")
var mcode = use("mcode")
var streamline = use("streamline")
var files = [
{src: "tokenize.cm", name: "tokenize", out: "tokenize.mach"},
@@ -25,21 +27,49 @@ var src = null
var tok_result = null
var ast = null
var folded = null
var ast_json = null
var compiled = null
var optimized = null
var mcode_json = null
var bytecode = null
var f = null
var errs = null
var ei = 0
var e = null
var had_errors = false
while (i < length(files)) {
entry = files[i]
src = text(fd.slurp(entry.src))
tok_result = tokenize(src, entry.src)
ast = parse(tok_result.tokens, src, entry.src, tokenize)
// Check for parse/semantic errors
errs = ast.errors
if (errs != null && length(errs) > 0) {
ei = 0
while (ei < length(errs)) {
e = errs[ei]
if (e.line != null) {
print(`${entry.src}:${text(e.line)}:${text(e.column)}: error: ${e.message}`)
} else {
print(`${entry.src}: error: ${e.message}`)
}
ei = ei + 1
}
had_errors = true
i = i + 1
continue
}
folded = fold(ast)
ast_json = json.encode(folded)
bytecode = mach_compile_ast(entry.name, ast_json)
compiled = mcode(folded)
optimized = streamline(compiled)
mcode_json = json.encode(optimized)
bytecode = mach_compile_mcode_bin(entry.name, mcode_json)
f = fd.open(entry.out, "w")
fd.write(f, bytecode)
fd.close(f)
print(`wrote ${entry.out}`)
i = i + 1
}
if (had_errors) {
print("regen aborted: fix errors above")
}

View File

@@ -12,7 +12,6 @@
#include "cJSON.h"
#define BOOTSTRAP_MACH "internal/bootstrap.mach"
#define BOOTSTRAP_AST "internal/bootstrap.ast.json"
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
#define CELL_SHOP_DIR ".cell"
#define CELL_CORE_DIR "packages/core"
@@ -179,14 +178,9 @@ void script_startup(cell_rt *prt)
cell_rt *crt = JS_GetContextOpaque(js);
JS_FreeValue(js, js_blob_use(js));
// Load pre-compiled bootstrap bytecode (.mach), fall back to AST JSON
// Load pre-compiled bootstrap bytecode (.mach)
size_t boot_size;
int boot_is_bin = 1;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
if (!boot_data) {
boot_is_bin = 0;
boot_data = load_core_file(BOOTSTRAP_AST, &boot_size);
}
if (!boot_data) {
printf("ERROR: Could not load bootstrap from %s!\n", core_path);
return;
@@ -225,17 +219,8 @@ void script_startup(cell_rt *prt)
// Run through MACH VM
crt->state = ACTOR_RUNNING;
JSValue v;
if (boot_is_bin) {
v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
} else {
cJSON *ast = cJSON_Parse(boot_data);
free(boot_data);
if (!ast) { printf("ERROR: Failed to parse bootstrap AST\n"); return; }
v = JS_RunMachTree(js, ast, hidden_env);
cJSON_Delete(ast);
}
JSValue v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
uncaught_exception(js, v);
crt->state = ACTOR_IDLE;
set_actor_state(crt);
@@ -359,12 +344,7 @@ int cell_init(int argc, char **argv)
actor_initialize();
size_t boot_size;
int boot_is_bin = 1;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
if (!boot_data) {
boot_is_bin = 0;
boot_data = load_core_file(BOOTSTRAP_AST, &boot_size);
}
if (!boot_data) {
printf("ERROR: Could not load bootstrap from %s\n", core_path);
return 1;
@@ -433,17 +413,8 @@ int cell_init(int argc, char **argv)
JS_SetPropertyStr(ctx, hidden_env, "args", args_arr);
hidden_env = JS_Stone(ctx, hidden_env);
JSValue result;
if (boot_is_bin) {
result = JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
} else {
cJSON *ast = cJSON_Parse(boot_data);
free(boot_data);
if (!ast) { printf("Failed to parse bootstrap AST\n"); JS_FreeContext(ctx); JS_FreeRuntime(g_runtime); return 1; }
result = JS_RunMachTree(ctx, ast, hidden_env);
cJSON_Delete(ast);
}
JSValue result = JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data);
int exit_code = 0;
if (JS_IsException(result)) {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -812,28 +812,6 @@ typedef struct JSCodeRegister {
uint16_t disruption_pc; /* start of disruption handler (0 = none) */
} JSCodeRegister;
/* Pre-parsed MCODE for a single function (off-heap, never GC'd).
Created by jsmcode_parse from cJSON MCODE output.
Instructions remain as cJSON pointers for string-based dispatch. */
typedef struct JSMCode {
uint16_t nr_args;
uint16_t nr_slots;
/* Pre-flattened instruction array (cJSON array items → C array for O(1) access) */
cJSON **instrs;
uint32_t instr_count;
/* Label map: label string → instruction index */
struct { const char *name; uint32_t index; } *labels;
uint32_t label_count;
/* Nested function definitions (indexes into top-level functions array) */
struct JSMCode **functions;
uint32_t func_count;
/* Keep root cJSON alive (owns all the cJSON nodes instrs[] point into) */
cJSON *json_root;
MachLineEntry *line_table; /* [instr_count], parallel to instrs[] */
const char *name; /* function name (points into cJSON tree) */
const char *filename; /* source filename (points into cJSON tree) */
uint16_t disruption_pc; /* start of disruption handler (0 = none) */
} JSMCode;
/* Frame for closures - used by link-time relocation model where closures
reference outer frames via (depth, slot) addressing.
@@ -1306,7 +1284,6 @@ typedef enum {
JS_FUNC_KIND_BYTECODE,
JS_FUNC_KIND_C_DATA,
JS_FUNC_KIND_REGISTER, /* register-based VM function */
JS_FUNC_KIND_MCODE, /* MCODE JSON interpreter */
} JSFunctionKind;
typedef struct JSFunction {
@@ -1330,11 +1307,6 @@ typedef struct JSFunction {
JSValue env_record; /* stone record, module environment */
JSValue outer_frame; /* JSFrame JSValue, for closures */
} reg;
struct {
JSMCode *code; /* pre-parsed MCODE (off-heap) */
JSValue outer_frame; /* lexical parent frame for closures */
JSValue env_record; /* module env or JS_NULL */
} mcode;
} u;
} JSFunction;
@@ -1527,8 +1499,6 @@ JSValue js_call_c_function (JSContext *ctx, JSValue func_obj, JSValue this_obj,
JSValue js_call_bound_function (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv);
JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv, int flags);
JSValue JS_CallRegisterVM(JSContext *ctx, JSCodeRegister *code, JSValue this_obj, int argc, JSValue *argv, JSValue env, JSValue outer_frame);
JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj,
int argc, JSValue *argv, JSValue outer_frame);
int JS_DeleteProperty (JSContext *ctx, JSValue obj, JSValue prop);
JSValue __attribute__ ((format (printf, 2, 3)))
JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...);
@@ -1860,13 +1830,6 @@ typedef struct {
} GetLineColCache;
/* === MachVarInfo (shared by mach.c and mcode.c) === */
typedef struct MachVarInfo {
char *name;
int slot;
int is_const; /* 1 for def, function args; 0 for var */
int is_closure; /* 1 if captured by a nested function */
} MachVarInfo;
/* === PPretext (parser pretext, system-malloc, used by cell_js.c parser) === */
typedef struct PPretext {
@@ -2057,8 +2020,5 @@ JSFrameRegister *alloc_frame_register(JSContext *ctx, int slot_count);
cJSON *mach_find_scope_record(cJSON *scopes, int function_nr);
int reg_vm_check_interrupt(JSContext *ctx);
/* mcode.c exports */
JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, int argc, JSValue *argv, JSValue outer_frame);
#endif /* QUICKJS_INTERNAL_H */

View File

@@ -1091,34 +1091,12 @@ MachCode *JS_DeserializeMachCode(const uint8_t *data, size_t size);
/* Load compiled MachCode into a JSContext, materializing JSValues. */
struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env);
/* Dump MACH bytecode to stdout. Takes AST cJSON tree. */
void JS_DumpMachTree (JSContext *ctx, struct cJSON *ast, JSValue env);
/* Dump MACH bytecode to stdout. Takes AST JSON string. */
void JS_DumpMach (JSContext *ctx, const char *ast_json, JSValue env);
/* Compile and execute MACH bytecode from AST cJSON tree. */
JSValue JS_RunMachTree (JSContext *ctx, struct cJSON *ast, JSValue env);
/* Compile and execute MACH bytecode from AST JSON string. */
JSValue JS_RunMach (JSContext *ctx, const char *ast_json, JSValue env);
/* Deserialize and execute pre-compiled MACH binary bytecode. */
JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env);
/* Compile mcode JSON IR to MachCode binary. */
MachCode *mach_compile_mcode(struct cJSON *mcode_json);
/* Execute MCODE from cJSON tree. Takes ownership of root. */
JSValue JS_CallMcodeTree (JSContext *ctx, struct cJSON *root);
/* Execute MCODE from cJSON tree with hidden env. Takes ownership of root. */
JSValue JS_CallMcodeTreeEnv (JSContext *ctx, struct cJSON *root, JSValue env);
/* Parse and execute MCODE JSON string.
Returns result of execution, or JS_EXCEPTION on error. */
JSValue JS_CallMcode (JSContext *ctx, const char *mcode_json);
/* Get stack trace as cJSON array of frame objects.
Returns NULL if no register VM frame is active.
Caller must call cJSON_Delete() on the result. */

View File

@@ -1139,10 +1139,6 @@ void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8_t *fro
nested->name = gc_copy_value (ctx, nested->name, from_base, from_end, to_base, to_free, to_end);
}
}
} else if (fn->kind == JS_FUNC_KIND_MCODE) {
/* MCODE function - scan outer_frame and env_record */
fn->u.mcode.outer_frame = gc_copy_value (ctx, fn->u.mcode.outer_frame, from_base, from_end, to_base, to_free, to_end);
fn->u.mcode.env_record = gc_copy_value (ctx, fn->u.mcode.env_record, from_base, from_end, to_base, to_free, to_end);
}
break;
}
@@ -4630,8 +4626,6 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
case JS_FUNC_KIND_REGISTER:
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
f->u.reg.env_record, f->u.reg.outer_frame);
case JS_FUNC_KIND_MCODE:
return mcode_exec (ctx, f->u.mcode.code, this_obj, argc, argv, f->u.mcode.outer_frame);
default:
return JS_ThrowTypeError (ctx, "not a function");
}
@@ -4653,8 +4647,6 @@ JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, J
case JS_FUNC_KIND_REGISTER:
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
f->u.reg.env_record, f->u.reg.outer_frame);
case JS_FUNC_KIND_MCODE:
return mcode_exec (ctx, f->u.mcode.code, this_obj, argc, argv, f->u.mcode.outer_frame);
default:
return JS_ThrowTypeError (ctx, "not a function");
}
@@ -10117,83 +10109,6 @@ int js_is_blob (JSContext *js, JSValue v) {
* ============================================================================
*/
/* mach_eval_ast(name, ast_json, env?) - compile pre-parsed AST and run */
static JSValue js_mach_eval_ast (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
return JS_ThrowTypeError (ctx, "mach_eval_ast requires (name, ast_json) text arguments");
const char *name = JS_ToCString (ctx, argv[0]);
if (!name) return JS_EXCEPTION;
const char *json_str = JS_ToCString (ctx, argv[1]);
if (!json_str) {
JS_FreeCString (ctx, name);
return JS_EXCEPTION;
}
cJSON *ast = cJSON_Parse (json_str);
JS_FreeCString (ctx, json_str);
if (!ast) {
JS_FreeCString (ctx, name);
return JS_ThrowSyntaxError (ctx, "mach_eval_ast: failed to parse AST JSON");
}
/* Set the filename on the AST root */
cJSON_DeleteItemFromObjectCaseSensitive (ast, "filename");
cJSON_AddStringToObject (ast, "filename", name);
JSValue env = (argc >= 3 && JS_IsObject (argv[2])) ? argv[2] : JS_NULL;
JSValue result = JS_RunMachTree (ctx, ast, env);
cJSON_Delete (ast);
JS_FreeCString (ctx, name);
return result;
}
/* mach_compile_ast(name, ast_json) - compile pre-parsed AST to binary blob */
static JSValue js_mach_compile_ast (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
return JS_ThrowTypeError (ctx, "mach_compile_ast requires (name, ast_json) text arguments");
const char *name = JS_ToCString (ctx, argv[0]);
if (!name) return JS_EXCEPTION;
const char *json_str = JS_ToCString (ctx, argv[1]);
if (!json_str) {
JS_FreeCString (ctx, name);
return JS_EXCEPTION;
}
cJSON *ast = cJSON_Parse (json_str);
JS_FreeCString (ctx, json_str);
if (!ast) {
JS_FreeCString (ctx, name);
return JS_ThrowSyntaxError (ctx, "mach_compile_ast: failed to parse AST JSON");
}
cJSON_DeleteItemFromObjectCaseSensitive (ast, "filename");
cJSON_AddStringToObject (ast, "filename", name);
MachCode *mc = JS_CompileMachTree (ast);
cJSON_Delete (ast);
JS_FreeCString (ctx, name);
if (!mc)
return JS_ThrowSyntaxError (ctx, "mach_compile_ast: failed to compile AST");
size_t blob_size;
uint8_t *buf = JS_SerializeMachCode (mc, &blob_size);
JS_FreeMachCode (mc);
if (!buf)
return JS_ThrowInternalError (ctx, "mach_compile_ast: serialization failed");
JSValue result = js_new_blob_stoned_copy (ctx, buf, blob_size);
sys_free (buf);
return result;
}
/* mach_load(blob, env?) - deserialize and execute binary blob */
static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1)
@@ -10207,6 +10122,11 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
if (!mc)
return JS_ThrowSyntaxError (ctx, "mach_load: failed to deserialize bytecode");
{
extern void verify_getup(MachCode *mc, const char *path);
verify_getup(mc, "MACH_LOAD");
}
JSValue env = (argc >= 2 && JS_IsObject (argv[1])) ? argv[1] : JS_NULL;
JSGCRef env_ref;
@@ -10220,35 +10140,6 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
return result;
}
/* mcode_run(name, mcode_json, env?) - run pre-compiled mcode JSON */
static JSValue js_mcode_run (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
return JS_ThrowTypeError (ctx, "mcode_run requires (name, mcode_json) text arguments");
const char *name = JS_ToCString (ctx, argv[0]);
if (!name) return JS_EXCEPTION;
const char *json_str = JS_ToCString (ctx, argv[1]);
if (!json_str) {
JS_FreeCString (ctx, name);
return JS_EXCEPTION;
}
cJSON *mcode = cJSON_Parse (json_str);
JS_FreeCString (ctx, json_str);
if (!mcode) {
JS_FreeCString (ctx, name);
return JS_ThrowSyntaxError (ctx, "mcode_run: failed to parse mcode JSON");
}
JSValue env = (argc >= 3 && JS_IsObject (argv[2])) ? argv[2] : JS_NULL;
JSValue result = JS_CallMcodeTreeEnv (ctx, mcode, env);
/* mcode tree ownership transferred to JS_CallMcodeTreeEnv — do not free */
JS_FreeCString (ctx, name);
return result;
}
/* mach_eval_mcode(name, mcode_json, env?) - compile mcode IR and run via register VM */
static JSValue js_mach_eval_mcode (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
@@ -10298,6 +10189,61 @@ static JSValue js_mach_eval_mcode (JSContext *ctx, JSValue this_val, int argc, J
return result;
}
/* mach_compile_mcode_bin(name, mcode_json) - compile mcode IR to serialized binary blob */
static JSValue js_mach_compile_mcode_bin (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 2 || !JS_IsText (argv[0]) || !JS_IsText (argv[1]))
return JS_ThrowTypeError (ctx, "mach_compile_mcode_bin requires (name, mcode_json) text arguments");
const char *name = JS_ToCString (ctx, argv[0]);
if (!name) return JS_EXCEPTION;
const char *json_str = JS_ToCString (ctx, argv[1]);
if (!json_str) {
JS_FreeCString (ctx, name);
return JS_EXCEPTION;
}
cJSON *mcode = cJSON_Parse (json_str);
JS_FreeCString (ctx, json_str);
if (!mcode) {
JS_FreeCString (ctx, name);
return JS_ThrowSyntaxError (ctx, "mach_compile_mcode_bin: failed to parse mcode JSON");
}
if (!cJSON_GetObjectItemCaseSensitive (mcode, "filename"))
cJSON_AddStringToObject (mcode, "filename", name);
MachCode *mc = mach_compile_mcode (mcode);
cJSON_Delete (mcode);
JS_FreeCString (ctx, name);
if (!mc)
return JS_ThrowInternalError (ctx, "mach_compile_mcode_bin: compilation failed");
size_t size = 0;
uint8_t *data = JS_SerializeMachCode (mc, &size);
/* DEBUG: verify round-trip */
{
MachCode *mc2 = JS_DeserializeMachCode (data, size);
if (mc2) {
extern void verify_getup(MachCode *mc, const char *path);
verify_getup(mc2, "ROUNDTRIP");
JS_FreeMachCode (mc2);
}
}
JS_FreeMachCode (mc);
if (!data)
return JS_ThrowInternalError (ctx, "mach_compile_mcode_bin: serialization failed");
JSValue blob = js_new_blob_stoned_copy (ctx, data, size);
sys_free (data);
return blob;
}
/* ============================================================================
* stone() function - deep freeze with blob support
* ============================================================================
@@ -11398,11 +11344,9 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
}
/* Core functions - using GC-safe helper */
js_set_global_cfunc(ctx, "mach_eval_ast", js_mach_eval_ast, 3);
js_set_global_cfunc(ctx, "mcode_run", js_mcode_run, 3);
js_set_global_cfunc(ctx, "mach_compile_ast", js_mach_compile_ast, 2);
js_set_global_cfunc(ctx, "mach_load", js_mach_load, 2);
js_set_global_cfunc(ctx, "mach_eval_mcode", js_mach_eval_mcode, 3);
js_set_global_cfunc(ctx, "mach_compile_mcode_bin", js_mach_compile_mcode_bin, 2);
js_set_global_cfunc(ctx, "stone", js_cell_stone, 1);
js_set_global_cfunc(ctx, "length", js_cell_length, 1);
js_set_global_cfunc(ctx, "call", js_cell_call, 3);
@@ -13150,17 +13094,6 @@ cJSON *JS_GetStack(JSContext *ctx) {
line = code->line_table[pc].line;
col = code->line_table[pc].col;
}
} else if (fn->kind == JS_FUNC_KIND_MCODE && fn->u.mcode.code) {
JSMCode *code = fn->u.mcode.code;
file = code->filename;
func_name = code->name;
if (!is_first) {
pc = (uint32_t)(JS_VALUE_GET_INT(frame->address) >> 16);
}
if (code->line_table && pc < code->instr_count) {
line = code->line_table[pc].line;
col = code->line_table[pc].col;
}
}
cJSON *entry = cJSON_CreateObject();

Binary file not shown.

Binary file not shown.