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', 'miniz.c',
'runtime.c', 'runtime.c',
'mach.c', 'mach.c',
'mcode.c',
'libregexp.c', 'libunicode.c', 'cutils.c', 'dtoa.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 errors = []
var error_count = 0 var error_count = 0
var function_nr = 1 var fn_counter = 1
var ast_node = function(kind, token) { var ast_node = function(kind, token) {
return { return {
@@ -422,8 +422,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = meth_old_cd _control_depth = meth_old_cd
_control_type = meth_old_ct _control_type = meth_old_ct
_expecting_body = meth_old_eb _expecting_body = meth_old_eb
fn.function_nr = function_nr fn.function_nr = fn_counter
function_nr = function_nr + 1 fn_counter = fn_counter + 1
ast_node_end(fn) ast_node_end(fn)
pair.right = fn pair.right = fn
} else if (is_ident && (tok.kind == "," || tok.kind == "}")) { } else if (is_ident && (tok.kind == "," || tok.kind == "}")) {
@@ -918,8 +918,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = old_cd _control_depth = old_cd
_control_type = old_ct _control_type = old_ct
_expecting_body = old_eb _expecting_body = old_eb
node.function_nr = function_nr node.function_nr = fn_counter
function_nr = function_nr + 1 fn_counter = fn_counter + 1
ast_node_end(node) ast_node_end(node)
return node return node
} }
@@ -1008,8 +1008,8 @@ var parse = function(tokens, src, filename, tokenizer) {
_control_depth = old_cd _control_depth = old_cd
_control_type = old_ct _control_type = old_ct
_expecting_body = old_eb _expecting_body = old_eb
node.function_nr = function_nr node.function_nr = fn_counter
function_nr = function_nr + 1 fn_counter = fn_counter + 1
ast_node_end(node) ast_node_end(node)
return 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 tokenize = use("tokenize")
var parse = use("parse") var parse = use("parse")
var fold = use("fold") var fold = use("fold")
var mcode = use("mcode")
var streamline = use("streamline")
var files = [ var files = [
{src: "tokenize.cm", name: "tokenize", out: "tokenize.mach"}, {src: "tokenize.cm", name: "tokenize", out: "tokenize.mach"},
@@ -25,21 +27,49 @@ var src = null
var tok_result = null var tok_result = null
var ast = null var ast = null
var folded = null var folded = null
var ast_json = null var compiled = null
var optimized = null
var mcode_json = null
var bytecode = null var bytecode = null
var f = null var f = null
var errs = null
var ei = 0
var e = null
var had_errors = false
while (i < length(files)) { while (i < length(files)) {
entry = files[i] entry = files[i]
src = text(fd.slurp(entry.src)) src = text(fd.slurp(entry.src))
tok_result = tokenize(src, entry.src) tok_result = tokenize(src, entry.src)
ast = parse(tok_result.tokens, src, entry.src, tokenize) 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) folded = fold(ast)
ast_json = json.encode(folded) compiled = mcode(folded)
bytecode = mach_compile_ast(entry.name, ast_json) optimized = streamline(compiled)
mcode_json = json.encode(optimized)
bytecode = mach_compile_mcode_bin(entry.name, mcode_json)
f = fd.open(entry.out, "w") f = fd.open(entry.out, "w")
fd.write(f, bytecode) fd.write(f, bytecode)
fd.close(f) fd.close(f)
print(`wrote ${entry.out}`) print(`wrote ${entry.out}`)
i = i + 1 i = i + 1
} }
if (had_errors) {
print("regen aborted: fix errors above")
}

View File

@@ -12,7 +12,6 @@
#include "cJSON.h" #include "cJSON.h"
#define BOOTSTRAP_MACH "internal/bootstrap.mach" #define BOOTSTRAP_MACH "internal/bootstrap.mach"
#define BOOTSTRAP_AST "internal/bootstrap.ast.json"
#define BOOTSTRAP_SRC "internal/bootstrap.cm" #define BOOTSTRAP_SRC "internal/bootstrap.cm"
#define CELL_SHOP_DIR ".cell" #define CELL_SHOP_DIR ".cell"
#define CELL_CORE_DIR "packages/core" #define CELL_CORE_DIR "packages/core"
@@ -179,14 +178,9 @@ void script_startup(cell_rt *prt)
cell_rt *crt = JS_GetContextOpaque(js); cell_rt *crt = JS_GetContextOpaque(js);
JS_FreeValue(js, js_blob_use(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; size_t boot_size;
int boot_is_bin = 1;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size); 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) { if (!boot_data) {
printf("ERROR: Could not load bootstrap from %s!\n", core_path); printf("ERROR: Could not load bootstrap from %s!\n", core_path);
return; return;
@@ -225,17 +219,8 @@ void script_startup(cell_rt *prt)
// Run through MACH VM // Run through MACH VM
crt->state = ACTOR_RUNNING; crt->state = ACTOR_RUNNING;
JSValue v; JSValue v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
if (boot_is_bin) {
v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data); 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);
}
uncaught_exception(js, v); uncaught_exception(js, v);
crt->state = ACTOR_IDLE; crt->state = ACTOR_IDLE;
set_actor_state(crt); set_actor_state(crt);
@@ -359,12 +344,7 @@ int cell_init(int argc, char **argv)
actor_initialize(); actor_initialize();
size_t boot_size; size_t boot_size;
int boot_is_bin = 1;
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size); 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) { if (!boot_data) {
printf("ERROR: Could not load bootstrap from %s\n", core_path); printf("ERROR: Could not load bootstrap from %s\n", core_path);
return 1; return 1;
@@ -433,17 +413,8 @@ int cell_init(int argc, char **argv)
JS_SetPropertyStr(ctx, hidden_env, "args", args_arr); JS_SetPropertyStr(ctx, hidden_env, "args", args_arr);
hidden_env = JS_Stone(ctx, hidden_env); hidden_env = JS_Stone(ctx, hidden_env);
JSValue result; JSValue result = JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
if (boot_is_bin) {
result = JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
free(boot_data); 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);
}
int exit_code = 0; int exit_code = 0;
if (JS_IsException(result)) { 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) */ uint16_t disruption_pc; /* start of disruption handler (0 = none) */
} JSCodeRegister; } 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 /* Frame for closures - used by link-time relocation model where closures
reference outer frames via (depth, slot) addressing. reference outer frames via (depth, slot) addressing.
@@ -1306,7 +1284,6 @@ typedef enum {
JS_FUNC_KIND_BYTECODE, JS_FUNC_KIND_BYTECODE,
JS_FUNC_KIND_C_DATA, JS_FUNC_KIND_C_DATA,
JS_FUNC_KIND_REGISTER, /* register-based VM function */ JS_FUNC_KIND_REGISTER, /* register-based VM function */
JS_FUNC_KIND_MCODE, /* MCODE JSON interpreter */
} JSFunctionKind; } JSFunctionKind;
typedef struct JSFunction { typedef struct JSFunction {
@@ -1330,11 +1307,6 @@ typedef struct JSFunction {
JSValue env_record; /* stone record, module environment */ JSValue env_record; /* stone record, module environment */
JSValue outer_frame; /* JSFrame JSValue, for closures */ JSValue outer_frame; /* JSFrame JSValue, for closures */
} reg; } 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; } u;
} JSFunction; } 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_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_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 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); int JS_DeleteProperty (JSContext *ctx, JSValue obj, JSValue prop);
JSValue __attribute__ ((format (printf, 2, 3))) JSValue __attribute__ ((format (printf, 2, 3)))
JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...); JS_ThrowInternalError (JSContext *ctx, const char *fmt, ...);
@@ -1860,13 +1830,6 @@ typedef struct {
} GetLineColCache; } 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) === */ /* === PPretext (parser pretext, system-malloc, used by cell_js.c parser) === */
typedef struct PPretext { 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); cJSON *mach_find_scope_record(cJSON *scopes, int function_nr);
int reg_vm_check_interrupt(JSContext *ctx); 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 */ #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. */ /* Load compiled MachCode into a JSContext, materializing JSValues. */
struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env); 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. */ /* Deserialize and execute pre-compiled MACH binary bytecode. */
JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env); JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env);
/* Compile mcode JSON IR to MachCode binary. */ /* Compile mcode JSON IR to MachCode binary. */
MachCode *mach_compile_mcode(struct cJSON *mcode_json); 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. /* Get stack trace as cJSON array of frame objects.
Returns NULL if no register VM frame is active. Returns NULL if no register VM frame is active.
Caller must call cJSON_Delete() on the result. */ 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); 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; break;
} }
@@ -4630,8 +4626,6 @@ JSValue JS_CallInternal (JSContext *ctx, JSValue func_obj, JSValue this_obj,
case JS_FUNC_KIND_REGISTER: case JS_FUNC_KIND_REGISTER:
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv, return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
f->u.reg.env_record, f->u.reg.outer_frame); 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: default:
return JS_ThrowTypeError (ctx, "not a function"); 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: case JS_FUNC_KIND_REGISTER:
return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv, return JS_CallRegisterVM (ctx, f->u.reg.code, this_obj, argc, argv,
f->u.reg.env_record, f->u.reg.outer_frame); 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: default:
return JS_ThrowTypeError (ctx, "not a function"); 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 */ /* mach_load(blob, env?) - deserialize and execute binary blob */
static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) { static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
if (argc < 1) if (argc < 1)
@@ -10207,6 +10122,11 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
if (!mc) if (!mc)
return JS_ThrowSyntaxError (ctx, "mach_load: failed to deserialize bytecode"); 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; JSValue env = (argc >= 2 && JS_IsObject (argv[1])) ? argv[1] : JS_NULL;
JSGCRef env_ref; JSGCRef env_ref;
@@ -10220,35 +10140,6 @@ static JSValue js_mach_load (JSContext *ctx, JSValue this_val, int argc, JSValue
return result; 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 */ /* 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) { 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])) 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; 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 * stone() function - deep freeze with blob support
* ============================================================================ * ============================================================================
@@ -11398,11 +11344,9 @@ static void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
} }
/* Core functions - using GC-safe helper */ /* 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_load", js_mach_load, 2);
js_set_global_cfunc(ctx, "mach_eval_mcode", js_mach_eval_mcode, 3); 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, "stone", js_cell_stone, 1);
js_set_global_cfunc(ctx, "length", js_cell_length, 1); js_set_global_cfunc(ctx, "length", js_cell_length, 1);
js_set_global_cfunc(ctx, "call", js_cell_call, 3); 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; line = code->line_table[pc].line;
col = code->line_table[pc].col; 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(); cJSON *entry = cJSON_CreateObject();

Binary file not shown.

Binary file not shown.