native boot
This commit is contained in:
@@ -52,6 +52,38 @@ function ensure_build_dir() {
|
||||
return dir
|
||||
}
|
||||
|
||||
// --- Native compilation support ---
|
||||
|
||||
function detect_host_target() {
|
||||
var platform = os.platform()
|
||||
var arch = os.arch ? os.arch() : 'arm64'
|
||||
if (platform == 'macOS' || platform == 'darwin')
|
||||
return arch == 'x86_64' ? 'macos_x86_64' : 'macos_arm64'
|
||||
if (platform == 'Linux' || platform == 'linux')
|
||||
return arch == 'x86_64' ? 'linux' : 'linux_arm64'
|
||||
if (platform == 'Windows' || platform == 'windows')
|
||||
return 'windows'
|
||||
return null
|
||||
}
|
||||
|
||||
function detect_cc() {
|
||||
var platform = os.platform()
|
||||
if (platform == 'macOS') return 'clang'
|
||||
return 'cc'
|
||||
}
|
||||
|
||||
function native_dylib_cache_path(src, target) {
|
||||
var native_key = src + '\n' + target + '\nnative\n'
|
||||
var full_key = native_key + '\nnative'
|
||||
return cache_path(content_hash(full_key))
|
||||
}
|
||||
|
||||
var _engine_host_target = null
|
||||
var _engine_cc = null
|
||||
var _engine_is_darwin = false
|
||||
var _qbe_mod = null
|
||||
var _qbe_emit_mod = null
|
||||
|
||||
// Load a boot seed module (for compiling pipeline modules on cache miss)
|
||||
function boot_load(name) {
|
||||
var mcode_path = core_path + '/boot/' + name + '.cm.mcode'
|
||||
@@ -85,8 +117,22 @@ function load_pipeline_module(name, env) {
|
||||
var ast = null
|
||||
var compiled = null
|
||||
var mcode_json = null
|
||||
if (fd.is_file(source_path)) {
|
||||
var native_path = null
|
||||
var native_handle = null
|
||||
|
||||
// Native mode: check native cache first
|
||||
if (native_mode && _engine_host_target && fd.is_file(source_path)) {
|
||||
source_blob = fd.slurp(source_path)
|
||||
src = text(source_blob)
|
||||
native_path = native_dylib_cache_path(src, _engine_host_target)
|
||||
if (native_path && fd.is_file(native_path)) {
|
||||
native_handle = os.dylib_open(native_path)
|
||||
return os.native_module_load_named(native_handle, 'cell_main', env)
|
||||
}
|
||||
}
|
||||
|
||||
if (fd.is_file(source_path)) {
|
||||
if (!source_blob) source_blob = fd.slurp(source_path)
|
||||
hash = content_hash(source_blob)
|
||||
cached = cache_path(hash)
|
||||
if (cached && fd.is_file(cached))
|
||||
@@ -99,7 +145,7 @@ function load_pipeline_module(name, env) {
|
||||
boot_par = boot_load("parse")
|
||||
boot_fld = boot_load("fold")
|
||||
boot_mc = boot_load("mcode")
|
||||
src = text(source_blob)
|
||||
if (!src) src = text(source_blob)
|
||||
tok_result = boot_tok(src, source_path)
|
||||
ast = boot_par(tok_result.tokens, src, source_path, boot_tok)
|
||||
if (ast.errors != null && length(ast.errors) > 0) {
|
||||
@@ -112,7 +158,7 @@ function load_pipeline_module(name, env) {
|
||||
compiled = boot_sl(compiled)
|
||||
mcode_json = json.encode(compiled)
|
||||
mach_blob = mach_compile_mcode_bin(name, mcode_json)
|
||||
if (cached) {
|
||||
if (!native_mode && cached) {
|
||||
ensure_build_dir()
|
||||
fd.slurpwrite(cached, mach_blob)
|
||||
}
|
||||
@@ -130,6 +176,13 @@ function load_pipeline_module(name, env) {
|
||||
disrupt
|
||||
}
|
||||
|
||||
// Initialize native compilation state before pipeline loading
|
||||
if (native_mode) {
|
||||
_engine_host_target = detect_host_target()
|
||||
_engine_cc = detect_cc()
|
||||
_engine_is_darwin = os.platform() == 'macOS'
|
||||
}
|
||||
|
||||
// Load compilation pipeline
|
||||
var pipeline_env = stone({use: use_embed})
|
||||
var tokenize_mod = load_pipeline_module('tokenize', pipeline_env)
|
||||
@@ -146,6 +199,16 @@ use_cache['core/mcode'] = mcode_mod
|
||||
use_cache['streamline'] = streamline_mod
|
||||
use_cache['core/streamline'] = streamline_mod
|
||||
|
||||
// Load QBE modules when native mode
|
||||
if (native_mode) {
|
||||
_qbe_mod = load_pipeline_module('qbe', pipeline_env)
|
||||
_qbe_emit_mod = load_pipeline_module('qbe_emit', pipeline_env)
|
||||
use_cache['qbe'] = _qbe_mod
|
||||
use_cache['core/qbe'] = _qbe_mod
|
||||
use_cache['qbe_emit'] = _qbe_emit_mod
|
||||
use_cache['core/qbe_emit'] = _qbe_emit_mod
|
||||
}
|
||||
|
||||
// analyze: tokenize + parse + fold, check for errors
|
||||
function analyze(src, filename) {
|
||||
var tok_result = tokenize_mod(src, filename)
|
||||
@@ -440,6 +503,70 @@ use_cache['core/internal/os'] = os
|
||||
// Extra env properties added as engine initializes (log, runtime fns, etc.)
|
||||
var core_extras = {}
|
||||
|
||||
// Compile a core module to a native dylib, return the dylib path
|
||||
function compile_core_native(name, source_path) {
|
||||
var source_blob = fd.slurp(source_path)
|
||||
var src = text(source_blob)
|
||||
var dylib_path = native_dylib_cache_path(src, _engine_host_target)
|
||||
var ast = null
|
||||
var compiled = null
|
||||
var il_parts = null
|
||||
var helpers_il = null
|
||||
var all_fns = null
|
||||
var full_il = null
|
||||
var asm_text = null
|
||||
var tmp = null
|
||||
var rc = null
|
||||
var rt_o = null
|
||||
var qbe_rt_path = null
|
||||
var link_cmd = null
|
||||
|
||||
if (dylib_path && fd.is_file(dylib_path))
|
||||
return dylib_path
|
||||
|
||||
ast = analyze(src, source_path)
|
||||
compiled = streamline_mod(mcode_mod(ast))
|
||||
il_parts = _qbe_emit_mod(compiled, _qbe_mod, null)
|
||||
|
||||
helpers_il = (il_parts.helpers && length(il_parts.helpers) > 0)
|
||||
? text(il_parts.helpers, "\n") : ""
|
||||
all_fns = text(il_parts.functions, "\n")
|
||||
full_il = il_parts.data + "\n\n" + helpers_il + "\n\n" + all_fns
|
||||
|
||||
asm_text = os.qbe(full_il)
|
||||
tmp = '/tmp/cell_engine_' + replace(name, '/', '_')
|
||||
fd.slurpwrite(tmp + '.s', stone(blob(asm_text)))
|
||||
|
||||
rc = os.system(_engine_cc + ' -c ' + tmp + '.s -o ' + tmp + '.o')
|
||||
if (rc != 0) {
|
||||
os.print("error: assembly failed for " + name + "\n")
|
||||
disrupt
|
||||
}
|
||||
|
||||
rt_o = '/tmp/cell_qbe_rt.o'
|
||||
if (!fd.is_file(rt_o)) {
|
||||
qbe_rt_path = core_path + '/src/qbe_rt.c'
|
||||
rc = os.system(_engine_cc + ' -c ' + qbe_rt_path + ' -o ' + rt_o + ' -fPIC')
|
||||
if (rc != 0) {
|
||||
os.print("error: qbe_rt compilation failed\n")
|
||||
disrupt
|
||||
}
|
||||
}
|
||||
|
||||
ensure_build_dir()
|
||||
link_cmd = _engine_cc + ' -shared -fPIC'
|
||||
if (_engine_is_darwin)
|
||||
link_cmd = link_cmd + ' -undefined dynamic_lookup'
|
||||
link_cmd = link_cmd + ' ' + tmp + '.o ' + rt_o + ' -o ' + dylib_path
|
||||
|
||||
rc = os.system(link_cmd)
|
||||
if (rc != 0) {
|
||||
os.print("error: linking failed for " + name + "\n")
|
||||
disrupt
|
||||
}
|
||||
return dylib_path
|
||||
}
|
||||
|
||||
// Load a core module from the file system
|
||||
function use_core(path) {
|
||||
var cache_key = 'core/' + path
|
||||
@@ -452,6 +579,7 @@ function use_core(path) {
|
||||
var script = null
|
||||
var ast = null
|
||||
var _load_mod = null
|
||||
var _try_native = null
|
||||
|
||||
// Build env: merge core_extras
|
||||
env = {use: use_core}
|
||||
@@ -467,8 +595,34 @@ function use_core(path) {
|
||||
// Compile from source .cm file
|
||||
file_path = core_path + '/' + path + MOD_EXT
|
||||
if (fd.is_file(file_path)) {
|
||||
// Native path: try native cache or compile natively
|
||||
if (native_mode && _qbe_mod && _qbe_emit_mod) {
|
||||
_try_native = function() {
|
||||
var src = null
|
||||
var native_path = null
|
||||
var native_handle = null
|
||||
source_blob = fd.slurp(file_path)
|
||||
src = text(source_blob)
|
||||
native_path = native_dylib_cache_path(src, _engine_host_target)
|
||||
if (native_path && fd.is_file(native_path)) {
|
||||
native_handle = os.dylib_open(native_path)
|
||||
result = os.native_module_load_named(native_handle, 'cell_main', env)
|
||||
return
|
||||
}
|
||||
native_path = compile_core_native('core:' + path, file_path)
|
||||
native_handle = os.dylib_open(native_path)
|
||||
result = os.native_module_load_named(native_handle, 'cell_main', env)
|
||||
} disruption {}
|
||||
_try_native()
|
||||
if (result != null) {
|
||||
use_cache[cache_key] = result
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Bytecode path (fallback or non-native mode)
|
||||
_load_mod = function() {
|
||||
source_blob = fd.slurp(file_path)
|
||||
if (!source_blob) source_blob = fd.slurp(file_path)
|
||||
hash = content_hash(source_blob)
|
||||
cached_path = cache_path(hash)
|
||||
if (cached_path && fd.is_file(cached_path)) {
|
||||
@@ -477,7 +631,7 @@ function use_core(path) {
|
||||
script = text(source_blob)
|
||||
ast = analyze(script, file_path)
|
||||
mach_blob = compile_to_blob('core:' + path, ast)
|
||||
if (cached_path) {
|
||||
if (!native_mode && cached_path) {
|
||||
ensure_build_dir()
|
||||
fd.slurpwrite(cached_path, mach_blob)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user