fixed function arity

This commit is contained in:
2026-01-25 13:51:34 -06:00
parent 802c94085b
commit 8325253f1a
6 changed files with 223 additions and 116 deletions

View File

@@ -121,11 +121,11 @@ Build.compile_file = function(pkg, file, target, buildtype = 'release') {
// Add buildtype-specific flags // Add buildtype-specific flags
if (buildtype == 'release') { if (buildtype == 'release') {
push(cmd_parts, '-O3', '-DNDEBUG') cmd_parts = array(cmd_parts, ['-O3', '-DNDEBUG'])
} else if (buildtype == 'debug') { } else if (buildtype == 'debug') {
push(cmd_parts, '-O2', '-g') cmd_parts = array(cmd_parts, ['-O2', '-g'])
} else if (buildtype == 'minsize') { } else if (buildtype == 'minsize') {
push(cmd_parts, '-Os', '-DNDEBUG') cmd_parts = array(cmd_parts, ['-Os', '-DNDEBUG'])
} }
push(cmd_parts, '-DCELL_USE_NAME=' + sym_name) 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 // Platform-specific flags for undefined symbols (resolved at dlopen) and size optimization
if (tc.system == 'darwin') { if (tc.system == 'darwin') {
// Allow undefined symbols - they will be resolved when dlopen'd into the main executable cmd_parts = array(cmd_parts, [
push(cmd_parts, '-undefined', 'dynamic_lookup') '-undefined', 'dynamic_lookup',
// Dead-strip unused code '-Wl,-dead_strip',
push(cmd_parts, '-Wl,-dead_strip') '-Wl,-install_name,' + stable_path,
// Set install_name to stable path so runtime finds it correctly '-Wl,-rpath,@loader_path/../local',
push(cmd_parts, '-Wl,-install_name,' + stable_path) '-Wl,-rpath,' + local_dir
// rpath for .cell/local libraries ])
push(cmd_parts, '-Wl,-rpath,@loader_path/../local')
push(cmd_parts, '-Wl,-rpath,' + local_dir)
} else if (tc.system == 'linux') { } else if (tc.system == 'linux') {
// Allow undefined symbols at link time cmd_parts = array(cmd_parts, [
push(cmd_parts, '-Wl,--allow-shlib-undefined') '-Wl,--allow-shlib-undefined',
// Garbage collect unused sections '-Wl,--gc-sections',
push(cmd_parts, '-Wl,--gc-sections') '-Wl,-rpath,$ORIGIN/../local',
// rpath for .cell/local libraries '-Wl,-rpath,' + local_dir
push(cmd_parts, '-Wl,-rpath,$ORIGIN/../local') ])
push(cmd_parts, '-Wl,-rpath,' + local_dir)
} else if (tc.system == 'windows') { } else if (tc.system == 'windows') {
// Windows DLLs: use --allow-shlib-undefined for mingw // Windows DLLs: use --allow-shlib-undefined for mingw
push(cmd_parts, '-Wl,--allow-shlib-undefined') 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 // 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 push(cmd_parts, '-o')
arrfor(resolved_ldflags, function(flag) { push(cmd_parts, '"' + store_path + '"')
push(cmd_parts, flag)
})
arrfor(target_ldflags, function(flag) {
push(cmd_parts, flag)
})
push(cmd_parts, '-o', '"' + store_path + '"')
var cmd_str = text(cmd_parts, ' ') var cmd_str = text(cmd_parts, ' ')

View File

@@ -231,7 +231,7 @@ JSValue js_crypto_unlock(JSContext *js, JSValue self, int argc, JSValue *argv) {
static const JSCFunctionListEntry js_crypto_funcs[] = { static const JSCFunctionListEntry js_crypto_funcs[] = {
JS_CFUNC_DEF("shared", 2, js_crypto_shared), 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("sign", 2, js_crypto_sign),
JS_CFUNC_DEF("verify", 3, js_crypto_verify), JS_CFUNC_DEF("verify", 3, js_crypto_verify),
JS_CFUNC_DEF("lock", 3, js_crypto_lock), JS_CFUNC_DEF("lock", 3, js_crypto_lock),

View File

@@ -88,7 +88,7 @@ function use_core(path) {
var script = text(script_blob) var script = text(script_blob)
var mod = `(function setup_module(use){${script}})` var mod = `(function setup_module(use){${script}})`
var fn = js.eval('core:' + path, mod) 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; use_cache[cache_key] = result;
return result; return result;
} }
@@ -185,7 +185,7 @@ function disrupt(err)
if (underlings) { if (underlings) {
var unders = array(underlings) var unders = array(underlings)
arrfor(unders, function(id) { arrfor(unders, function(id, index) {
log.console(`calling on ${id} to disrupt too`) log.console(`calling on ${id} to disrupt too`)
$_.stop(create_actor({id})) $_.stop(create_actor({id}))
}) })
@@ -416,14 +416,14 @@ function handle_host(e) {
peers[`${e.peer.address}:${e.peer.port}`] = e.peer peers[`${e.peer.address}:${e.peer.port}`] = e.peer
var queue = peer_queue.get(e.peer) var queue = peer_queue.get(e.peer)
if (queue) { 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`) log.system(`sent ${msg} out of queue`)
peer_queue.delete(e.peer) peer_queue.delete(e.peer)
} }
break break
case "disconnect": case "disconnect":
peer_queue.delete(e.peer) peer_queue.delete(e.peer)
arrfor(array(peers), function(id) { arrfor(array(peers), function(id, index) {
if (peers[id] == e.peer) delete peers[id] if (peers[id] == e.peer) delete peers[id]
}) })
log.system('portal got disconnect from ' + e.peer.address + ":" + e.peer.port) 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].address = e.peer.address
obj[ACTORDATA].port = e.peer.port obj[ACTORDATA].port = e.peer.port
} }
arrfor(array(obj), function(key) { arrfor(array(obj), function(key, index) {
if (key in obj) if (key in obj)
populate_actor_addresses(obj[key]) 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. // schedules the invocation of a function after a specified amount of time.
$_.delay = function delay(fn, seconds = 0) { $_.delay = function delay(fn, seconds = 0) {
if (seconds <= 0) {
$_.clock(fn)
return
}
function delay_turn() { function delay_turn() {
fn() fn()
send_messages() send_messages()
@@ -592,7 +587,7 @@ var need_stop = false
return return
} }
arrfor(message_queue, function(msg) { arrfor(message_queue, function(msg, index) {
if (msg.startup) { if (msg.startup) {
// now is the time to actually spin up the actor // now is the time to actually spin up the actor
actor_mod.createactor(msg.startup) actor_mod.createactor(msg.startup)
@@ -817,7 +812,7 @@ $_.clock(_ => {
// Call with signature: setup_module(args, use, env) // Call with signature: setup_module(args, use, env)
// The script wrapper binds $delay, $start, etc. from 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) if (val)
throw Error('Program must not return anything'); throw Error('Program must not return anything');

View File

@@ -561,7 +561,7 @@ Shop.open_package_dylib = function(pkg) {
var content = text(fd.slurp(toml_path)) var content = text(fd.slurp(toml_path))
var cfg = toml.decode(content) var cfg = toml.decode(content)
if (cfg.dependencies) { if (cfg.dependencies) {
arrfor(array(cfg.dependencies), function(alias) { arrfor(array(cfg.dependencies), function(alias, i) {
var dep_pkg = cfg.dependencies[alias] var dep_pkg = cfg.dependencies[alias]
try { try {
Shop.open_package_dylib(dep_pkg) Shop.open_package_dylib(dep_pkg)
@@ -812,7 +812,7 @@ function execute_module(info)
// Call with signature: setup_module(args, use, env) // Call with signature: setup_module(args, use, env)
// args is null for module loading // 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) { } else if (c_resolve.scope < 900) {
// C only // C only
used = call_c_module(c_resolve) used = call_c_module(c_resolve)
@@ -1195,11 +1195,11 @@ Shop.module_reload = function(path, package) {
var old = use_cache[cache_key] var old = use_cache[cache_key]
var newmod = get_module(path, package) var newmod = get_module(path, package)
arrfor(array(newmod), function(i) { arrfor(array(newmod), function(i, idx) {
old[i] = newmod[i] old[i] = newmod[i]
}) })
arrfor(array(old), function(i) { arrfor(array(old), function(i, idx) {
if (!(i in newmod)) if (!(i in newmod))
old[i] = null old[i] = null
}) })
@@ -1226,7 +1226,7 @@ Shop.build_package_scripts = function(package)
var scripts = get_package_scripts(package) var scripts = get_package_scripts(package)
var pkg_dir = get_package_abs_dir(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) resolve_mod_fn(pkg_dir + '/' + script, package)
}) })
} }
@@ -1284,7 +1284,7 @@ Shop.audit_packages = function() {
var bad = [] var bad = []
arrfor(packages, function(package) { arrfor(packages, function(package, i) {
if (package == 'core') return if (package == 'core') return
if (fd.is_dir(package)) return if (fd.is_dir(package)) return
if (fetch_remote_hash(package)) return if (fetch_remote_hash(package)) return

View File

@@ -686,7 +686,7 @@ typedef enum {
typedef struct JSFunction { typedef struct JSFunction {
JSGCObjectHeader header; /* must come first */ JSGCObjectHeader header; /* must come first */
JSAtom name; JSAtom name;
uint8_t length; uint16_t length; /* arity: max allowed arguments */
uint8_t kind; uint8_t kind;
uint8_t free_mark : 1; uint8_t free_mark : 1;
union { union {
@@ -4986,7 +4986,7 @@ JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func,
typedef struct JSCFunctionDataRecord { typedef struct JSCFunctionDataRecord {
JSCFunctionData *func; JSCFunctionData *func;
uint8_t length; uint16_t length; /* arity: max allowed arguments */
uint8_t data_len; uint8_t data_len;
uint16_t magic; uint16_t magic;
JSValue data[0]; JSValue data[0];
@@ -10133,7 +10133,7 @@ static JSValue js_closure(JSContext *ctx, JSValue bfunc,
if (name_atom == JS_ATOM_NULL) if (name_atom == JS_ATOM_NULL)
name_atom = JS_ATOM_empty_string; name_atom = JS_ATOM_empty_string;
f->name = JS_DupAtom(ctx, name_atom); 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; return func_obj;
fail: fail:
/* bfunc is freed when func_obj is freed */ /* 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)); ret_val = JS_NewFloat64(ctx, func.f_f_f(d1, d2));
} }
break; 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: default:
abort(); abort();
} }
@@ -10436,10 +10449,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
return JS_ThrowTypeError(caller_ctx, "not a function"); return JS_ThrowTypeError(caller_ctx, "not a function");
} }
f = JS_VALUE_GET_FUNCTION(func_obj); 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) { switch (f->kind) {
case JS_FUNC_KIND_C: case JS_FUNC_KIND_C:
return js_call_c_function(caller_ctx, func_obj, this_obj, argc, return js_call_c_function(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv); (JSValueConst *)argv);
case JS_FUNC_KIND_BOUND: case JS_FUNC_KIND_BOUND:
return js_call_bound_function(caller_ctx, func_obj, this_obj, argc, return js_call_bound_function(caller_ctx, func_obj, this_obj, argc,
(JSValueConst *)argv); (JSValueConst *)argv);
@@ -10985,6 +11003,16 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
scope_idx = get_u16(pc) + ARG_SCOPE_END; scope_idx = get_u16(pc) + ARG_SCOPE_END;
pc += 2; pc += 2;
sf->cur_pc = pc; 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]); tab = build_arg_list(ctx, &len, sp[-1]);
if (!tab) if (!tab)
goto exception; goto exception;
@@ -22070,7 +22098,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
JSFunctionDef *fd = s->cur_func; JSFunctionDef *fd = s->cur_func;
BOOL is_expr; BOOL is_expr;
int func_idx, lexical_func_idx = -1; int func_idx, lexical_func_idx = -1;
BOOL has_opt_arg;
BOOL create_func_var = FALSE; BOOL create_func_var = FALSE;
is_expr = (func_type != JS_PARSE_FUNC_STATEMENT && is_expr = (func_type != JS_PARSE_FUNC_STATEMENT &&
@@ -22154,7 +22181,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* parse arguments */ /* parse arguments */
fd->has_simple_parameter_list = TRUE; fd->has_simple_parameter_list = TRUE;
fd->has_parameter_expressions = FALSE; fd->has_parameter_expressions = FALSE;
has_opt_arg = FALSE;
if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) { if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
JSAtom name; JSAtom name;
if (s->token.u.ident.is_reserved) { 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; name = s->token.u.ident.atom;
if (add_arg(ctx, fd, name) < 0) if (add_arg(ctx, fd, name) < 0)
goto fail; goto fail;
fd->defined_arg_count = 1;
} else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) { } else if (func_type != JS_PARSE_FUNC_CLASS_STATIC_INIT) {
if (s->token.val == '(') { if (s->token.val == '(') {
int skip_bits; 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); has_initializer = js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, TRUE, FALSE);
if (has_initializer < 0) if (has_initializer < 0)
goto fail; goto fail;
if (has_initializer)
has_opt_arg = TRUE;
if (!has_opt_arg)
fd->defined_arg_count++;
} else if (s->token.val == TOK_IDENT) { } else if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) { if (s->token.u.ident.is_reserved) {
js_parse_error_reserved_identifier(s); js_parse_error_reserved_identifier(s);
@@ -22224,7 +22245,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
int label; int label;
fd->has_simple_parameter_list = FALSE; fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
if (next_token(s)) if (next_token(s))
goto fail; goto fail;
@@ -22248,9 +22268,6 @@ static __exception int js_parse_function_decl2(JSParseState *s,
emit_atom(s, name); emit_atom(s, name);
emit_u16(s, fd->scope_level); emit_u16(s, fd->scope_level);
} else { } else {
if (!has_opt_arg) {
fd->defined_arg_count++;
}
if (fd->has_parameter_expressions) { if (fd->has_parameter_expressions) {
/* copy the argument to the argument scope */ /* copy the argument to the argument scope */
emit_op(s, OP_get_arg); emit_op(s, OP_get_arg);
@@ -22276,6 +22293,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
goto fail; goto fail;
} }
} }
/* Explicit arity: defined_arg_count == arg_count always */
fd->defined_arg_count = fd->arg_count;
if (fd->has_parameter_expressions) { if (fd->has_parameter_expressions) {
int idx; int idx;
@@ -24518,14 +24537,22 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
JSValueConst this_arg, array_arg; JSValueConst this_arg, array_arg;
uint32_t len; uint32_t len;
JSValue *tab, ret; JSValue *tab, ret;
JSFunction *f;
if (check_function(ctx, this_val)) if (check_function(ctx, this_val))
return JS_EXCEPTION; return JS_EXCEPTION;
f = JS_VALUE_GET_FUNCTION(this_val);
this_arg = argv[0]; this_arg = argv[0];
array_arg = argv[1]; array_arg = argv[1];
if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL && magic != 2) { if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL && magic != 2) {
return JS_Call(ctx, this_val, this_arg, 0, NULL); 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); tab = build_arg_list(ctx, &len, array_arg);
if (!tab) if (!tab)
return JS_EXCEPTION; return JS_EXCEPTION;
@@ -27872,6 +27899,8 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
if (JS_IsFunction(ctx, argv[1])) { if (JS_IsFunction(ctx, argv[1])) {
/* Map */ /* Map */
JSValueConst func = argv[1]; JSValueConst func = argv[1];
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
int reverse = argc > 2 && JS_ToBool(ctx, argv[2]); int reverse = argc > 2 && JS_ToBool(ctx, argv[2]);
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL; 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); JS_FreeValue(ctx, result);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue val;
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args); if (arity >= 2) {
JS_FreeValue(ctx, args[0]); JSValue args[2] = { item, JS_NewInt64(ctx, i) };
JS_FreeValue(ctx, args[1]); 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)) { if (JS_IsException(val)) {
JS_FreeValue(ctx, result); JS_FreeValue(ctx, result);
return JS_EXCEPTION; return JS_EXCEPTION;
@@ -27908,10 +27942,15 @@ static JSValue js_cell_array(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, result); JS_FreeValue(ctx, result);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue val;
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args); if (arity >= 2) {
JS_FreeValue(ctx, args[0]); JSValue args[2] = { item, JS_NewInt64(ctx, i) };
JS_FreeValue(ctx, args[1]); 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)) { if (JS_IsException(val)) {
JS_FreeValue(ctx, result); JS_FreeValue(ctx, result);
return JS_EXCEPTION; 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]); int reverse = argc > 2 && JS_ToBool(ctx, argv[2]);
JSValue exit_val = argc > 3 ? argv[3] : JS_NULL; JSValue exit_val = argc > 3 ? argv[3] : JS_NULL;
/* Determine function arity */
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
if (reverse) { if (reverse) {
for (int64_t i = len - 1; i >= 0; i--) { for (int64_t i = len - 1; i >= 0; i--) {
JSValue item = JS_GetPropertyInt64(ctx, arr, i); JSValue item = JS_GetPropertyInt64(ctx, arr, i);
if (JS_IsException(item)) return JS_EXCEPTION; if (JS_IsException(item)) return JS_EXCEPTION;
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue result;
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args); 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, item);
JS_FreeValue(ctx, args[1]);
if (JS_IsException(result)) return JS_EXCEPTION; if (JS_IsException(result)) return JS_EXCEPTION;
if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) { if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) {
return result; 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++) { for (int64_t i = 0; i < len; i++) {
JSValue item = JS_GetPropertyInt64(ctx, arr, i); JSValue item = JS_GetPropertyInt64(ctx, arr, i);
if (JS_IsException(item)) return JS_EXCEPTION; if (JS_IsException(item)) return JS_EXCEPTION;
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue result;
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args); 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, item);
JS_FreeValue(ctx, args[1]);
if (JS_IsException(result)) return JS_EXCEPTION; if (JS_IsException(result)) return JS_EXCEPTION;
if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) { if (!JS_IsNull(exit_val) && js_strict_eq(ctx, result, exit_val)) {
return result; return result;
@@ -28443,14 +28495,21 @@ static JSValue js_cell_array_find(JSContext *ctx, JSValueConst this_val,
/* Use function predicate */ /* Use function predicate */
JSValueConst func = argv[1]; JSValueConst func = argv[1];
int arity = (JSFunction*)JS_VALUE_GET_FUNCTION(argv[1])->length;
if (reverse) { if (reverse) {
for (int64_t i = from; i >= 0; i--) { for (int64_t i = from; i >= 0; i--) {
JSValue item = JS_GetPropertyInt64(ctx, arr, i); JSValue item = JS_GetPropertyInt64(ctx, arr, i);
if (JS_IsException(item)) return JS_EXCEPTION; if (JS_IsException(item)) return JS_EXCEPTION;
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue result;
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args); 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, item);
JS_FreeValue(ctx, args[1]);
if (JS_IsException(result)) return JS_EXCEPTION; if (JS_IsException(result)) return JS_EXCEPTION;
if (JS_ToBool(ctx, result)) { if (JS_ToBool(ctx, result)) {
JS_FreeValue(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++) { for (int64_t i = from; i < len; i++) {
JSValue item = JS_GetPropertyInt64(ctx, arr, i); JSValue item = JS_GetPropertyInt64(ctx, arr, i);
if (JS_IsException(item)) return JS_EXCEPTION; if (JS_IsException(item)) return JS_EXCEPTION;
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue result;
JSValue result = JS_Call(ctx, func, JS_NULL, 2, args); 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, item);
JS_FreeValue(ctx, args[1]);
if (JS_IsException(result)) return JS_EXCEPTION; if (JS_IsException(result)) return JS_EXCEPTION;
if (JS_ToBool(ctx, result)) { if (JS_ToBool(ctx, result)) {
JS_FreeValue(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); JSValue result = JS_NewArray(ctx);
if (JS_IsException(result)) return result; if (JS_IsException(result)) return result;
int arity = ((JSFunction*)JS_VALUE_GET_FUNCTION(func))->length;
int64_t out_idx = 0; int64_t out_idx = 0;
for (int64_t i = 0; i < len; i++) { for (int64_t i = 0; i < len; i++) {
JSValue item = JS_GetPropertyInt64(ctx, arr, 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); JS_FreeValue(ctx, result);
return JS_EXCEPTION; return JS_EXCEPTION;
} }
JSValue args[2] = { item, JS_NewInt64(ctx, i) }; JSValue val;
JSValue val = JS_Call(ctx, func, JS_NULL, 2, args); if (arity == 0) {
JS_FreeValue(ctx, args[1]); 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)) { if (JS_IsException(val)) {
JS_FreeValue(ctx, item); JS_FreeValue(ctx, item);
JS_FreeValue(ctx, result); JS_FreeValue(ctx, result);
@@ -28848,7 +28922,7 @@ static JSValue js_cell_object(JSContext *ctx, JSValueConst this_val,
* fn function and sub-functions * 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, static JSValue js_cell_fn_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) 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)) if (js_get_length64(ctx, &len, args_val))
return JS_EXCEPTION; 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)); JSValue *args = js_malloc(ctx, sizeof(JSValue) * (len > 0 ? len : 1));
if (!args) return JS_EXCEPTION; if (!args) return JS_EXCEPTION;
@@ -29221,22 +29282,22 @@ static JSValue js_blob_w32(JSContext *ctx, JSValueConst this_val,
} }
/* blob.wf(value) - write float */ /* 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); blob *bd = js_get_blob(ctx, this_val);
if (!bd) return JS_ThrowTypeError(ctx, "wf: not called on a blob"); if (!bd) return JS_ThrowTypeError(ctx, "wf: not called on a blob");
float f; float f;
int tag = JS_VALUE_GET_TAG(argv[0]); int tag = JS_VALUE_GET_TAG(arg0);
if (tag == JS_TAG_INT) { 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) { } else if (tag == JS_TAG_FLOAT64) {
f = (float)JS_VALUE_GET_FLOAT64(argv[0]); f = (float)JS_VALUE_GET_FLOAT64(arg0);
} else { } else {
double d; 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; 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_fit", 2, js_blob_write_fit),
JS_CFUNC_DEF("write_text", 1, js_blob_write_text), JS_CFUNC_DEF("write_text", 1, js_blob_write_text),
JS_CFUNC_DEF("write_pad", 1, js_blob_write_pad), 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("w16", 1, js_blob_w16),
JS_CFUNC_DEF("w32", 1, js_blob_w32), 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() 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, static JSValue js_cell_call(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) int argc, JSValueConst *argv)
{ {
@@ -29937,10 +29998,20 @@ static JSValue js_cell_call(JSContext *ctx, JSValueConst this_val,
if (argc >= 2) if (argc >= 2)
this_arg = argv[1]; this_arg = argv[1];
int call_argc = argc > 2 ? argc - 2 : 0; if (argc < 3 || JS_IsNull(argv[2]))
JSValueConst *call_argv = call_argc > 0 ? &argv[2] : NULL; 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 */ /* 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); JS_SetPropertyStr(ctx, ctx->global_obj, "text", text_func);
JSValue number_func = JS_NewCFunction(ctx, js_cell_number, "number", 2); 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_SetPropertyStr(ctx, ctx->global_obj, "apply",
JS_NewCFunction(ctx, js_cell_fn_apply, "apply", 2)); JS_NewCFunction(ctx, js_cell_fn_apply, "apply", 2));
JS_SetPropertyStr(ctx, ctx->global_obj, "replace", 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_SetPropertyStr(ctx, ctx->global_obj, "lower",
JS_NewCFunction(ctx, js_cell_text_lower, "lower", 1)); JS_NewCFunction(ctx, js_cell_text_lower, "lower", 1));
JS_SetPropertyStr(ctx, ctx->global_obj, "upper", JS_SetPropertyStr(ctx, ctx->global_obj, "upper",
@@ -30279,7 +30350,7 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_SetPropertyStr(ctx, ctx->global_obj, "search", JS_SetPropertyStr(ctx, ctx->global_obj, "search",
JS_NewCFunction(ctx, js_cell_text_search, "search", 3)); JS_NewCFunction(ctx, js_cell_text_search, "search", 3));
JS_SetPropertyStr(ctx, ctx->global_obj, "extract", 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_SetPropertyStr(ctx, ctx->global_obj, "reduce",
JS_NewCFunction(ctx, js_cell_array_reduce, "reduce", 4)); JS_NewCFunction(ctx, js_cell_array_reduce, "reduce", 4));
JS_SetPropertyStr(ctx, ctx->global_obj, "arrfor", JS_SetPropertyStr(ctx, ctx->global_obj, "arrfor",
@@ -30309,9 +30380,9 @@ void JS_AddIntrinsicBaseObjects(JSContext *ctx)
JS_SetPropertyStr(ctx, ctx->global_obj, "trunc", JS_SetPropertyStr(ctx, ctx->global_obj, "trunc",
JS_NewCFunction(ctx, js_cell_number_trunc, "trunc", 2)); JS_NewCFunction(ctx, js_cell_number_trunc, "trunc", 2));
JS_SetPropertyStr(ctx, ctx->global_obj, "min", 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_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_SetPropertyStr(ctx, ctx->global_obj, "remainder",
JS_NewCFunction(ctx, js_cell_number_remainder, "remainder", 2)); JS_NewCFunction(ctx, js_cell_number_remainder, "remainder", 2));
JS_SetPropertyStr(ctx, ctx->global_obj, "character", JS_SetPropertyStr(ctx, ctx->global_obj, "character",

View File

@@ -746,13 +746,32 @@ typedef enum JSCFunctionEnum {
JS_CFUNC_generic_magic, JS_CFUNC_generic_magic,
JS_CFUNC_f_f, JS_CFUNC_f_f,
JS_CFUNC_f_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; } 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 { typedef union JSCFunctionType {
JSCFunction *generic; JSCFunction *generic;
JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic); JSValue (*generic_magic)(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv, int magic);
double (*f_f)(double); double (*f_f)(double);
double (*f_f_f)(double, double); double (*f_f_f)(double, double);
/* Fixed-arity fast paths */
JSCFunction0 *f0;
JSCFunction1 *f1;
JSCFunction2 *f2;
JSCFunction3 *f3;
JSCFunction4 *f4;
} JSCFunctionType; } JSCFunctionType;
JSValue JS_NewCFunction2(JSContext *ctx, JSCFunction *func, 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); 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 */ /* C property definition */
typedef struct JSCFunctionListEntry { 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_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_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 } } } } #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_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_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 } } #define JS_PROP_INT32_DEF(name, val, prop_flags) { name, prop_flags, JS_DEF_PROP_INT32, 0, .u = { .i32 = val } }