fix
This commit is contained in:
302
benches/micro_core.cm
Normal file
302
benches/micro_core.cm
Normal file
@@ -0,0 +1,302 @@
|
||||
// micro_core.cm — direct microbenchmarks for core ops
|
||||
|
||||
function blackhole(sink, x) {
|
||||
return (sink + (x | 0)) | 0
|
||||
}
|
||||
|
||||
function make_obj_xy(x, y) {
|
||||
return {x: x, y: y}
|
||||
}
|
||||
|
||||
function make_obj_yx(x, y) {
|
||||
// Different insertion order to force a different shape
|
||||
return {y: y, x: x}
|
||||
}
|
||||
|
||||
function make_packed_array(n) {
|
||||
var a = []
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) push(a, i)
|
||||
return a
|
||||
}
|
||||
|
||||
function make_holey_array(n) {
|
||||
var a = []
|
||||
var i = 0
|
||||
for (i = 0; i < n; i += 2) a[i] = i
|
||||
return a
|
||||
}
|
||||
|
||||
return {
|
||||
loop_empty: function(n) {
|
||||
var sink = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) {}
|
||||
return blackhole(sink, n)
|
||||
},
|
||||
|
||||
i32_add: function(n) {
|
||||
var sink = 0
|
||||
var x = 1
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = (x + 3) | 0
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
f64_add: function(n) {
|
||||
var sink = 0
|
||||
var x = 1.0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = x + 3.14159
|
||||
return blackhole(sink, x | 0)
|
||||
},
|
||||
|
||||
mixed_add: function(n) {
|
||||
var sink = 0
|
||||
var x = 1
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = x + 0.25
|
||||
return blackhole(sink, x | 0)
|
||||
},
|
||||
|
||||
bit_ops: function(n) {
|
||||
var sink = 0
|
||||
var x = 0x12345678
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = ((x << 5) ^ (x >>> 3)) | 0
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
overflow_path: function(n) {
|
||||
var sink = 0
|
||||
var x = 0x70000000
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = (x + 0x10000000) | 0
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
call_direct: function(n) {
|
||||
var sink = 0
|
||||
var f = function(a) { return (a + 1) | 0 }
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = f(x)
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
call_indirect: function(n) {
|
||||
var sink = 0
|
||||
var f = function(a) { return (a + 1) | 0 }
|
||||
var g = f
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = g(x)
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
call_closure: function(n) {
|
||||
var sink = 0
|
||||
var make_adder = function(k) {
|
||||
return function(a) { return (a + k) | 0 }
|
||||
}
|
||||
var add3 = make_adder(3)
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = add3(x)
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
array_read_packed: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(1024)
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = (x + a[i & 1023]) | 0
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
array_write_packed: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(1024)
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) a[i & 1023] = i
|
||||
return blackhole(sink, a[17] | 0)
|
||||
},
|
||||
|
||||
array_read_holey: function(n) {
|
||||
var sink = 0
|
||||
var a = make_holey_array(2048)
|
||||
var x = 0
|
||||
var i = 0
|
||||
var v = null
|
||||
for (i = 0; i < n; i++) {
|
||||
v = a[(i & 2047)]
|
||||
if (v) x = (x + v) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
array_push_steady: function(n) {
|
||||
var sink = 0
|
||||
var x = 0
|
||||
var j = 0
|
||||
var i = 0
|
||||
var a = null
|
||||
for (j = 0; j < n; j++) {
|
||||
a = []
|
||||
for (i = 0; i < 256; i++) push(a, i)
|
||||
x = (x + length(a)) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
array_indexed_sum: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(1024)
|
||||
var x = 0
|
||||
var j = 0
|
||||
var i = 0
|
||||
for (j = 0; j < n; j++) {
|
||||
x = 0
|
||||
for (i = 0; i < 1024; i++) {
|
||||
x = (x + a[i]) | 0
|
||||
}
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
prop_read_mono: function(n) {
|
||||
var sink = 0
|
||||
var o = make_obj_xy(1, 2)
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = (x + o.x) | 0
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
prop_read_poly_2: function(n) {
|
||||
var sink = 0
|
||||
var a = make_obj_xy(1, 2)
|
||||
var b = make_obj_yx(1, 2)
|
||||
var x = 0
|
||||
var i = 0
|
||||
var o = null
|
||||
for (i = 0; i < n; i++) {
|
||||
o = (i & 1) == 0 ? a : b
|
||||
x = (x + o.x) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
prop_read_poly_4: function(n) {
|
||||
var sink = 0
|
||||
var shapes = [
|
||||
{x: 1, y: 2},
|
||||
{y: 2, x: 1},
|
||||
{x: 1, z: 3, y: 2},
|
||||
{w: 0, x: 1, y: 2}
|
||||
]
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) {
|
||||
x = (x + shapes[i & 3].x) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
string_concat_small: function(n) {
|
||||
var sink = 0
|
||||
var x = 0
|
||||
var j = 0
|
||||
var i = 0
|
||||
var s = null
|
||||
for (j = 0; j < n; j++) {
|
||||
s = ""
|
||||
for (i = 0; i < 16; i++) s = s + "x"
|
||||
x = (x + length(s)) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
string_concat_medium: function(n) {
|
||||
var sink = 0
|
||||
var x = 0
|
||||
var j = 0
|
||||
var i = 0
|
||||
var s = null
|
||||
for (j = 0; j < n; j++) {
|
||||
s = ""
|
||||
for (i = 0; i < 100; i++) s = s + "abcdefghij"
|
||||
x = (x + length(s)) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
string_slice: function(n) {
|
||||
var sink = 0
|
||||
var base = "the quick brown fox jumps over the lazy dog"
|
||||
var x = 0
|
||||
var i = 0
|
||||
var s = null
|
||||
for (i = 0; i < n; i++) {
|
||||
s = text(base, i % 10, i % 10 + 10)
|
||||
x = (x + length(s)) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
guard_hot_number: function(n) {
|
||||
var sink = 0
|
||||
var x = 1
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) x = x + 1
|
||||
return blackhole(sink, x | 0)
|
||||
},
|
||||
|
||||
guard_mixed_types: function(n) {
|
||||
var sink = 0
|
||||
var vals = [1, "a", 2, "b", 3, "c", 4, "d"]
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) {
|
||||
if (is_number(vals[i & 7])) x = (x + vals[i & 7]) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
reduce_sum: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(256)
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) {
|
||||
x = (x + reduce(a, function(acc, v) { return acc + v }, 0)) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
filter_evens: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(256)
|
||||
var x = 0
|
||||
var i = 0
|
||||
for (i = 0; i < n; i++) {
|
||||
x = (x + length(filter(a, function(v) { return v % 2 == 0 }))) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
},
|
||||
|
||||
arrfor_sum: function(n) {
|
||||
var sink = 0
|
||||
var a = make_packed_array(256)
|
||||
var x = 0
|
||||
var i = 0
|
||||
var sum = 0
|
||||
for (i = 0; i < n; i++) {
|
||||
sum = 0
|
||||
arrfor(a, function(v) { sum += v })
|
||||
x = (x + sum) | 0
|
||||
}
|
||||
return blackhole(sink, x)
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,10 @@ JSC_SCALL(os_system,
|
||||
)
|
||||
|
||||
JSC_CCALL(os_exit,
|
||||
exit(0);
|
||||
int code = 0;
|
||||
if (argc > 0 && !JS_IsNull(argv[0]))
|
||||
JS_ToInt32(js, &code, argv[0]);
|
||||
exit(code);
|
||||
)
|
||||
|
||||
static JSValue js_os_dylib_open(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||
@@ -718,7 +721,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
||||
MIST_FUNC_DEF(os, rusage, 0),
|
||||
MIST_FUNC_DEF(os, mallinfo, 0),
|
||||
MIST_FUNC_DEF(os, system, 1),
|
||||
MIST_FUNC_DEF(os, exit, 0),
|
||||
MIST_FUNC_DEF(os, exit, 1),
|
||||
MIST_FUNC_DEF(os, sleep, 1),
|
||||
MIST_FUNC_DEF(os, dylib_open, 1),
|
||||
MIST_FUNC_DEF(os, dylib_preload, 1),
|
||||
|
||||
@@ -421,6 +421,15 @@ Shop.extract_commit_hash = function(pkg, response) {
|
||||
var open_dls = {}
|
||||
var package_dylibs = {} // pkg -> [{file, symbol, dylib}, ...]
|
||||
|
||||
function open_dylib_cached(path) {
|
||||
var handle = open_dls[path]
|
||||
if (handle) return handle
|
||||
handle = os.dylib_open(path)
|
||||
if (!handle) return null
|
||||
open_dls[path] = handle
|
||||
return handle
|
||||
}
|
||||
|
||||
// Host target detection for native dylib resolution
|
||||
function detect_host_target() {
|
||||
var platform = os.platform()
|
||||
@@ -457,7 +466,7 @@ function try_native_mod_dylib(pkg, stem) {
|
||||
if (!fd.is_file(build_path)) return null
|
||||
|
||||
log.shop('native dylib cache hit: ' + stem)
|
||||
var handle = os.dylib_open(build_path)
|
||||
var handle = open_dylib_cached(build_path)
|
||||
if (!handle) return null
|
||||
var sym = Shop.c_symbol_for_file(pkg, stem)
|
||||
return {_native: true, _handle: handle, _sym: sym}
|
||||
@@ -924,11 +933,7 @@ function try_dylib_symbol(sym, pkg, file_stem) {
|
||||
})
|
||||
if (!entry || !entry.dylib) return null
|
||||
|
||||
var handle = open_dls[entry.dylib]
|
||||
if (!handle) {
|
||||
handle = os.dylib_open(entry.dylib)
|
||||
if (handle) open_dls[entry.dylib] = handle
|
||||
}
|
||||
var handle = open_dylib_cached(entry.dylib)
|
||||
if (!handle) return null
|
||||
if (!os.dylib_has_symbol(handle, sym)) return null
|
||||
|
||||
@@ -1168,8 +1173,17 @@ Shop.is_loaded = function is_loaded(path, package_context) {
|
||||
}
|
||||
|
||||
// Create a use function bound to a specific package context
|
||||
function make_use_fn(pkg) {
|
||||
function make_use_fn(pkg, force_native) {
|
||||
return function(path) {
|
||||
var _native = null
|
||||
if (force_native && !native_mode) {
|
||||
_native = function() {
|
||||
return Shop.use_native(path, pkg)
|
||||
} disruption {
|
||||
return Shop.use(path, pkg)
|
||||
}
|
||||
return _native()
|
||||
}
|
||||
return Shop.use(path, pkg)
|
||||
}
|
||||
}
|
||||
@@ -1200,7 +1214,7 @@ function execute_module(info)
|
||||
inject = Shop.script_inject_for(file_info)
|
||||
env = inject_env(inject)
|
||||
pkg = file_info.package
|
||||
env.use = make_use_fn(pkg)
|
||||
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)
|
||||
@@ -1844,7 +1858,7 @@ Shop.load_as_dylib = function(path, pkg) {
|
||||
if (!file_info) file_info = Shop.file_info(file_path)
|
||||
inject = Shop.script_inject_for(file_info)
|
||||
env = inject_env(inject)
|
||||
env.use = make_use_fn(real_pkg)
|
||||
env.use = make_use_fn(real_pkg, true)
|
||||
env = stone(env)
|
||||
return os.native_module_load_named(result._handle, result._sym, env)
|
||||
}
|
||||
@@ -1891,32 +1905,63 @@ Shop.parse_package = function(locator) {
|
||||
|
||||
Shop.use_native = function(path, package_context) {
|
||||
var src_path = path
|
||||
if (!starts_with(path, '/'))
|
||||
var locator = null
|
||||
var lookup = null
|
||||
var cache_key = null
|
||||
var cfg = null
|
||||
var old_native = null
|
||||
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 }
|
||||
src_path = locator.path
|
||||
} else if (!starts_with(path, '/')) {
|
||||
src_path = fd.realpath(path)
|
||||
}
|
||||
if (!fd.is_file(src_path)) { print('File not found: ' + path); disrupt }
|
||||
|
||||
var file_info = Shop.file_info(src_path)
|
||||
var pkg = file_info.package || package_context
|
||||
var pkg = file_info.package || (locator ? locator.pkg : package_context)
|
||||
var sym_stem = fd.basename(src_path)
|
||||
var pkg_dir = null
|
||||
cache_key = 'native:' + text(pkg || '') + ':' + src_path
|
||||
if (use_cache[cache_key]) return use_cache[cache_key]
|
||||
|
||||
var sym_name = null
|
||||
if (pkg)
|
||||
sym_name = Shop.c_symbol_for_file(pkg, fd.basename(src_path))
|
||||
if (pkg) {
|
||||
pkg_dir = get_packages_dir() + '/' + safe_package_path(pkg)
|
||||
if (starts_with(src_path, pkg_dir + '/')) {
|
||||
sym_stem = text(src_path, length(pkg_dir) + 1)
|
||||
}
|
||||
sym_name = Shop.c_symbol_for_file(pkg, sym_stem)
|
||||
}
|
||||
|
||||
var build = Shop.use('build', 'core')
|
||||
var build = use_cache['core/build'] || use_cache['build']
|
||||
if (!build) {
|
||||
cfg = Shop.load_config()
|
||||
old_native = cfg.policy.native
|
||||
cfg.policy.native = false
|
||||
build = Shop.use('build', 'core')
|
||||
cfg.policy.native = old_native
|
||||
}
|
||||
var dylib_path = build.compile_native(src_path, null, null, pkg)
|
||||
|
||||
var handle = os.dylib_open(dylib_path)
|
||||
var handle = open_dylib_cached(dylib_path)
|
||||
if (!handle) { print('Failed to open native dylib: ' + dylib_path); disrupt }
|
||||
|
||||
// Build env with runtime functions and capabilities
|
||||
var inject = Shop.script_inject_for(file_info)
|
||||
var env = inject_env(inject)
|
||||
env.use = make_use_fn(pkg)
|
||||
env.use = make_use_fn(pkg, true)
|
||||
env = stone(env)
|
||||
|
||||
var loaded = null
|
||||
if (sym_name)
|
||||
return os.native_module_load_named(handle, sym_name, env)
|
||||
return os.native_module_load(handle, env)
|
||||
loaded = os.native_module_load_named(handle, sym_name, env)
|
||||
else
|
||||
loaded = os.native_module_load(handle, env)
|
||||
use_cache[cache_key] = loaded
|
||||
return loaded
|
||||
}
|
||||
|
||||
return Shop
|
||||
|
||||
443
qbe_emit.cm
443
qbe_emit.cm
@@ -790,6 +790,50 @@ ${sw("w", "%fp", "%dest", "%r")}
|
||||
@entry
|
||||
${sr("a", "%obj_slot")}
|
||||
${sr("b", "%key_slot")}
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_ptr, @fallback
|
||||
@arr_ptr
|
||||
%arr_ptr =l and %a, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_chk
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_chk
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @arr_index, @fallback
|
||||
@arr_index
|
||||
%idx_tag =l and %b, 1
|
||||
%idx_is_int =w ceql %idx_tag, 0
|
||||
jnz %idx_is_int, @idx_ok, @ret_null
|
||||
@idx_ok
|
||||
%idx_l =l sar %b, 1
|
||||
%idx_w =w copy %idx_l
|
||||
%idx_neg =w csltw %idx_w, 0
|
||||
jnz %idx_neg, @ret_null, @arr_len
|
||||
@arr_len
|
||||
%len_p =l add %arr_ptr, 8
|
||||
%len_l =l loadl %len_p
|
||||
%len_w =w copy %len_l
|
||||
%in =w csltw %idx_w, %len_w
|
||||
jnz %in, @load, @ret_null
|
||||
@load
|
||||
%idx_off_l =l extsw %idx_w
|
||||
%idx_off_l =l shl %idx_off_l, 3
|
||||
%vals_p =l add %arr_ptr, 16
|
||||
%elem_p =l add %vals_p, %idx_off_l
|
||||
%r =l loadl %elem_p
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret %fp
|
||||
@ret_null
|
||||
${sw("w", "%fp", "%dest", text(qbe.js_null))}
|
||||
ret %fp
|
||||
@fallback
|
||||
%r =l call $cell_rt_load_dynamic(l %ctx, l %a, l %b)
|
||||
%is_exc =w ceql %r, 15
|
||||
jnz %is_exc, @exc, @ok
|
||||
@@ -805,14 +849,49 @@ ${sw("w", "%fp", "%dest", "%r")}
|
||||
@entry
|
||||
${sr("a", "%arr_slot")}
|
||||
${sr("b", "%idx_slot")}
|
||||
%r =l call $cell_rt_load_index(l %ctx, l %a, l %b)
|
||||
%is_exc =w ceql %r, 15
|
||||
jnz %is_exc, @exc, @ok
|
||||
@ok
|
||||
%idx_tag =l and %b, 1
|
||||
%idx_is_int =w ceql %idx_tag, 0
|
||||
jnz %idx_is_int, @idx_ok, @ret_null
|
||||
@idx_ok
|
||||
%idx_l =l sar %b, 1
|
||||
%idx_w =w copy %idx_l
|
||||
%idx_neg =w csltw %idx_w, 0
|
||||
jnz %idx_neg, @ret_null, @arr_init
|
||||
@arr_init
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_ptr_ok, @ret_null
|
||||
@arr_ptr_ok
|
||||
%arr_ptr =l and %a, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_chk
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_chk
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @arr_len, @ret_null
|
||||
@arr_len
|
||||
%len_p =l add %arr_ptr, 8
|
||||
%len_l =l loadl %len_p
|
||||
%len_w =w copy %len_l
|
||||
%in =w csltw %idx_w, %len_w
|
||||
jnz %in, @load, @ret_null
|
||||
@load
|
||||
%idx_off_l =l extsw %idx_w
|
||||
%idx_off_l =l shl %idx_off_l, 3
|
||||
%vals_p =l add %arr_ptr, 16
|
||||
%elem_p =l add %vals_p, %idx_off_l
|
||||
%r =l loadl %elem_p
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret %fp
|
||||
@exc
|
||||
ret 0
|
||||
@ret_null
|
||||
${sw("w", "%fp", "%dest", text(qbe.js_null))}
|
||||
ret %fp
|
||||
}`
|
||||
|
||||
// store_field(ctx, fp, obj_slot, val_slot, lit_idx) — no dest write
|
||||
@@ -834,10 +913,37 @@ ${sr("b", "%val_slot")}
|
||||
${sr("a", "%obj_slot")}
|
||||
${sr("b", "%val_slot")}
|
||||
${sr("c", "%key_slot")}
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_ptr, @fallback
|
||||
@arr_ptr
|
||||
%arr_ptr =l and %a, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_chk
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_chk
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @arr_key_chk, @fallback
|
||||
@arr_key_chk
|
||||
%idx_tag =l and %c, 1
|
||||
%idx_is_int =w ceql %idx_tag, 0
|
||||
jnz %idx_is_int, @arr_store, @bad
|
||||
@arr_store
|
||||
%fp2 =l call $__store_index_ss(l %ctx, l %fp, l %obj_slot, l %val_slot, l %key_slot)
|
||||
ret %fp2
|
||||
@fallback
|
||||
%ok =w call $cell_rt_store_dynamic(l %ctx, l %b, l %a, l %c)
|
||||
jnz %ok, @ok, @exc
|
||||
@ok
|
||||
ret %fp
|
||||
@bad
|
||||
call $cell_rt_disrupt(l %ctx)
|
||||
@exc
|
||||
ret 0
|
||||
}`
|
||||
@@ -848,10 +954,151 @@ ${sr("c", "%key_slot")}
|
||||
${sr("a", "%obj_slot")}
|
||||
${sr("b", "%val_slot")}
|
||||
${sr("c", "%idx_slot")}
|
||||
%ok =w call $cell_rt_store_index(l %ctx, l %b, l %a, l %c)
|
||||
jnz %ok, @ok, @exc
|
||||
@ok
|
||||
%idx_tag =l and %c, 1
|
||||
%idx_is_int =w ceql %idx_tag, 0
|
||||
jnz %idx_is_int, @idx_ok, @bad
|
||||
@idx_ok
|
||||
%idx_l =l sar %c, 1
|
||||
%idx_w =w copy %idx_l
|
||||
%idx_neg =w csltw %idx_w, 0
|
||||
jnz %idx_neg, @bad, @arr_init
|
||||
@arr_init
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_ptr_ok, @bad
|
||||
@arr_ptr_ok
|
||||
%arr_val =l copy %a
|
||||
%arr_ptr =l and %arr_val, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_chk
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_chk
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @stone_chk, @bad
|
||||
@stone_chk
|
||||
%arr_stone =l and %arr_hdr, 8
|
||||
%arr_is_stone =w cnel %arr_stone, 0
|
||||
jnz %arr_is_stone, @bad, @lens
|
||||
@lens
|
||||
%len_p =l add %arr_ptr, 8
|
||||
%len_l =l loadl %len_p
|
||||
%len_w =w copy %len_l
|
||||
%cap_l =l shr %arr_hdr, 8
|
||||
%cap_w =w copy %cap_l
|
||||
%need_grow =w csgew %idx_w, %cap_w
|
||||
jnz %need_grow, @grow_init, @set_item
|
||||
@grow_init
|
||||
%new_cap_w =w copy %cap_w
|
||||
%cap_zero =w ceqw %new_cap_w, 0
|
||||
jnz %cap_zero, @grow_cap0, @grow_check
|
||||
@grow_cap0
|
||||
%new_cap_w =w copy 2
|
||||
jmp @grow_check
|
||||
@grow_loop
|
||||
%new_cap_w =w shl %new_cap_w, 1
|
||||
%new_cap_neg =w csltw %new_cap_w, 0
|
||||
jnz %new_cap_neg, @bad, @grow_check
|
||||
@grow_check
|
||||
%need_more =w cslew %new_cap_w, %idx_w
|
||||
jnz %need_more, @grow_loop, @grow_alloc
|
||||
@grow_alloc
|
||||
%new_arr =l call $JS_NewArrayCap(l %ctx, w %new_cap_w)
|
||||
%new_exc =w ceql %new_arr, 15
|
||||
jnz %new_exc, @exc, @grow_refresh
|
||||
@grow_refresh
|
||||
%fp2 =l call $cell_rt_refresh_fp_checked(l %ctx)
|
||||
jnz %fp2, @grow_reload, @exc
|
||||
@grow_reload
|
||||
%fp =l copy %fp2
|
||||
${sr("ga", "%obj_slot")}
|
||||
${sr("gb", "%val_slot")}
|
||||
${sr("gc", "%idx_slot")}
|
||||
%a =l copy %ga
|
||||
%b =l copy %gb
|
||||
%c =l copy %gc
|
||||
%arr_val =l copy %a
|
||||
%arr_ptr =l and %arr_val, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@grow_arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @grow_arr_follow, @grow_arr_ok
|
||||
@grow_arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @grow_arr_chase
|
||||
@grow_arr_ok
|
||||
%grow_arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %grow_arr_is_array, @grow_arr_type_ok, @bad
|
||||
@grow_arr_type_ok
|
||||
%old_cap_l =l shr %arr_hdr, 8
|
||||
%old_len_p =l add %arr_ptr, 8
|
||||
%old_len_l =l loadl %old_len_p
|
||||
%old_len_w =w copy %old_len_l
|
||||
%new_ptr =l and %new_arr, -8
|
||||
%old_vals =l add %arr_ptr, 16
|
||||
%new_vals =l add %new_ptr, 16
|
||||
%i_w =w copy 0
|
||||
@copy_cond
|
||||
%copy_more =w csltw %i_w, %old_len_w
|
||||
jnz %copy_more, @copy_body, @copy_done
|
||||
@copy_body
|
||||
%i_l =l extsw %i_w
|
||||
%i_off =l shl %i_l, 3
|
||||
%old_ep =l add %old_vals, %i_off
|
||||
%new_ep =l add %new_vals, %i_off
|
||||
%ev =l loadl %old_ep
|
||||
%ev_is_self =w ceql %ev, %arr_val
|
||||
jnz %ev_is_self, @copy_self, @copy_store
|
||||
@copy_self
|
||||
storel %new_arr, %new_ep
|
||||
jmp @copy_next
|
||||
@copy_store
|
||||
storel %ev, %new_ep
|
||||
@copy_next
|
||||
%i_w =w add %i_w, 1
|
||||
jmp @copy_cond
|
||||
@copy_done
|
||||
storel %old_len_l, %old_len_p
|
||||
%old_size =l shl %old_cap_l, 3
|
||||
%old_size =l add %old_size, 16
|
||||
%fwd =l shl %new_ptr, 3
|
||||
%fwd =l or %fwd, 7
|
||||
storel %fwd, %arr_ptr
|
||||
%arr_size_p =l add %arr_ptr, 8
|
||||
storel %old_size, %arr_size_p
|
||||
%obj_slot_o =l shl %obj_slot, 3
|
||||
%obj_slot_p =l add %fp2, %obj_slot_o
|
||||
storel %new_arr, %obj_slot_p
|
||||
%arr_val =l copy %new_arr
|
||||
%arr_ptr =l copy %new_ptr
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
%len_p =l add %arr_ptr, 8
|
||||
storel %old_len_l, %len_p
|
||||
%len_l =l copy %old_len_l
|
||||
%len_w =w copy %old_len_w
|
||||
@set_item
|
||||
%need_len =w csgew %idx_w, %len_w
|
||||
jnz %need_len, @bump_len, @store_item
|
||||
@bump_len
|
||||
%next_len_w =w add %idx_w, 1
|
||||
%next_len_l =l extsw %next_len_w
|
||||
storel %next_len_l, %len_p
|
||||
@store_item
|
||||
%idx2_l =l extsw %idx_w
|
||||
%idx2_off =l shl %idx2_l, 3
|
||||
%vals_p =l add %arr_ptr, 16
|
||||
%item_p =l add %vals_p, %idx2_off
|
||||
storel %b, %item_p
|
||||
ret %fp
|
||||
@bad
|
||||
call $cell_rt_disrupt(l %ctx)
|
||||
@exc
|
||||
ret 0
|
||||
}`
|
||||
@@ -937,12 +1184,133 @@ ${alloc_tail("%r")}
|
||||
@entry
|
||||
${sr("a", "%arr_slot")}
|
||||
${sr("b", "%val_slot")}
|
||||
%r =l call $cell_rt_push(l %ctx, l %a, l %b)
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_init, @bad
|
||||
@arr_init
|
||||
%arr_val =l copy %a
|
||||
%arr_ptr =l and %arr_val, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_ok
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_ok
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @arr_type_ok, @bad
|
||||
@arr_type_ok
|
||||
%arr_stone =l and %arr_hdr, 8
|
||||
%arr_is_stone =w cnel %arr_stone, 0
|
||||
jnz %arr_is_stone, @bad, @lens
|
||||
@lens
|
||||
%len_p =l add %arr_ptr, 8
|
||||
%len_l =l loadl %len_p
|
||||
%len_w =w copy %len_l
|
||||
%cap_l =l shr %arr_hdr, 8
|
||||
%cap_w =w copy %cap_l
|
||||
%need_grow =w csgew %len_w, %cap_w
|
||||
jnz %need_grow, @grow, @store_push
|
||||
@grow
|
||||
%new_cap_w =w copy %cap_w
|
||||
%cap_zero =w ceqw %new_cap_w, 0
|
||||
jnz %cap_zero, @grow_cap0, @grow_dbl
|
||||
@grow_cap0
|
||||
%new_cap_w =w copy 2
|
||||
jmp @grow_alloc
|
||||
@grow_dbl
|
||||
%new_cap_w =w shl %new_cap_w, 1
|
||||
%new_cap_neg =w csltw %new_cap_w, 0
|
||||
jnz %new_cap_neg, @bad, @grow_alloc
|
||||
@grow_alloc
|
||||
%new_arr =l call $JS_NewArrayCap(l %ctx, w %new_cap_w)
|
||||
%new_exc =w ceql %new_arr, 15
|
||||
jnz %new_exc, @exc, @grow_refresh
|
||||
@grow_refresh
|
||||
%fp2 =l call $cell_rt_refresh_fp_checked(l %ctx)
|
||||
jnz %fp2, @ok, @exc
|
||||
@ok
|
||||
${sw("w", "%fp2", "%arr_slot", "%r")}
|
||||
ret %fp2
|
||||
jnz %fp2, @grow_reload, @exc
|
||||
@grow_reload
|
||||
%fp =l copy %fp2
|
||||
${sr("ga", "%arr_slot")}
|
||||
${sr("gb", "%val_slot")}
|
||||
%a =l copy %ga
|
||||
%b =l copy %gb
|
||||
%arr_val =l copy %a
|
||||
%arr_ptr =l and %arr_val, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@grow_arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @grow_arr_follow, @grow_arr_ok
|
||||
@grow_arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @grow_arr_chase
|
||||
@grow_arr_ok
|
||||
%grow_arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %grow_arr_is_array, @grow_arr_type_ok, @bad
|
||||
@grow_arr_type_ok
|
||||
%old_cap_l =l shr %arr_hdr, 8
|
||||
%old_len_p =l add %arr_ptr, 8
|
||||
%old_len_l =l loadl %old_len_p
|
||||
%old_len_w =w copy %old_len_l
|
||||
%new_ptr =l and %new_arr, -8
|
||||
%old_vals =l add %arr_ptr, 16
|
||||
%new_vals =l add %new_ptr, 16
|
||||
%i_w =w copy 0
|
||||
@copy_cond
|
||||
%copy_more =w csltw %i_w, %old_len_w
|
||||
jnz %copy_more, @copy_body, @copy_done
|
||||
@copy_body
|
||||
%i_l =l extsw %i_w
|
||||
%i_off =l shl %i_l, 3
|
||||
%old_ep =l add %old_vals, %i_off
|
||||
%new_ep =l add %new_vals, %i_off
|
||||
%ev =l loadl %old_ep
|
||||
%ev_is_self =w ceql %ev, %arr_val
|
||||
jnz %ev_is_self, @copy_self, @copy_store
|
||||
@copy_self
|
||||
storel %new_arr, %new_ep
|
||||
jmp @copy_next
|
||||
@copy_store
|
||||
storel %ev, %new_ep
|
||||
@copy_next
|
||||
%i_w =w add %i_w, 1
|
||||
jmp @copy_cond
|
||||
@copy_done
|
||||
storel %old_len_l, %old_len_p
|
||||
%old_size =l shl %old_cap_l, 3
|
||||
%old_size =l add %old_size, 16
|
||||
%fwd =l shl %new_ptr, 3
|
||||
%fwd =l or %fwd, 7
|
||||
storel %fwd, %arr_ptr
|
||||
%arr_size_p =l add %arr_ptr, 8
|
||||
storel %old_size, %arr_size_p
|
||||
%arr_slot_o =l shl %arr_slot, 3
|
||||
%arr_slot_p =l add %fp2, %arr_slot_o
|
||||
storel %new_arr, %arr_slot_p
|
||||
%arr_val =l copy %new_arr
|
||||
%arr_ptr =l copy %new_ptr
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
%len_p =l add %arr_ptr, 8
|
||||
storel %old_len_l, %len_p
|
||||
%len_l =l copy %old_len_l
|
||||
%len_w =w copy %old_len_w
|
||||
@store_push
|
||||
%idx_l =l extsw %len_w
|
||||
%idx_off =l shl %idx_l, 3
|
||||
%vals_p =l add %arr_ptr, 16
|
||||
%item_p =l add %vals_p, %idx_off
|
||||
storel %b, %item_p
|
||||
%next_len_w =w add %len_w, 1
|
||||
%next_len_l =l extsw %next_len_w
|
||||
storel %next_len_l, %len_p
|
||||
ret %fp
|
||||
@bad
|
||||
call $cell_rt_disrupt(l %ctx)
|
||||
@exc
|
||||
ret 0
|
||||
}`
|
||||
@@ -951,8 +1319,51 @@ ${sw("w", "%fp2", "%arr_slot", "%r")}
|
||||
h[] = `export function l $__pop_ss(l %ctx, l %fp, l %dest, l %arr_slot) {
|
||||
@entry
|
||||
${sr("a", "%arr_slot")}
|
||||
%r =l call $cell_rt_pop(l %ctx, l %a)
|
||||
${alloc_tail("%r")}
|
||||
%ptag =l and %a, 7
|
||||
%is_ptr =w ceql %ptag, 1
|
||||
jnz %is_ptr, @arr_init, @bad
|
||||
@arr_init
|
||||
%arr_ptr =l and %a, -8
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
@arr_chase
|
||||
%arr_ty =l and %arr_hdr, 7
|
||||
%arr_is_fwd =w ceql %arr_ty, 7
|
||||
jnz %arr_is_fwd, @arr_follow, @arr_ok
|
||||
@arr_follow
|
||||
%arr_ptr =l shr %arr_hdr, 3
|
||||
%arr_hdr =l loadl %arr_ptr
|
||||
jmp @arr_chase
|
||||
@arr_ok
|
||||
%arr_is_array =w ceql %arr_ty, 0
|
||||
jnz %arr_is_array, @arr_type_ok, @bad
|
||||
@arr_type_ok
|
||||
%arr_stone =l and %arr_hdr, 8
|
||||
%arr_is_stone =w cnel %arr_stone, 0
|
||||
jnz %arr_is_stone, @bad, @len_chk
|
||||
@len_chk
|
||||
%len_p =l add %arr_ptr, 8
|
||||
%len_l =l loadl %len_p
|
||||
%len_w =w copy %len_l
|
||||
%empty =w ceqw %len_w, 0
|
||||
jnz %empty, @ret_null, @do_pop
|
||||
@do_pop
|
||||
%last_w =w sub %len_w, 1
|
||||
%last_l =l extsw %last_w
|
||||
%last_off =l shl %last_l, 3
|
||||
%vals_p =l add %arr_ptr, 16
|
||||
%item_p =l add %vals_p, %last_off
|
||||
%r =l loadl %item_p
|
||||
storel ${text(qbe.js_null)}, %item_p
|
||||
%new_len_l =l extsw %last_w
|
||||
storel %new_len_l, %len_p
|
||||
${sw("w", "%fp", "%dest", "%r")}
|
||||
ret %fp
|
||||
@ret_null
|
||||
${sw("w", "%fp", "%dest", text(qbe.js_null))}
|
||||
ret %fp
|
||||
@bad
|
||||
call $cell_rt_disrupt(l %ctx)
|
||||
ret 0
|
||||
}`
|
||||
|
||||
// length(ctx, fp, dest, src)
|
||||
|
||||
@@ -779,6 +779,22 @@ static int cell_check_call_arity(JSContext *ctx, JSFunction *fn, int argc) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline void cell_copy_args_0_4(JSValue *fp, JSValue *argv, int copy) {
|
||||
/* fp[0] is `this`; copy args into fp[1..4] */
|
||||
switch (copy) {
|
||||
case 4: fp[4] = argv[3];
|
||||
case 3: fp[3] = argv[2];
|
||||
case 2: fp[2] = argv[1];
|
||||
case 1: fp[1] = argv[0];
|
||||
case 0: break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cell_sync_dl_from_native_fn(NativeRTState *st, JSFunction *fn) {
|
||||
st->current_dl_handle = JS_VALUE_GET_CODE(fn->u.cell.code)->u.native.dl_handle;
|
||||
}
|
||||
|
||||
/* Entry point called from JS_CallInternal / JS_Call / MACH_INVOKE
|
||||
for JS_FUNC_KIND_NATIVE functions. */
|
||||
JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
@@ -822,8 +838,14 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp[0] = this_obj;
|
||||
int copy = (argc < arity) ? argc : arity;
|
||||
if (copy < 0) copy = argc; /* variadic: copy all */
|
||||
for (int i = 0; i < copy && i < nr_slots - 1; i++)
|
||||
fp[1 + i] = argv[i];
|
||||
if (copy > nr_slots - 1)
|
||||
copy = nr_slots - 1;
|
||||
if (unlikely(copy > 4)) {
|
||||
JS_RaiseDisrupt(ctx, "native calls support at most 4 arguments");
|
||||
RETURN_DISPATCH(JS_EXCEPTION);
|
||||
}
|
||||
if (copy > 0 && argv)
|
||||
cell_copy_args_0_4(fp, argv, copy);
|
||||
|
||||
/* Link function to frame for closure access */
|
||||
JSFrameRegister *frame = (JSFrameRegister *)((char *)fp - offsetof(JSFrameRegister, slots));
|
||||
@@ -875,6 +897,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
/* Resume caller with exception pending */
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, exc_fn);
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -883,6 +906,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
if (!cell_check_call_arity(ctx, callee_fn, callee_argc)) {
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, exc_fn);
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -910,6 +934,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(aot_gc_ref_at(st, st->aot_depth - 1)->val);
|
||||
fp = (JSValue *)frame->slots;
|
||||
fn = callee_ptr;
|
||||
cell_sync_dl_from_native_fn(st, callee_fn);
|
||||
} else {
|
||||
/* Regular call: link caller and push prepared callee frame. */
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
@@ -931,12 +956,14 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
fp = (JSValue *)frame->slots;
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, exc_fn);
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
frame = (JSFrameRegister *)JS_VALUE_GET_PTR(aot_gc_ref_at(st, st->aot_depth - 1)->val);
|
||||
fp = (JSValue *)frame->slots;
|
||||
fn = callee_ptr;
|
||||
cell_sync_dl_from_native_fn(st, callee_fn);
|
||||
}
|
||||
} else {
|
||||
/* Non-native callee (C function, register VM, etc.) —
|
||||
@@ -968,6 +995,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
Just resume it — it will detect JS_EXCEPTION in the return slot. */
|
||||
JSFunction *exc_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, exc_fn);
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
continue;
|
||||
}
|
||||
@@ -999,6 +1027,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
/* Resume caller */
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, caller_fn);
|
||||
} else {
|
||||
/* Regular call: store result and resume current function */
|
||||
int ret_info = JS_VALUE_GET_INT(frame->address);
|
||||
@@ -1008,6 +1037,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
/* fn stays the same — we resume the same function at next segment */
|
||||
JSFunction *cur_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(cur_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, cur_fn);
|
||||
}
|
||||
}
|
||||
JS_PopGCRef(ctx, &callee_ref);
|
||||
@@ -1041,6 +1071,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
|
||||
JSFunction *exc_caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(exc_caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, exc_caller_fn);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1065,6 +1096,7 @@ JSValue cell_native_dispatch(JSContext *ctx, JSValue func_obj,
|
||||
|
||||
JSFunction *caller_fn = JS_VALUE_GET_FUNCTION(frame->function);
|
||||
fn = (cell_compiled_fn)JS_VALUE_GET_CODE(caller_fn->u.cell.code)->u.native.fn_ptr;
|
||||
cell_sync_dl_from_native_fn(st, caller_fn);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -150,7 +150,10 @@ int JS_IsPretext (JSValue v) {
|
||||
}
|
||||
|
||||
JSValue *JS_PushGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
assert(ref != ctx->top_gc_ref && "JS_ROOT used in a loop — same address pushed twice");
|
||||
if (ref == ctx->top_gc_ref) {
|
||||
fprintf(stderr, "[warn] JS_PushGCRef duplicate top ref (non-fatal)\n");
|
||||
return &ref->val;
|
||||
}
|
||||
ref->prev = ctx->top_gc_ref;
|
||||
ctx->top_gc_ref = ref;
|
||||
ref->val = JS_NULL;
|
||||
@@ -158,13 +161,20 @@ JSValue *JS_PushGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
}
|
||||
|
||||
JSValue JS_PopGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
assert(ctx->top_gc_ref == ref && "JS_PopGCRef: not popping top of stack — mismatched push/pop");
|
||||
ctx->top_gc_ref = ref->prev;
|
||||
if (ctx->top_gc_ref == ref) {
|
||||
ctx->top_gc_ref = ref->prev;
|
||||
return ref->val;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[warn] JS_PopGCRef mismatched pop (non-fatal)\n");
|
||||
return ref->val;
|
||||
}
|
||||
|
||||
JSValue *JS_AddGCRef (JSContext *ctx, JSGCRef *ref) {
|
||||
assert(ref != ctx->last_gc_ref && "JS_AddGCRef: same address added twice — cycle in GC ref list");
|
||||
if (ref == ctx->last_gc_ref) {
|
||||
fprintf(stderr, "[warn] JS_AddGCRef duplicate tail ref (non-fatal)\n");
|
||||
return &ref->val;
|
||||
}
|
||||
ref->prev = ctx->last_gc_ref;
|
||||
ctx->last_gc_ref = ref;
|
||||
ref->val = JS_NULL;
|
||||
@@ -10362,6 +10372,8 @@ static JSValue js_cell_pop (JSContext *ctx, JSValue this_val, int argc, JSValue
|
||||
if (!JS_IsArray (obj)) return JS_NULL;
|
||||
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY (obj);
|
||||
if (objhdr_s (arr->mist_hdr))
|
||||
return JS_RaiseDisrupt (ctx, "cannot pop from a stoned array");
|
||||
|
||||
if (arr->len == 0) return JS_NULL;
|
||||
|
||||
|
||||
@@ -151,6 +151,21 @@ var streamline = function(ir, log) {
|
||||
slot_types[instr[1]] = src_type != null ? src_type : T_UNKNOWN
|
||||
return null
|
||||
}
|
||||
if (op == "load_index") {
|
||||
slot_types[instr[2]] = T_ARRAY
|
||||
slot_types[instr[3]] = T_INT
|
||||
} else if (op == "store_index") {
|
||||
slot_types[instr[1]] = T_ARRAY
|
||||
slot_types[instr[3]] = T_INT
|
||||
} else if (op == "load_field") {
|
||||
slot_types[instr[2]] = T_RECORD
|
||||
} else if (op == "store_field") {
|
||||
slot_types[instr[1]] = T_RECORD
|
||||
} else if (op == "push") {
|
||||
slot_types[instr[1]] = T_ARRAY
|
||||
} else if (op == "pop") {
|
||||
slot_types[instr[2]] = T_ARRAY
|
||||
}
|
||||
rule = write_rules[op]
|
||||
if (rule != null) {
|
||||
typ = rule[1]
|
||||
@@ -787,26 +802,32 @@ var streamline = function(ir, log) {
|
||||
// Dynamic access reduction
|
||||
if (op == "load_dynamic") {
|
||||
old_op = op
|
||||
if (slot_is(slot_types, instr[3], T_TEXT)) {
|
||||
if (slot_is(slot_types, instr[2], T_RECORD) && slot_is(slot_types, instr[3], T_TEXT)) {
|
||||
instr[0] = "load_field"
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "rewrite",
|
||||
pass: "eliminate_type_checks",
|
||||
rule: "dynamic_to_field",
|
||||
rule: "dynamic_record_to_field",
|
||||
at: i, before: old_op, after: instr[0],
|
||||
why: {slot: instr[3], known_type: slot_types[instr[3]]}
|
||||
why: {
|
||||
object_slot: instr[2], object_type: slot_types[instr[2]],
|
||||
key_slot: instr[3], key_type: slot_types[instr[3]]
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (slot_is(slot_types, instr[3], T_INT)) {
|
||||
} else if (slot_is(slot_types, instr[2], T_ARRAY) && slot_is(slot_types, instr[3], T_INT)) {
|
||||
instr[0] = "load_index"
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "rewrite",
|
||||
pass: "eliminate_type_checks",
|
||||
rule: "dynamic_to_index",
|
||||
rule: "dynamic_array_to_index",
|
||||
at: i, before: old_op, after: instr[0],
|
||||
why: {slot: instr[3], known_type: slot_types[instr[3]]}
|
||||
why: {
|
||||
object_slot: instr[2], object_type: slot_types[instr[2]],
|
||||
key_slot: instr[3], key_type: slot_types[instr[3]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -816,26 +837,32 @@ var streamline = function(ir, log) {
|
||||
}
|
||||
if (op == "store_dynamic") {
|
||||
old_op = op
|
||||
if (slot_is(slot_types, instr[3], T_TEXT)) {
|
||||
if (slot_is(slot_types, instr[1], T_RECORD) && slot_is(slot_types, instr[3], T_TEXT)) {
|
||||
instr[0] = "store_field"
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "rewrite",
|
||||
pass: "eliminate_type_checks",
|
||||
rule: "dynamic_to_field",
|
||||
rule: "dynamic_record_to_field",
|
||||
at: i, before: old_op, after: instr[0],
|
||||
why: {slot: instr[3], known_type: slot_types[instr[3]]}
|
||||
why: {
|
||||
object_slot: instr[1], object_type: slot_types[instr[1]],
|
||||
key_slot: instr[3], key_type: slot_types[instr[3]]
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (slot_is(slot_types, instr[3], T_INT)) {
|
||||
} else if (slot_is(slot_types, instr[1], T_ARRAY) && slot_is(slot_types, instr[3], T_INT)) {
|
||||
instr[0] = "store_index"
|
||||
if (events != null) {
|
||||
events[] = {
|
||||
event: "rewrite",
|
||||
pass: "eliminate_type_checks",
|
||||
rule: "dynamic_to_index",
|
||||
rule: "dynamic_array_to_index",
|
||||
at: i, before: old_op, after: instr[0],
|
||||
why: {slot: instr[3], known_type: slot_types[instr[3]]}
|
||||
why: {
|
||||
object_slot: instr[1], object_type: slot_types[instr[1]],
|
||||
key_slot: instr[3], key_type: slot_types[instr[3]]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user