more native without fallback
This commit is contained in:
@@ -523,6 +523,11 @@ function try_native_mod_dylib(pkg, stem) {
|
||||
var handle = open_dylib_cached(build_path)
|
||||
if (!handle) return null
|
||||
var sym = Shop.c_symbol_for_file(pkg, stem)
|
||||
// Verify the symbol actually exists in the dylib before returning native descriptor
|
||||
if (sym && !os.dylib_has_symbol(handle, sym) && !os.dylib_has_symbol(handle, 'cell_main')) {
|
||||
log.shop('native dylib for ' + stem + ' missing symbol ' + sym + ' and cell_main, falling back to bytecode')
|
||||
return null
|
||||
}
|
||||
return {_native: true, _handle: handle, _sym: sym}
|
||||
}
|
||||
|
||||
@@ -774,8 +779,8 @@ function resolve_mod_fn(path, pkg) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check for native .cm dylib at deterministic path first
|
||||
if (policy.allow_dylib && pkg && _stem) {
|
||||
// Check for native .cm dylib at deterministic path first (only in native mode)
|
||||
if (policy.native && policy.allow_dylib && pkg && _stem) {
|
||||
native_result = try_native_mod_dylib(pkg, _stem)
|
||||
if (native_result != null) return native_result
|
||||
}
|
||||
@@ -846,6 +851,50 @@ function resolve_mod_fn(path, pkg) {
|
||||
disrupt
|
||||
}
|
||||
|
||||
// Resolve a module's bytecode only (skip native dylib check).
|
||||
// Used as fallback when a cached native dylib fails to load.
|
||||
function resolve_mod_fn_bytecode(path, pkg) {
|
||||
if (!fd.is_file(path)) return null
|
||||
|
||||
var content = text(fd.slurp(path))
|
||||
if (length(content) == 0) return null
|
||||
var content_key = stone(blob(content))
|
||||
var cached = null
|
||||
var cached_mcode_path = null
|
||||
var mcode_json = null
|
||||
var compiled = null
|
||||
|
||||
// Check cache for pre-compiled .mach blob
|
||||
cached = pull_from_cache(content_key)
|
||||
if (cached) return cached
|
||||
|
||||
// Check for cached mcode
|
||||
cached_mcode_path = hash_path(content_key, 'mcode')
|
||||
if (fd.is_file(cached_mcode_path)) {
|
||||
mcode_json = text(fd.slurp(cached_mcode_path))
|
||||
compiled = mach_compile_mcode_bin(path, mcode_json)
|
||||
put_into_cache(content_key, compiled)
|
||||
return compiled
|
||||
}
|
||||
|
||||
// Compile from source
|
||||
if (!_mcode_mod) _mcode_mod = use_cache['core/mcode'] || use_cache['mcode']
|
||||
if (!_streamline_mod) _streamline_mod = use_cache['core/streamline'] || use_cache['streamline']
|
||||
if (!_mcode_mod || !_streamline_mod) return null
|
||||
|
||||
var ast = analyze(content, path)
|
||||
var ir = _mcode_mod(ast)
|
||||
var optimized = _streamline_mod(ir)
|
||||
mcode_json = shop_json.encode(optimized)
|
||||
|
||||
fd.ensure_dir(global_shop_path + '/build')
|
||||
fd.slurpwrite(hash_path(content_key, 'mcode'), stone(blob(mcode_json)))
|
||||
|
||||
compiled = mach_compile_mcode_bin(path, mcode_json)
|
||||
put_into_cache(content_key, compiled)
|
||||
return compiled
|
||||
}
|
||||
|
||||
// given a path and a package context
|
||||
// return module info about where it was found
|
||||
// Resolve a module path to {path, scope, pkg} without compiling.
|
||||
@@ -1282,7 +1331,6 @@ Shop.is_loaded = function is_loaded(path, package_context) {
|
||||
// Create a use function bound to a specific package context
|
||||
function make_use_fn(pkg, force_native) {
|
||||
return function(path) {
|
||||
if (path == 'prosperon/compositor') log.shop('DEBUG make_use_fn: pkg=' + (is_text(pkg) ? pkg : '(non-text)') + ' force_native=' + (force_native ? 'true' : 'false'))
|
||||
var _native = null
|
||||
if (force_native && !native_mode) {
|
||||
_native = function() {
|
||||
@@ -1314,6 +1362,8 @@ function execute_module(info)
|
||||
var inject = null
|
||||
var env = null
|
||||
var pkg = null
|
||||
var _native_load = null
|
||||
var _bc = null
|
||||
|
||||
if (mod_resolve.scope < 900) {
|
||||
// Check if native dylib was resolved (descriptor with _handle and _sym)
|
||||
@@ -1324,9 +1374,27 @@ function execute_module(info)
|
||||
pkg = file_info.package
|
||||
env.use = make_use_fn(pkg, true)
|
||||
env = stone(env)
|
||||
used = os.native_module_load_named(
|
||||
mod_resolve.symbol._handle, mod_resolve.symbol._sym, env)
|
||||
log.shop('loaded ' + info.cache_key + ' [native]')
|
||||
_native_load = function() {
|
||||
used = os.native_module_load_named(
|
||||
mod_resolve.symbol._handle, mod_resolve.symbol._sym, env)
|
||||
log.shop('loaded ' + info.cache_key + ' [native]')
|
||||
} disruption {
|
||||
// Native load failed — fall back to bytecode
|
||||
log.shop('native load failed for ' + info.cache_key + ' (sym=' + text(mod_resolve.symbol._sym || '') + '), falling back to bytecode')
|
||||
_bc = resolve_mod_fn_bytecode(mod_resolve.path, file_info.package)
|
||||
if (_bc) {
|
||||
// Build a fresh env for bytecode (env is stoned, can't modify)
|
||||
env = inject_env(inject)
|
||||
env.use = make_use_fn(pkg)
|
||||
env = stone(env)
|
||||
used = mach_load(_bc, env)
|
||||
log.shop('loaded ' + info.cache_key + ' [bytecode fallback]')
|
||||
} else {
|
||||
log.error('native load failed and bytecode fallback also failed for ' + info.cache_key)
|
||||
disrupt
|
||||
}
|
||||
}
|
||||
_native_load()
|
||||
} else {
|
||||
// Build env with runtime fns, capabilities, and use function
|
||||
file_info = Shop.file_info(mod_resolve.path)
|
||||
@@ -1347,7 +1415,7 @@ function execute_module(info)
|
||||
log.shop(`Module could not be found (c_resolve scope=${info.c_resolve.scope}, mod_resolve scope=${info.mod_resolve.scope}, cache_key=${info.cache_key})`); disrupt
|
||||
}
|
||||
|
||||
if (!used) { log.error(`Module ${info} returned null`); disrupt }
|
||||
if (!used) { log.error('Module ' + text(info.cache_key || info) + ' returned null'); disrupt }
|
||||
|
||||
return used
|
||||
}
|
||||
@@ -1378,11 +1446,6 @@ Shop.use = function use(path, _pkg_ctx) {
|
||||
log.error("use() expects a text module path, but received a non-text value")
|
||||
disrupt
|
||||
}
|
||||
if (path == 'prosperon/compositor') {
|
||||
if (is_text(_pkg_ctx)) log.shop('DEBUG use(): _pkg_ctx=' + _pkg_ctx)
|
||||
else if (_pkg_ctx == null) log.shop('DEBUG use(): _pkg_ctx=NULL')
|
||||
else log.shop('DEBUG use(): _pkg_ctx is non-text non-null')
|
||||
}
|
||||
var package_context = is_core_dir(_pkg_ctx) ? 'core' : safe_canonicalize(_pkg_ctx)
|
||||
// Check for embedded module (static builds)
|
||||
var embed_key = 'embedded:' + path
|
||||
@@ -2288,7 +2351,7 @@ Shop.use_native = function(path, package_context) {
|
||||
if (!starts_with(path, '/') && !fd.is_file(path)) {
|
||||
lookup = ends_with(path, '.cm') ? path : path + '.cm'
|
||||
locator = resolve_locator(lookup, package_context)
|
||||
if (!locator) { print('Module not found: ' + path); disrupt }
|
||||
if (!locator) { log.error('use_native: module not found: ' + path + ' (package: ' + text(package_context || '') + ')'); disrupt }
|
||||
src_path = locator.path
|
||||
} else if (!starts_with(path, '/')) {
|
||||
src_path = fd.realpath(path)
|
||||
@@ -2304,7 +2367,7 @@ Shop.use_native = function(path, package_context) {
|
||||
|
||||
var sym_name = null
|
||||
if (pkg) {
|
||||
pkg_dir = get_packages_dir() + '/' + safe_package_path(pkg)
|
||||
pkg_dir = get_packages_dir() + '/' + fd.safe_package_path(pkg)
|
||||
if (starts_with(src_path, pkg_dir + '/')) {
|
||||
sym_stem = text(src_path, length(pkg_dir) + 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user