Merge branch 'pretty_mcode' into runtime_rework
This commit is contained in:
23267
fold.cm.mcode
Normal file
23267
fold.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
@@ -24,15 +24,21 @@ function use_basic(path) {
|
||||
return result
|
||||
}
|
||||
|
||||
// Load a module from .mach bytecode (bootstrap modules have no source fallback)
|
||||
// Load a module from .mach/.mcode bytecode (bootstrap modules have no source fallback)
|
||||
function boot_load(name, env) {
|
||||
var mach_path = core_path + '/' + name + ".mach"
|
||||
var mach_path = core_path + '/' + name + ".cm.mach"
|
||||
var mcode_path = core_path + '/' + name + ".cm.mcode"
|
||||
var data = null
|
||||
var mcode_json = null
|
||||
if (fd.is_file(mach_path)) {
|
||||
data = fd.slurp(mach_path)
|
||||
return mach_load(data, env)
|
||||
}
|
||||
print("error: missing bootstrap bytecode: " + mach_path + "\n")
|
||||
if (fd.is_file(mcode_path)) {
|
||||
mcode_json = text(fd.slurp(mcode_path))
|
||||
return mach_eval_mcode(name, mcode_json, env)
|
||||
}
|
||||
print("error: missing bootstrap bytecode: " + name + "\n")
|
||||
disrupt
|
||||
}
|
||||
|
||||
@@ -50,33 +56,45 @@ use_cache['mcode'] = mcode_mod
|
||||
var streamline_mod = null
|
||||
var qbe_emit_mod = null
|
||||
|
||||
// Warn if any .cm source is newer than its .mach bytecode
|
||||
// Warn if any .cm source is newer than its compiled bytecode
|
||||
function check_mach_stale() {
|
||||
var pairs = [
|
||||
["tokenize.cm", "tokenize.mach"],
|
||||
["parse.cm", "parse.mach"],
|
||||
["fold.cm", "fold.mach"],
|
||||
["mcode.cm", "mcode.mach"],
|
||||
["streamline.cm", "streamline.mach"],
|
||||
["qbe.cm", "qbe.mach"],
|
||||
["qbe_emit.cm", "qbe_emit.mach"],
|
||||
["internal/bootstrap.cm", "internal/bootstrap.mach"],
|
||||
["internal/engine.cm", "internal/engine.mach"]
|
||||
var sources = [
|
||||
"tokenize.cm",
|
||||
"parse.cm",
|
||||
"fold.cm",
|
||||
"mcode.cm",
|
||||
"streamline.cm",
|
||||
"qbe.cm",
|
||||
"qbe_emit.cm",
|
||||
"internal/bootstrap.cm",
|
||||
"internal/engine.cm"
|
||||
]
|
||||
var stale = []
|
||||
var _i = 0
|
||||
var cm_path = null
|
||||
var mach_path = null
|
||||
var mcode_path = null
|
||||
var cm_stat = null
|
||||
var mach_stat = null
|
||||
while (_i < length(pairs)) {
|
||||
cm_path = core_path + '/' + pairs[_i][0]
|
||||
mach_path = core_path + '/' + pairs[_i][1]
|
||||
if (fd.is_file(cm_path) && fd.is_file(mach_path)) {
|
||||
var compiled_stat = null
|
||||
var best_mtime = null
|
||||
while (_i < length(sources)) {
|
||||
cm_path = core_path + '/' + sources[_i]
|
||||
mach_path = cm_path + '.mach'
|
||||
mcode_path = cm_path + '.mcode'
|
||||
best_mtime = null
|
||||
if (fd.is_file(mach_path)) {
|
||||
best_mtime = fd.stat(mach_path).mtime
|
||||
}
|
||||
if (fd.is_file(mcode_path)) {
|
||||
compiled_stat = fd.stat(mcode_path)
|
||||
if (best_mtime == null || compiled_stat.mtime > best_mtime) {
|
||||
best_mtime = compiled_stat.mtime
|
||||
}
|
||||
}
|
||||
if (best_mtime != null && fd.is_file(cm_path)) {
|
||||
cm_stat = fd.stat(cm_path)
|
||||
mach_stat = fd.stat(mach_path)
|
||||
if (cm_stat.mtime > mach_stat.mtime) {
|
||||
push(stale, pairs[_i][0])
|
||||
if (cm_stat.mtime > best_mtime) {
|
||||
push(stale, sources[_i])
|
||||
}
|
||||
}
|
||||
_i = _i + 1
|
||||
@@ -123,10 +141,12 @@ function analyze(src, filename) {
|
||||
return ast
|
||||
}
|
||||
|
||||
// Load a module from .mach bytecode, falling back to source compilation
|
||||
// Load a module from .mach/.mcode bytecode, falling back to source compilation
|
||||
function load_module(name, env) {
|
||||
var mach_path = core_path + '/' + name + ".mach"
|
||||
var mach_path = core_path + '/' + name + ".cm.mach"
|
||||
var mcode_path = core_path + '/' + name + ".cm.mcode"
|
||||
var data = null
|
||||
var mcode_json = null
|
||||
var src_path = null
|
||||
var src = null
|
||||
var ast = null
|
||||
@@ -136,6 +156,10 @@ function load_module(name, env) {
|
||||
data = fd.slurp(mach_path)
|
||||
return mach_load(data, env)
|
||||
}
|
||||
if (fd.is_file(mcode_path)) {
|
||||
mcode_json = text(fd.slurp(mcode_path))
|
||||
return mach_eval_mcode(name, mcode_json, env)
|
||||
}
|
||||
src_path = core_path + '/' + name + ".cm"
|
||||
src = text(fd.slurp(src_path))
|
||||
ast = analyze(src, src_path)
|
||||
@@ -176,6 +200,8 @@ function run_ast(name, ast, env) {
|
||||
function use_fn(path) {
|
||||
var file_path = null
|
||||
var mach_path = null
|
||||
var mcode_path = null
|
||||
var mcode_json = null
|
||||
var data = null
|
||||
var script = null
|
||||
var ast = null
|
||||
@@ -183,10 +209,10 @@ function use_fn(path) {
|
||||
if (use_cache[path])
|
||||
return use_cache[path]
|
||||
|
||||
// Try .mach bytecode first (CWD then core_path)
|
||||
mach_path = path + '.mach'
|
||||
// Try .cm.mach bytecode first (CWD then core_path)
|
||||
mach_path = path + '.cm.mach'
|
||||
if (!fd.is_file(mach_path))
|
||||
mach_path = core_path + '/' + path + '.mach'
|
||||
mach_path = core_path + '/' + path + '.cm.mach'
|
||||
if (fd.is_file(mach_path)) {
|
||||
data = fd.slurp(mach_path)
|
||||
result = mach_load(data, {use: use_fn})
|
||||
@@ -194,6 +220,17 @@ function use_fn(path) {
|
||||
return result
|
||||
}
|
||||
|
||||
// Try .cm.mcode JSON IR (CWD then core_path)
|
||||
mcode_path = path + '.cm.mcode'
|
||||
if (!fd.is_file(mcode_path))
|
||||
mcode_path = core_path + '/' + path + '.cm.mcode'
|
||||
if (fd.is_file(mcode_path)) {
|
||||
mcode_json = text(fd.slurp(mcode_path))
|
||||
result = mach_eval_mcode(path, mcode_json, {use: use_fn})
|
||||
use_cache[path] = result
|
||||
return result
|
||||
}
|
||||
|
||||
// Try .cm source (CWD then core_path)
|
||||
file_path = path + '.cm'
|
||||
if (!fd.is_file(file_path))
|
||||
@@ -215,14 +252,20 @@ function use_fn(path) {
|
||||
|
||||
// Helper to load engine.cm and run it with given env
|
||||
function load_engine(env) {
|
||||
var engine_path = core_path + '/internal/engine.mach'
|
||||
var engine_path = core_path + '/internal/engine.cm.mach'
|
||||
var mcode_path = core_path + '/internal/engine.cm.mcode'
|
||||
var data = null
|
||||
var mcode_json = null
|
||||
var engine_src = null
|
||||
var engine_ast = null
|
||||
if (fd.is_file(engine_path)) {
|
||||
data = fd.slurp(engine_path)
|
||||
return mach_load(data, env)
|
||||
}
|
||||
if (fd.is_file(mcode_path)) {
|
||||
mcode_json = text(fd.slurp(mcode_path))
|
||||
return mach_eval_mcode('engine', mcode_json, env)
|
||||
}
|
||||
engine_path = core_path + '/internal/engine.cm'
|
||||
engine_src = text(fd.slurp(engine_path))
|
||||
engine_ast = analyze(engine_src, engine_path)
|
||||
|
||||
4080
internal/bootstrap.cm.mcode
Normal file
4080
internal/bootstrap.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -76,14 +76,22 @@ function use_core(path) {
|
||||
arrfor(array(core_extras), function(k) { env[k] = core_extras[k] })
|
||||
if (sym) env.native = sym
|
||||
|
||||
// Check for pre-compiled .mach file first
|
||||
var mach_path = core_path + '/' + path + '.mach'
|
||||
// Check for pre-compiled .cm.mach file first
|
||||
var mach_path = core_path + '/' + path + '.cm.mach'
|
||||
if (fd.is_file(mach_path)) {
|
||||
result = mach_load(fd.slurp(mach_path), env)
|
||||
use_cache[cache_key] = result
|
||||
return result
|
||||
}
|
||||
|
||||
// Check for .cm.mcode JSON IR
|
||||
var mcode_path = core_path + '/' + path + '.cm.mcode'
|
||||
if (fd.is_file(mcode_path)) {
|
||||
result = mach_eval_mcode('core:' + path, text(fd.slurp(mcode_path)), env)
|
||||
use_cache[cache_key] = result
|
||||
return result
|
||||
}
|
||||
|
||||
// Fall back to source .cm file — compile at runtime
|
||||
var file_path = core_path + '/' + path + MOD_EXT
|
||||
if (fd.is_file(file_path)) {
|
||||
|
||||
7940
internal/engine.cm.mcode
Normal file
7940
internal/engine.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
22949
mcode.cm.mcode
Normal file
22949
mcode.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
BIN
mcode.mach
BIN
mcode.mach
Binary file not shown.
28603
parse.cm.mcode
Normal file
28603
parse.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
BIN
parse.mach
BIN
parse.mach
Binary file not shown.
2649
qbe.cm.mcode
Normal file
2649
qbe.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
12522
qbe_emit.cm.mcode
Normal file
12522
qbe_emit.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
BIN
qbe_emit.mach
BIN
qbe_emit.mach
Binary file not shown.
110
regen.cm
110
regen.cm
@@ -1,4 +1,4 @@
|
||||
// regen.cm — regenerate .mach bytecode files
|
||||
// regen.cm — regenerate .cm.mcode files
|
||||
// Run with: ./cell --core . regen.cm
|
||||
|
||||
var fd = use("fd")
|
||||
@@ -10,15 +10,15 @@ var mcode = use("mcode")
|
||||
var streamline = use("streamline")
|
||||
|
||||
var files = [
|
||||
{src: "tokenize.cm", name: "tokenize", out: "tokenize.mach"},
|
||||
{src: "parse.cm", name: "parse", out: "parse.mach"},
|
||||
{src: "fold.cm", name: "fold", out: "fold.mach"},
|
||||
{src: "mcode.cm", name: "mcode", out: "mcode.mach"},
|
||||
{src: "streamline.cm", name: "streamline", out: "streamline.mach"},
|
||||
{src: "qbe.cm", name: "qbe", out: "qbe.mach"},
|
||||
{src: "qbe_emit.cm", name: "qbe_emit", out: "qbe_emit.mach"},
|
||||
{src: "internal/bootstrap.cm", name: "bootstrap", out: "internal/bootstrap.mach"},
|
||||
{src: "internal/engine.cm", name: "engine", out: "internal/engine.mach"}
|
||||
{src: "tokenize.cm", name: "tokenize", out: "tokenize.cm.mcode"},
|
||||
{src: "parse.cm", name: "parse", out: "parse.cm.mcode"},
|
||||
{src: "fold.cm", name: "fold", out: "fold.cm.mcode"},
|
||||
{src: "mcode.cm", name: "mcode", out: "mcode.cm.mcode"},
|
||||
{src: "streamline.cm", name: "streamline", out: "streamline.cm.mcode"},
|
||||
{src: "qbe.cm", name: "qbe", out: "qbe.cm.mcode"},
|
||||
{src: "qbe_emit.cm", name: "qbe_emit", out: "qbe_emit.cm.mcode"},
|
||||
{src: "internal/bootstrap.cm", name: "bootstrap", out: "internal/bootstrap.cm.mcode"},
|
||||
{src: "internal/engine.cm", name: "engine", out: "internal/engine.cm.mcode"}
|
||||
]
|
||||
|
||||
var i = 0
|
||||
@@ -29,14 +29,95 @@ var ast = null
|
||||
var folded = null
|
||||
var compiled = null
|
||||
var optimized = null
|
||||
var mcode_json = null
|
||||
var bytecode = null
|
||||
var mcode_text = null
|
||||
var f = null
|
||||
var errs = null
|
||||
var ei = 0
|
||||
var e = null
|
||||
var had_errors = false
|
||||
|
||||
// Collapse leaf arrays (instruction arrays) onto single lines
|
||||
var compact_arrays = function(json_text) {
|
||||
var lines = array(json_text, "\n")
|
||||
var result = []
|
||||
var i = 0
|
||||
var line = null
|
||||
var trimmed = null
|
||||
var collecting = false
|
||||
var collected = null
|
||||
var indent = null
|
||||
var is_leaf = null
|
||||
var j = 0
|
||||
var inner = null
|
||||
var parts = null
|
||||
var trailing = null
|
||||
var chars = null
|
||||
var k = 0
|
||||
|
||||
while (i < length(lines)) {
|
||||
line = lines[i]
|
||||
trimmed = trim(line)
|
||||
if (collecting == false && trimmed == "[") {
|
||||
collecting = true
|
||||
chars = array(line)
|
||||
k = 0
|
||||
while (k < length(chars) && chars[k] == " ") {
|
||||
k = k + 1
|
||||
}
|
||||
indent = text(line, 0, k)
|
||||
collected = []
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
if (collecting) {
|
||||
if (trimmed == "]" || trimmed == "],") {
|
||||
is_leaf = true
|
||||
j = 0
|
||||
while (j < length(collected)) {
|
||||
inner = trim(collected[j])
|
||||
if (starts_with(inner, "[") || starts_with(inner, "{")) {
|
||||
is_leaf = false
|
||||
}
|
||||
j = j + 1
|
||||
}
|
||||
if (is_leaf && length(collected) > 0) {
|
||||
parts = []
|
||||
j = 0
|
||||
while (j < length(collected)) {
|
||||
inner = trim(collected[j])
|
||||
if (ends_with(inner, ",")) {
|
||||
inner = text(inner, 0, length(inner) - 1)
|
||||
}
|
||||
parts[] = inner
|
||||
j = j + 1
|
||||
}
|
||||
trailing = ""
|
||||
if (ends_with(trimmed, ",")) {
|
||||
trailing = ","
|
||||
}
|
||||
result[] = `${indent}[${text(parts, ", ")}]${trailing}`
|
||||
} else {
|
||||
result[] = `${indent}[`
|
||||
j = 0
|
||||
while (j < length(collected)) {
|
||||
result[] = collected[j]
|
||||
j = j + 1
|
||||
}
|
||||
result[] = line
|
||||
}
|
||||
collecting = false
|
||||
} else {
|
||||
collected[] = line
|
||||
}
|
||||
i = i + 1
|
||||
continue
|
||||
}
|
||||
result[] = line
|
||||
i = i + 1
|
||||
}
|
||||
return text(result, "\n")
|
||||
}
|
||||
|
||||
while (i < length(files)) {
|
||||
entry = files[i]
|
||||
src = text(fd.slurp(entry.src))
|
||||
@@ -62,10 +143,9 @@ while (i < length(files)) {
|
||||
folded = fold(ast)
|
||||
compiled = mcode(folded)
|
||||
optimized = streamline(compiled)
|
||||
mcode_json = json.encode(optimized)
|
||||
bytecode = mach_compile_mcode_bin(entry.name, mcode_json)
|
||||
mcode_text = compact_arrays(json.encode(optimized, null, 2))
|
||||
f = fd.open(entry.out, "w")
|
||||
fd.write(f, bytecode)
|
||||
fd.write(f, mcode_text)
|
||||
fd.close(f)
|
||||
print(`wrote ${entry.out}`)
|
||||
i = i + 1
|
||||
|
||||
@@ -11,8 +11,9 @@
|
||||
#include "cell_internal.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
#define BOOTSTRAP_MACH "internal/bootstrap.mach"
|
||||
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
|
||||
#define BOOTSTRAP_MACH "internal/bootstrap.cm.mach"
|
||||
#define BOOTSTRAP_MCODE "internal/bootstrap.cm.mcode"
|
||||
#define BOOTSTRAP_SRC "internal/bootstrap.cm"
|
||||
#define CELL_SHOP_DIR ".cell"
|
||||
#define CELL_CORE_DIR "packages/core"
|
||||
|
||||
@@ -178,9 +179,14 @@ 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)
|
||||
// Load pre-compiled bootstrap (.cm.mach or .cm.mcode)
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
|
||||
int boot_is_mcode = 0;
|
||||
if (!boot_data) {
|
||||
boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
boot_is_mcode = 1;
|
||||
}
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s!\n", core_path);
|
||||
return;
|
||||
@@ -218,7 +224,9 @@ void script_startup(cell_rt *prt)
|
||||
|
||||
// Run through MACH VM
|
||||
crt->state = ACTOR_RUNNING;
|
||||
JSValue v = JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
|
||||
JSValue v = boot_is_mcode
|
||||
? JS_RunMachMcode(js, boot_data, boot_size, hidden_env)
|
||||
: JS_RunMachBin(js, (const uint8_t *)boot_data, boot_size, hidden_env);
|
||||
free(boot_data);
|
||||
uncaught_exception(js, v);
|
||||
crt->state = ACTOR_IDLE;
|
||||
@@ -349,6 +357,11 @@ int cell_init(int argc, char **argv)
|
||||
|
||||
size_t boot_size;
|
||||
char *boot_data = load_core_file(BOOTSTRAP_MACH, &boot_size);
|
||||
int boot_is_mcode = 0;
|
||||
if (!boot_data) {
|
||||
boot_data = load_core_file(BOOTSTRAP_MCODE, &boot_size);
|
||||
boot_is_mcode = 1;
|
||||
}
|
||||
if (!boot_data) {
|
||||
printf("ERROR: Could not load bootstrap from %s\n", core_path);
|
||||
return 1;
|
||||
@@ -417,7 +430,9 @@ int cell_init(int argc, char **argv)
|
||||
JS_SetPropertyStr(ctx, hidden_env, "args", args_arr);
|
||||
hidden_env = JS_Stone(ctx, hidden_env);
|
||||
|
||||
JSValue result = JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
|
||||
JSValue result = boot_is_mcode
|
||||
? JS_RunMachMcode(ctx, boot_data, boot_size, hidden_env)
|
||||
: JS_RunMachBin(ctx, (const uint8_t *)boot_data, boot_size, hidden_env);
|
||||
free(boot_data);
|
||||
|
||||
int exit_code = 0;
|
||||
|
||||
@@ -3166,6 +3166,29 @@ JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue
|
||||
return result;
|
||||
}
|
||||
|
||||
JSValue JS_RunMachMcode(JSContext *ctx, const char *json_str, size_t len, JSValue env) {
|
||||
(void)len;
|
||||
cJSON *mcode = cJSON_Parse(json_str);
|
||||
if (!mcode)
|
||||
return JS_ThrowSyntaxError(ctx, "failed to parse mcode JSON");
|
||||
|
||||
MachCode *mc = mach_compile_mcode(mcode);
|
||||
cJSON_Delete(mcode);
|
||||
if (!mc)
|
||||
return JS_ThrowInternalError(ctx, "mcode compilation failed");
|
||||
|
||||
JSGCRef env_ref;
|
||||
JS_PushGCRef(ctx, &env_ref);
|
||||
env_ref.val = env;
|
||||
|
||||
JSCodeRegister *code = JS_LoadMachCode(ctx, mc, env_ref.val);
|
||||
JS_FreeMachCode(mc);
|
||||
|
||||
JSValue result = JS_CallRegisterVM(ctx, code, ctx->global_obj, 0, NULL, env_ref.val, JS_NULL);
|
||||
JS_PopGCRef(ctx, &env_ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
void JS_DumpMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env) {
|
||||
MachCode *mc = JS_DeserializeMachCode(data, size);
|
||||
if (!mc) {
|
||||
|
||||
@@ -995,6 +995,9 @@ struct JSCodeRegister *JS_LoadMachCode(JSContext *ctx, MachCode *mc, JSValue env
|
||||
/* Deserialize and execute pre-compiled MACH binary bytecode. */
|
||||
JSValue JS_RunMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env);
|
||||
|
||||
/* Parse mcode JSON IR, compile, and execute via register VM. */
|
||||
JSValue JS_RunMachMcode(JSContext *ctx, const char *json_str, size_t len, JSValue env);
|
||||
|
||||
/* Dump disassembly of pre-compiled MACH binary bytecode. */
|
||||
void JS_DumpMachBin(JSContext *ctx, const uint8_t *data, size_t size, JSValue env);
|
||||
|
||||
|
||||
15040
streamline.cm.mcode
Normal file
15040
streamline.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
BIN
streamline.mach
BIN
streamline.mach
Binary file not shown.
10913
tokenize.cm.mcode
Normal file
10913
tokenize.cm.mcode
Normal file
File diff suppressed because it is too large
Load Diff
BIN
tokenize.mach
BIN
tokenize.mach
Binary file not shown.
Reference in New Issue
Block a user