fixed function arity
This commit is contained in:
49
build.cm
49
build.cm
@@ -121,11 +121,11 @@ Build.compile_file = function(pkg, file, target, buildtype = 'release') {
|
||||
|
||||
// Add buildtype-specific flags
|
||||
if (buildtype == 'release') {
|
||||
push(cmd_parts, '-O3', '-DNDEBUG')
|
||||
cmd_parts = array(cmd_parts, ['-O3', '-DNDEBUG'])
|
||||
} else if (buildtype == 'debug') {
|
||||
push(cmd_parts, '-O2', '-g')
|
||||
cmd_parts = array(cmd_parts, ['-O2', '-g'])
|
||||
} else if (buildtype == 'minsize') {
|
||||
push(cmd_parts, '-Os', '-DNDEBUG')
|
||||
cmd_parts = array(cmd_parts, ['-Os', '-DNDEBUG'])
|
||||
}
|
||||
|
||||
push(cmd_parts, '-DCELL_USE_NAME=' + sym_name)
|
||||
@@ -278,23 +278,20 @@ Build.build_dynamic = function(pkg, target = Build.detect_host_target(), buildty
|
||||
|
||||
// Platform-specific flags for undefined symbols (resolved at dlopen) and size optimization
|
||||
if (tc.system == 'darwin') {
|
||||
// Allow undefined symbols - they will be resolved when dlopen'd into the main executable
|
||||
push(cmd_parts, '-undefined', 'dynamic_lookup')
|
||||
// Dead-strip unused code
|
||||
push(cmd_parts, '-Wl,-dead_strip')
|
||||
// Set install_name to stable path so runtime finds it correctly
|
||||
push(cmd_parts, '-Wl,-install_name,' + stable_path)
|
||||
// rpath for .cell/local libraries
|
||||
push(cmd_parts, '-Wl,-rpath,@loader_path/../local')
|
||||
push(cmd_parts, '-Wl,-rpath,' + local_dir)
|
||||
cmd_parts = array(cmd_parts, [
|
||||
'-undefined', 'dynamic_lookup',
|
||||
'-Wl,-dead_strip',
|
||||
'-Wl,-install_name,' + stable_path,
|
||||
'-Wl,-rpath,@loader_path/../local',
|
||||
'-Wl,-rpath,' + local_dir
|
||||
])
|
||||
} else if (tc.system == 'linux') {
|
||||
// Allow undefined symbols at link time
|
||||
push(cmd_parts, '-Wl,--allow-shlib-undefined')
|
||||
// Garbage collect unused sections
|
||||
push(cmd_parts, '-Wl,--gc-sections')
|
||||
// rpath for .cell/local libraries
|
||||
push(cmd_parts, '-Wl,-rpath,$ORIGIN/../local')
|
||||
push(cmd_parts, '-Wl,-rpath,' + local_dir)
|
||||
cmd_parts = array(cmd_parts, [
|
||||
'-Wl,--allow-shlib-undefined',
|
||||
'-Wl,--gc-sections',
|
||||
'-Wl,-rpath,$ORIGIN/../local',
|
||||
'-Wl,-rpath,' + local_dir
|
||||
])
|
||||
} else if (tc.system == 'windows') {
|
||||
// Windows DLLs: use --allow-shlib-undefined for mingw
|
||||
push(cmd_parts, '-Wl,--allow-shlib-undefined')
|
||||
@@ -308,17 +305,11 @@ Build.build_dynamic = function(pkg, target = Build.detect_host_target(), buildty
|
||||
})
|
||||
|
||||
// Do NOT link against core library - symbols resolved at dlopen time
|
||||
cmd_parts = array(cmd_parts, resolved_ldflags)
|
||||
cmd_parts = array(cmd_parts, target_ldflags)
|
||||
|
||||
// Add LDFLAGS
|
||||
arrfor(resolved_ldflags, function(flag) {
|
||||
push(cmd_parts, flag)
|
||||
})
|
||||
|
||||
arrfor(target_ldflags, function(flag) {
|
||||
push(cmd_parts, flag)
|
||||
})
|
||||
|
||||
push(cmd_parts, '-o', '"' + store_path + '"')
|
||||
push(cmd_parts, '-o')
|
||||
push(cmd_parts, '"' + store_path + '"')
|
||||
|
||||
var cmd_str = text(cmd_parts, ' ')
|
||||
|
||||
|
||||
2
crypto.c
2
crypto.c
@@ -231,7 +231,7 @@ JSValue js_crypto_unlock(JSContext *js, JSValue self, int argc, JSValue *argv) {
|
||||
|
||||
static const JSCFunctionListEntry js_crypto_funcs[] = {
|
||||
JS_CFUNC_DEF("shared", 2, js_crypto_shared),
|
||||
JS_CFUNC_DEF("blake2", 1, js_crypto_blake2),
|
||||
JS_CFUNC_DEF("blake2", 2, js_crypto_blake2),
|
||||
JS_CFUNC_DEF("sign", 2, js_crypto_sign),
|
||||
JS_CFUNC_DEF("verify", 3, js_crypto_verify),
|
||||
JS_CFUNC_DEF("lock", 3, js_crypto_lock),
|
||||
|
||||
@@ -88,7 +88,7 @@ function use_core(path) {
|
||||
var script = text(script_blob)
|
||||
var mod = `(function setup_module(use){${script}})`
|
||||
var fn = js.eval('core:' + path, mod)
|
||||
var result = call(fn,sym, use_core)
|
||||
var result = call(fn,sym, [use_core])
|
||||
use_cache[cache_key] = result;
|
||||
return result;
|
||||
}
|
||||
@@ -185,7 +185,7 @@ function disrupt(err)
|
||||
|
||||
if (underlings) {
|
||||
var unders = array(underlings)
|
||||
arrfor(unders, function(id) {
|
||||
arrfor(unders, function(id, index) {
|
||||
log.console(`calling on ${id} to disrupt too`)
|
||||
$_.stop(create_actor({id}))
|
||||
})
|
||||
@@ -416,14 +416,14 @@ function handle_host(e) {
|
||||
peers[`${e.peer.address}:${e.peer.port}`] = e.peer
|
||||
var queue = peer_queue.get(e.peer)
|
||||
if (queue) {
|
||||
arrfor(queue, msg => e.peer.send(nota.encode(msg)))
|
||||
arrfor(queue, (msg, index) => e.peer.send(nota.encode(msg)))
|
||||
log.system(`sent ${msg} out of queue`)
|
||||
peer_queue.delete(e.peer)
|
||||
}
|
||||
break
|
||||
case "disconnect":
|
||||
peer_queue.delete(e.peer)
|
||||
arrfor(array(peers), function(id) {
|
||||
arrfor(array(peers), function(id, index) {
|
||||
if (peers[id] == e.peer) delete peers[id]
|
||||
})
|
||||
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port)
|
||||
@@ -440,7 +440,7 @@ function handle_host(e) {
|
||||
obj[ACTORDATA].address = e.peer.address
|
||||
obj[ACTORDATA].port = e.peer.port
|
||||
}
|
||||
arrfor(array(obj), function(key) {
|
||||
arrfor(array(obj), function(key, index) {
|
||||
if (key in obj)
|
||||
populate_actor_addresses(obj[key])
|
||||
})
|
||||
@@ -496,11 +496,6 @@ $_.unneeded = function unneeded(fn, seconds) {
|
||||
|
||||
// schedules the invocation of a function after a specified amount of time.
|
||||
$_.delay = function delay(fn, seconds = 0) {
|
||||
if (seconds <= 0) {
|
||||
$_.clock(fn)
|
||||
return
|
||||
}
|
||||
|
||||
function delay_turn() {
|
||||
fn()
|
||||
send_messages()
|
||||
@@ -592,7 +587,7 @@ var need_stop = false
|
||||
return
|
||||
}
|
||||
|
||||
arrfor(message_queue, function(msg) {
|
||||
arrfor(message_queue, function(msg, index) {
|
||||
if (msg.startup) {
|
||||
// now is the time to actually spin up the actor
|
||||
actor_mod.createactor(msg.startup)
|
||||
@@ -817,7 +812,7 @@ $_.clock(_ => {
|
||||
|
||||
// Call with signature: setup_module(args, use, env)
|
||||
// The script wrapper binds $delay, $start, etc. from env
|
||||
var val = call(locator.symbol, null, _cell.args.arg, use_fn, env)
|
||||
var val = call(locator.symbol, null, [_cell.args.arg, use_fn, env])
|
||||
|
||||
if (val)
|
||||
throw Error('Program must not return anything');
|
||||
|
||||
@@ -561,7 +561,7 @@ Shop.open_package_dylib = function(pkg) {
|
||||
var content = text(fd.slurp(toml_path))
|
||||
var cfg = toml.decode(content)
|
||||
if (cfg.dependencies) {
|
||||
arrfor(array(cfg.dependencies), function(alias) {
|
||||
arrfor(array(cfg.dependencies), function(alias, i) {
|
||||
var dep_pkg = cfg.dependencies[alias]
|
||||
try {
|
||||
Shop.open_package_dylib(dep_pkg)
|
||||
@@ -812,7 +812,7 @@ function execute_module(info)
|
||||
|
||||
// Call with signature: setup_module(args, use, env)
|
||||
// args is null for module loading
|
||||
used = call(mod_resolve.symbol, context, null, use_fn, env)
|
||||
used = call(mod_resolve.symbol, context, [null, use_fn, env])
|
||||
} else if (c_resolve.scope < 900) {
|
||||
// C only
|
||||
used = call_c_module(c_resolve)
|
||||
@@ -1195,11 +1195,11 @@ Shop.module_reload = function(path, package) {
|
||||
var old = use_cache[cache_key]
|
||||
var newmod = get_module(path, package)
|
||||
|
||||
arrfor(array(newmod), function(i) {
|
||||
arrfor(array(newmod), function(i, idx) {
|
||||
old[i] = newmod[i]
|
||||
})
|
||||
|
||||
arrfor(array(old), function(i) {
|
||||
arrfor(array(old), function(i, idx) {
|
||||
if (!(i in newmod))
|
||||
old[i] = null
|
||||
})
|
||||
@@ -1226,7 +1226,7 @@ Shop.build_package_scripts = function(package)
|
||||
var scripts = get_package_scripts(package)
|
||||
var pkg_dir = get_package_abs_dir(package)
|
||||
|
||||
arrfor(scripts, function(script) {
|
||||
arrfor(scripts, function(script, i) {
|
||||
resolve_mod_fn(pkg_dir + '/' + script, package)
|
||||
})
|
||||
}
|
||||
@@ -1284,7 +1284,7 @@ Shop.audit_packages = function() {
|
||||
|
||||
var bad = []
|
||||
|
||||
arrfor(packages, function(package) {
|
||||
arrfor(packages, function(package, i) {
|
||||
if (package == 'core') return
|
||||
if (fd.is_dir(package)) return
|
||||
if (fetch_remote_hash(package)) return
|
||||
|
||||
207
source/quickjs.c
207
source/quickjs.c
@@ -686,7 +686,7 @@ typedef enum {
|
||||
typedef struct JSFunction {
|
||||
JSGCObjectHeader header; /* must come first */
|
||||
JSAtom name;
|
||||
uint8_t length;
|
||||
uint16_t length; /* arity: max allowed arguments */
|
||||
uint8_t kind;
|
||||
uint8_t free_mark : 1;
|
||||
union {
|
||||
@@ -4986,7 +4986,7 @@ JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
|
||||
|
||||
typedef struct JSCFunctionDataRecord {
|
||||
JSCFunctionData *func;
|
||||
uint8_t length;
|
||||
uint16_t length; /* arity: max allowed arguments */
|
||||
uint8_t data_len;
|
||||
uint16_t magic;
|
||||
JSValue data[0];
|
||||
@@ -10133,7 +10133,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
|
||||
if (name_atom == JS_ATOM_NULL)
|
||||
name_atom = JS_ATOM_empty_string;
|
||||
f->name = JS_DupAtom(ctx, name_atom);
|
||||
f->length = b->defined_arg_count;
|
||||
f->length = b->arg_count; /* arity = total parameter count */
|
||||
return func_obj;
|
||||
fail:
|
||||
/* bfunc is freed when func_obj is freed */
|
||||
@@ -10263,6 +10263,19 @@ static JSValue js_call_c_function(JSContext *ctx, JSValueConst func_obj,
|
||||
ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
|
||||
}
|
||||
break;
|
||||
/* Fixed-arity fast paths - direct call without argc/argv marshaling */
|
||||
case JS_CFUNC_0:
|
||||
ret_val = func.f0(ctx, this_obj);
|
||||
break;
|
||||
case JS_CFUNC_1:
|
||||
ret_val = func.f1(ctx, this_obj, arg_buf[0]);
|
||||
break;
|
||||
case JS_CFUNC_2:
|
||||
ret_val = func.f2(ctx, this_obj, arg_buf[0], arg_buf[1]);
|
||||
break;
|
||||
case JS_CFUNC_3:
|
||||
ret_val = func.f3(ctx, this_obj, arg_buf[0], arg_buf[1], arg_buf[2]);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
@@ -10436,10 +10449,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
return JS_ThrowTypeError(caller_ctx, "not a function");
|
||||
}
|
||||
f = JS_VALUE_GET_FUNCTION(func_obj);
|
||||
/* Strict arity enforcement: too many arguments throws */
|
||||
if (unlikely(argc > f->length)) {
|
||||
char buf[ATOM_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowTypeError(caller_ctx, "too many arguments for %s: expected %d, got %d", JS_AtomGetStr(caller_ctx,buf, ATOM_GET_STR_BUF_SIZE, f->name), f->length, argc);
|
||||
}
|
||||
switch (f->kind) {
|
||||
case JS_FUNC_KIND_C:
|
||||
return js_call_c_function(caller_ctx, func_obj, this_obj, argc,
|
||||
(JSValueConst *)argv);
|
||||
(JSValueConst *)argv);
|
||||
case JS_FUNC_KIND_BOUND:
|
||||
return js_call_bound_function(caller_ctx, func_obj, this_obj, argc,
|
||||
(JSValueConst *)argv);
|
||||
@@ -10985,6 +11003,16 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
||||
scope_idx = get_u16(pc) + ARG_SCOPE_END;
|
||||
pc += 2;
|
||||
sf->cur_pc = pc;
|
||||
/* Fast path: check arity before building arg list */
|
||||
if (JS_VALUE_GET_TAG(sp[-2]) == JS_TAG_FUNCTION &&
|
||||
JS_VALUE_GET_TAG(sp[-1]) == JS_TAG_ARRAY) {
|
||||
JSFunction *callee = JS_VALUE_GET_FUNCTION(sp[-2]);
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY(sp[-1]);
|
||||
if (unlikely(arr->len > callee->length)) {
|
||||
JS_ThrowTypeError(ctx, "too many arguments");
|
||||
goto exception;
|
||||
}
|
||||
}
|
||||
tab = build_arg_list(ctx, &len, sp[-1]);
|
||||
if (!tab)
|
||||
goto exception;
|
||||
@@ -22070,7 +22098,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
JSFunctionDef *fd = s->cur_func;
|
||||
BOOL is_expr;
|
||||
int func_idx, lexical_func_idx = -1;
|
||||
BOOL has_opt_arg;
|
||||
BOOL create_func_var = FALSE;
|
||||
|
||||
is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
|
||||
@@ -22154,7 +22181,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
/* parse arguments */
|
||||
fd->has_simple_parameter_list = TRUE;
|
||||
fd->has_parameter_expressions = FALSE;
|
||||
has_opt_arg = FALSE;
|
||||
if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
|
||||
JSAtom name;
|
||||
if (s->token.u.ident.is_reserved) {
|
||||
@@ -22164,7 +22190,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
name = s->token.u.ident.atom;
|
||||
if (add_arg(ctx, fd, name) < 0)
|
||||
goto fail;
|
||||
fd->defined_arg_count = 1;
|
||||
} else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
|
||||
if (s->token.val == '(') {
|
||||
int skip_bits;
|
||||
@@ -22199,10 +22224,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
has_initializer = js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, TRUE, FALSE);
|
||||
if (has_initializer < 0)
|
||||
goto fail;
|
||||
if (has_initializer)
|
||||
has_opt_arg = TRUE;
|
||||
if (!has_opt_arg)
|
||||
fd->defined_arg_count++;
|
||||
} else if (s->token.val == TOK_IDENT) {
|
||||
if (s->token.u.ident.is_reserved) {
|
||||
js_parse_error_reserved_identifier(s);
|
||||
@@ -22224,7 +22245,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
int label;
|
||||
|
||||
fd->has_simple_parameter_list = FALSE;
|
||||
has_opt_arg = TRUE;
|
||||
|
||||
if (next_token(s))
|
||||
goto fail;
|
||||
@@ -22248,9 +22268,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
emit_atom(s, name);
|
||||
emit_u16(s, fd->scope_level);
|
||||
} else {
|
||||
if (!has_opt_arg) {
|
||||
fd->defined_arg_count++;
|
||||
}
|
||||
if (fd->has_parameter_expressions) {
|
||||
/* copy the argument to the argument scope */
|
||||
emit_op(s, OP_get_arg);
|
||||
@@ -22276,6 +22293,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* Explicit arity: defined_arg_count == arg_count always */
|
||||
fd->defined_arg_count = fd->arg_count;
|
||||
|
||||
if (fd->has_parameter_expressions) {
|
||||
int idx;
|
||||
@@ -24518,14 +24537,22 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
|
||||
JSValueConst this_arg, array_arg;
|
||||
uint32_t len;
|
||||
JSValue *tab, ret;
|
||||
JSFunction *f;
|
||||
|
||||
if (check_function(ctx, this_val))
|
||||
return JS_EXCEPTION;
|
||||
f = JS_VALUE_GET_FUNCTION(this_val);
|
||||
this_arg = argv[0];
|
||||
array_arg = argv[1];
|
||||
if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL && magic != 2) {
|
||||
return JS_Call(ctx, this_val, this_arg, 0, NULL);
|
||||
}
|
||||
/* Fast path: check arity before building arg list */
|
||||
if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_ARRAY) {
|
||||
JSArray *arr = JS_VALUE_GET_ARRAY(array_arg);
|
||||
if (unlikely(arr->len > f->length))
|
||||
return JS_ThrowTypeError(ctx, "too many arguments");
|
||||
}
|
||||
tab = build_arg_list(ctx, &len, array_arg);
|
||||
if (!tab)
|
||||
return JS_EXCEPTION;
|
||||
@@ -27872,6 +27899,8 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
if (JS_IsFunction(ctx, argv[1])) {
|
||||
/* Map */
|
||||
JSValueConst func = argv[1];
|
||||
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
|
||||
|
||||
int reverse = argc > 2 && JS_ToBool(ctx, argv[2]);
|
||||
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
|
||||
|
||||
@@ -27886,10 +27915,15 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[0]);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
JSValue val;
|
||||
if (arity >= 2) {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
} else {
|
||||
val = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
if (JS_IsException(val)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
@@ -27908,10 +27942,15 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[0]);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
JSValue val;
|
||||
if (arity >= 2) {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
} else {
|
||||
val = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
if (JS_IsException(val)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
@@ -28360,14 +28399,22 @@ static JSValue js_cell_array_for(JSContext *ctx, JSValueConst this_val,
|
||||
int reverse = argc > 2 && JS_ToBool(ctx, argv[2]);
|
||||
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
|
||||
|
||||
/* Determine function arity */
|
||||
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
|
||||
|
||||
if (reverse) {
|
||||
for (int64_t i = len - 1; i >= 0; i--) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arr, i);
|
||||
if (JS_IsException(item)) return JS_EXCEPTION;
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JSValue result;
|
||||
if (arity == 1) {
|
||||
result = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
} else {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
if (JS_IsException(result)) return JS_EXCEPTION;
|
||||
if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) {
|
||||
return result;
|
||||
@@ -28378,10 +28425,15 @@ static JSValue js_cell_array_for(JSContext *ctx, JSValueConst this_val,
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arr, i);
|
||||
if (JS_IsException(item)) return JS_EXCEPTION;
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JSValue result;
|
||||
if (arity == 1) {
|
||||
result = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
} else {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
if (JS_IsException(result)) return JS_EXCEPTION;
|
||||
if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) {
|
||||
return result;
|
||||
@@ -28443,14 +28495,21 @@ static JSValue js_cell_array_find(JSContext *ctx, JSValueConst this_val,
|
||||
|
||||
/* Use function predicate */
|
||||
JSValueConst func = argv[1];
|
||||
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
|
||||
if (reverse) {
|
||||
for (int64_t i = from; i >= 0; i--) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arr, i);
|
||||
if (JS_IsException(item)) return JS_EXCEPTION;
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JSValue result;
|
||||
if (arity == 2) {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
} else {
|
||||
result = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
|
||||
if (JS_IsException(result)) return JS_EXCEPTION;
|
||||
if (JS_ToBool(ctx, result)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
@@ -28462,10 +28521,16 @@ static JSValue js_cell_array_find(JSContext *ctx, JSValueConst this_val,
|
||||
for (int64_t i = from; i < len; i++) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arr, i);
|
||||
if (JS_IsException(item)) return JS_EXCEPTION;
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JSValue result;
|
||||
if (arity == 2) {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
result = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
} else {
|
||||
result = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
}
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
|
||||
if (JS_IsException(result)) return JS_EXCEPTION;
|
||||
if (JS_ToBool(ctx, result)) {
|
||||
JS_FreeValue(ctx, result);
|
||||
@@ -28495,6 +28560,8 @@ static JSValue js_cell_array_filter(JSContext *ctx, JSValueConst this_val,
|
||||
JSValue result = JS_NewArray(ctx);
|
||||
if (JS_IsException(result)) return result;
|
||||
|
||||
int arity = ((JSFunction*)JS_VALUE_GET_FUNCTION(func))->length;
|
||||
|
||||
int64_t out_idx = 0;
|
||||
for (int64_t i = 0; i < len; i++) {
|
||||
JSValue item = JS_GetPropertyInt64(ctx, arr, i);
|
||||
@@ -28502,9 +28569,16 @@ static JSValue js_cell_array_filter(JSContext *ctx, JSValueConst this_val,
|
||||
JS_FreeValue(ctx, result);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
JSValue val;
|
||||
if (arity == 0) {
|
||||
val = JS_Call(ctx, func, JS_NULL, 0, NULL);
|
||||
} else if (arity == 1) {
|
||||
val = JS_Call(ctx, func, JS_NULL, 1, &item);
|
||||
} else {
|
||||
JSValue args[2] = { item, JS_NewInt64(ctx, i) };
|
||||
val = JS_Call(ctx, func, JS_NULL, 2, args);
|
||||
JS_FreeValue(ctx, args[1]);
|
||||
}
|
||||
if (JS_IsException(val)) {
|
||||
JS_FreeValue(ctx, item);
|
||||
JS_FreeValue(ctx, result);
|
||||
@@ -28848,7 +28922,7 @@ static JSValue js_cell_object(JSContext *ctx, JSValueConst this_val,
|
||||
* fn function and sub-functions
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
/* fn.apply(func, args) */
|
||||
/* fn.apply(func, args) - arity is enforced in JS_CallInternal */
|
||||
static JSValue js_cell_fn_apply(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
@@ -28871,19 +28945,6 @@ static JSValue js_cell_fn_apply(JSContext *ctx, JSValueConst this_val,
|
||||
if (js_get_length64(ctx, &len, args_val))
|
||||
return JS_EXCEPTION;
|
||||
|
||||
/* Check arity */
|
||||
JSValue func_len = JS_GetPropertyStr(ctx, func, "length");
|
||||
if (!JS_IsException(func_len)) {
|
||||
int arity;
|
||||
if (!JS_ToInt32(ctx, &arity, func_len)) {
|
||||
if (len > arity) {
|
||||
JS_FreeValue(ctx, func_len);
|
||||
return JS_ThrowTypeError(ctx, "fn.apply: too many arguments");
|
||||
}
|
||||
}
|
||||
JS_FreeValue(ctx, func_len);
|
||||
}
|
||||
|
||||
JSValue *args = js_malloc(ctx, sizeof(JSValue) * (len > 0 ? len : 1));
|
||||
if (!args) return JS_EXCEPTION;
|
||||
|
||||
@@ -29221,22 +29282,22 @@ static JSValue js_blob_w32(JSContext *ctx, JSValueConst this_val,
|
||||
}
|
||||
|
||||
/* blob.wf(value) - write float */
|
||||
static JSValue js_blob_wf(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
|
||||
static JSValue js_blob_wf(JSContext *ctx, JSValueConst this_val, JSValueConst arg0)
|
||||
{
|
||||
if (argc < 1) return JS_ThrowTypeError(ctx, "wf(value) requires 1 argument");
|
||||
if (JS_IsNull(arg0)) return JS_ThrowTypeError(ctx, "wf(value) requires 1 argument");
|
||||
|
||||
blob *bd = js_get_blob(ctx, this_val);
|
||||
if (!bd) return JS_ThrowTypeError(ctx, "wf: not called on a blob");
|
||||
|
||||
float f;
|
||||
int tag = JS_VALUE_GET_TAG(argv[0]);
|
||||
int tag = JS_VALUE_GET_TAG(arg0);
|
||||
if (tag == JS_TAG_INT) {
|
||||
f = (float)JS_VALUE_GET_INT(argv[0]);
|
||||
f = (float)JS_VALUE_GET_INT(arg0);
|
||||
} else if (tag == JS_TAG_FLOAT64) {
|
||||
f = (float)JS_VALUE_GET_FLOAT64(argv[0]);
|
||||
f = (float)JS_VALUE_GET_FLOAT64(arg0);
|
||||
} else {
|
||||
double d;
|
||||
if (JS_ToFloat64(ctx, &d, argv[0]) < 0) return JS_EXCEPTION;
|
||||
if (JS_ToFloat64(ctx, &d, arg0) < 0) return JS_EXCEPTION;
|
||||
f = (float)d;
|
||||
}
|
||||
|
||||
@@ -29409,7 +29470,7 @@ static const JSCFunctionListEntry js_blob_proto_funcs[] = {
|
||||
JS_CFUNC_DEF("write_fit", 2, js_blob_write_fit),
|
||||
JS_CFUNC_DEF("write_text", 1, js_blob_write_text),
|
||||
JS_CFUNC_DEF("write_pad", 1, js_blob_write_pad),
|
||||
JS_CFUNC_DEF("wf", 1, js_blob_wf),
|
||||
JS_CFUNC1_DEF("wf", js_blob_wf),
|
||||
JS_CFUNC_DEF("w16", 1, js_blob_w16),
|
||||
JS_CFUNC_DEF("w32", 1, js_blob_w32),
|
||||
|
||||
@@ -29922,7 +29983,7 @@ static JSValue js_cell_length(JSContext *ctx, JSValueConst this_val,
|
||||
* call() function - call a function with explicit this and arguments
|
||||
* ============================================================================ */
|
||||
|
||||
/* call(func, this_val, ...args) */
|
||||
/* call(func, this_val, args_array) */
|
||||
static JSValue js_cell_call(JSContext *ctx, JSValueConst this_val,
|
||||
int argc, JSValueConst *argv)
|
||||
{
|
||||
@@ -29937,10 +29998,20 @@ static JSValue js_cell_call(JSContext *ctx, JSValueConst this_val,
|
||||
if (argc >= 2)
|
||||
this_arg = argv[1];
|
||||
|
||||
int call_argc = argc > 2 ? argc - 2 : 0;
|
||||
JSValueConst *call_argv = call_argc > 0 ? &argv[2] : NULL;
|
||||
if (argc < 3 || JS_IsNull(argv[2]))
|
||||
return JS_Call(ctx, func, this_arg, 0, NULL);
|
||||
|
||||
return JS_Call(ctx, func, this_arg, call_argc, call_argv);
|
||||
if (!JS_IsArray(ctx, argv[2]))
|
||||
return JS_ThrowTypeError(ctx, "third argument must be an array");
|
||||
|
||||
uint32_t len;
|
||||
JSValue *tab = build_arg_list(ctx, &len, argv[2]);
|
||||
if (!tab)
|
||||
return JS_EXCEPTION;
|
||||
|
||||
JSValue ret = JS_Call(ctx, func, this_arg, len, (JSValueConst *)tab);
|
||||
free_arg_list(ctx, tab, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -30199,7 +30270,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
||||
|
||||
/* Cell Script global functions: text, number, array, object, fn */
|
||||
{
|
||||
JSValue text_func = JS_NewCFunction(ctx, js_cell_text, "text", 2);
|
||||
JSValue text_func = JS_NewCFunction(ctx, js_cell_text, "text", 3);
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "text", text_func);
|
||||
|
||||
JSValue number_func = JS_NewCFunction(ctx, js_cell_number, "number", 2);
|
||||
@@ -30267,7 +30338,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "apply",
|
||||
JS_NewCFunction(ctx, js_cell_fn_apply, "apply", 2));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "replace",
|
||||
JS_NewCFunction(ctx, js_cell_text_replace, "replace", 2));
|
||||
JS_NewCFunction(ctx, js_cell_text_replace, "replace", 4));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "lower",
|
||||
JS_NewCFunction(ctx, js_cell_text_lower, "lower", 1));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "upper",
|
||||
@@ -30279,7 +30350,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "search",
|
||||
JS_NewCFunction(ctx, js_cell_text_search, "search", 3));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "extract",
|
||||
JS_NewCFunction(ctx, js_cell_text_extract, "extract", 3));
|
||||
JS_NewCFunction(ctx, js_cell_text_extract, "extract", 4));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "reduce",
|
||||
JS_NewCFunction(ctx, js_cell_array_reduce, "reduce", 4));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "arrfor",
|
||||
@@ -30309,9 +30380,9 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "trunc",
|
||||
JS_NewCFunction(ctx, js_cell_number_trunc, "trunc", 2));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "min",
|
||||
JS_NewCFunction(ctx, js_cell_number_min, "min", 0));
|
||||
JS_NewCFunction(ctx, js_cell_number_min, "min", 2));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "max",
|
||||
JS_NewCFunction(ctx, js_cell_number_max, "max", 0));
|
||||
JS_NewCFunction(ctx, js_cell_number_max, "max", 2));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "remainder",
|
||||
JS_NewCFunction(ctx, js_cell_number_remainder, "remainder", 2));
|
||||
JS_SetPropertyStr(ctx, ctx->global_obj, "character",
|
||||
|
||||
@@ -746,13 +746,32 @@ typedef enum JSCFunctionEnum {
|
||||
JS_CFUNC_generic_magic,
|
||||
JS_CFUNC_f_f,
|
||||
JS_CFUNC_f_f_f,
|
||||
/* Fixed-arity fast paths - no argc/argv overhead */
|
||||
JS_CFUNC_0, /* JSValue f(ctx, this_val) */
|
||||
JS_CFUNC_1, /* JSValue f(ctx, this_val, arg0) */
|
||||
JS_CFUNC_2, /* JSValue f(ctx, this_val, arg0, arg1) */
|
||||
JS_CFUNC_3, /* JSValue f(ctx, this_val, arg0, arg1, arg2) */
|
||||
JS_CFUNC_4
|
||||
} JSCFunctionEnum;
|
||||
|
||||
/* Fixed-arity C function types for fast paths */
|
||||
typedef JSValue JSCFunction0(JSContext *ctx, JSValueConst this_val);
|
||||
typedef JSValue JSCFunction1(JSContext *ctx, JSValueConst this_val, JSValueConst arg0);
|
||||
typedef JSValue JSCFunction2(JSContext *ctx, JSValueConst this_val, JSValueConst arg0, JSValueConst arg1);
|
||||
typedef JSValue JSCFunction3(JSContext *ctx, JSValueConst this_val, JSValueConst arg0, JSValueConst arg1, JSValueConst arg2);
|
||||
typedef JSValue JSCFunction4(JSContext *ctx, JSValueConst this_val, JSValueConst arg0, JSValueConst arg1, JSValueConst arg2, JSValueConst arg3);
|
||||
|
||||
typedef union JSCFunctionType {
|
||||
JSCFunction *generic;
|
||||
JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
|
||||
double (*f_f)(double);
|
||||
double (*f_f_f)(double, double);
|
||||
/* Fixed-arity fast paths */
|
||||
JSCFunction0 *f0;
|
||||
JSCFunction1 *f1;
|
||||
JSCFunction2 *f2;
|
||||
JSCFunction3 *f3;
|
||||
JSCFunction4 *f4;
|
||||
} JSCFunctionType;
|
||||
|
||||
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
|
||||
@@ -775,6 +794,32 @@ static inline JSValue JS_NewCFunctionMagic(JSContext *ctx, JSCFunctionMagic *fun
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, length, cproto, magic);
|
||||
}
|
||||
|
||||
/* Fixed-arity fast path constructors */
|
||||
static inline JSValue JS_NewCFuncFixed0(JSContext *ctx, JSCFunction0 *func, const char *name)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, 0, JS_CFUNC_0, 0);
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewCFuncFixed1(JSContext *ctx, JSCFunction1 *func, const char *name)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, 1, JS_CFUNC_1, 0);
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewCFuncFixed2(JSContext *ctx, JSCFunction2 *func, const char *name)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, 2, JS_CFUNC_2, 0);
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewCFuncFixed3(JSContext *ctx, JSCFunction3 *func, const char *name)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, 3, JS_CFUNC_3, 0);
|
||||
}
|
||||
|
||||
static inline JSValue JS_NewCFuncFixed4(JSContext *ctx, JSCFunction4 *func, const char *name)
|
||||
{
|
||||
return JS_NewCFunction2(ctx, (JSCFunction *)func, name, 4, JS_CFUNC_4, 0);
|
||||
}
|
||||
|
||||
/* C property definition */
|
||||
|
||||
typedef struct JSCFunctionListEntry {
|
||||
@@ -816,6 +861,11 @@ typedef struct JSCFunctionListEntry {
|
||||
#define JS_CFUNC_DEF(name, length, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_generic, { .generic = func1 } } } }
|
||||
#define JS_CFUNC_MAGIC_DEF(name, length, func1, magic) { name, 0, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_generic_magic, { .generic_magic = func1 } } } }
|
||||
#define JS_CFUNC_SPECIAL_DEF(name, length, cproto, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { length, JS_CFUNC_ ## cproto, { .cproto = func1 } } } }
|
||||
/* Fixed-arity fast path macros */
|
||||
#define JS_CFUNC0_DEF(name, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { 0, JS_CFUNC_0, { .f0 = func1 } } } }
|
||||
#define JS_CFUNC1_DEF(name, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { 1, JS_CFUNC_1, { .f1 = func1 } } } }
|
||||
#define JS_CFUNC2_DEF(name, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { 2, JS_CFUNC_2, { .f2 = func1 } } } }
|
||||
#define JS_CFUNC3_DEF(name, func1) { name, 0, JS_DEF_CFUNC, 0, .u = { .func = { 3, JS_CFUNC_3, { .f3 = func1 } } } }
|
||||
#define JS_ITERATOR_NEXT_DEF(name, length, func1, magic) { name, 0, JS_DEF_CFUNC, magic, .u = { .func = { length, JS_CFUNC_iterator_next, { .iterator_next = func1 } } } }
|
||||
#define JS_PROP_STRING_DEF(name, cstr, prop_flags) { name, prop_flags, JS_DEF_PROP_STRING, 0, .u = { .str = cstr } }
|
||||
#define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }
|
||||
|
||||
Reference in New Issue
Block a user