diff --git a/debug/js.c b/debug/js.c index 3d991c02..32b94ef2 100644 --- a/debug/js.c +++ b/debug/js.c @@ -39,20 +39,22 @@ JSC_CCALL(os_calc_mem, JSC_SSCALL(os_eval, if (!str2) return JS_ThrowReferenceError(js, "Second argument should be the script."); if (!str) return JS_ThrowReferenceError(js, "First argument should be the name of the script."); - ret = JS_Eval(js,str2,strlen(str2),str, 0); + JSValue bytecode = JS_Compile(js, str2, strlen(str2), str); + if (JS_IsException(bytecode)) return bytecode; + ret = JS_Integrate(js, bytecode, JS_NULL); ) // Compile a string of JavaScript code into a function object. JSC_SSCALL(js_compile, if (!str2) return JS_ThrowReferenceError(js, "Second argument should be the script."); if (!str) return JS_ThrowReferenceError(js, "First argument should be the name of the script."); - ret = JS_Eval(js, str2, strlen(str2), str, JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_FLAG_BACKTRACE_BARRIER); + ret = JS_Compile(js, str2, strlen(str2), str); ) -// Evaluate a function object in the current QuickJS context. -JSC_CCALL(js_eval_compile, - JS_DupValue(js,argv[0]); - ret = JS_EvalFunction(js, argv[0]); +// Link compiled bytecode with environment and execute. +JSC_CCALL(js_integrate, + JSValue env = (argc > 1 && !JS_IsNull(argv[1])) ? argv[1] : JS_NULL; + ret = JS_Integrate(js, argv[0], env); ) // Compile a function object into a bytecode blob. @@ -92,7 +94,7 @@ static const JSCFunctionListEntry js_js_funcs[] = { MIST_FUNC_DEF(os, max_stacksize, 1), MIST_FUNC_DEF(os, eval, 2), MIST_FUNC_DEF(js, compile, 2), - MIST_FUNC_DEF(js, eval_compile, 1), + MIST_FUNC_DEF(js, integrate, 2), MIST_FUNC_DEF(js, compile_blob, 1), MIST_FUNC_DEF(js, compile_unblob, 1), MIST_FUNC_DEF(js, disassemble, 1), diff --git a/internal/engine.cm b/internal/engine.cm index 10f69856..e5f4d530 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -1,19 +1,12 @@ -(function engine() { -var _cell = globalThis.cell -delete globalThis.cell -var ACTORDATA = _cell.hidden.actorsym +(function engine() { +// Hidden vars (os, actorsym, init, core_path) come from env +var ACTORDATA = actorsym var SYSYM = '__SYSTEM__' -var hidden = _cell.hidden - -var os = hidden.os; - -_cell.os = null +var _cell = {} var dylib_ext -_cell.id ??= "newguy" - switch(os.platform()) { case 'Windows': dylib_ext = '.dll'; break; case 'macOS': dylib_ext = '.dylib'; break; @@ -28,8 +21,7 @@ function use_embed(name) { return load_internal("js_" + name + "_use") } -globalThis.logical = function(val1) -{ +function logical(val1) { if (val1 == 0 || val1 == false || val1 == "false" || val1 == null) return false; if (val1 == 1 || val1 == true || val1 == "true") @@ -37,19 +29,19 @@ globalThis.logical = function(val1) return null; } -globalThis.some = function(arr, pred) { +function some(arr, pred) { return find(arr, pred) != null } -globalThis.every = function(arr, pred) { +function every(arr, pred) { return find(arr, x => not(pred(x))) == null } -globalThis.starts_with = function(str, prefix) { +function starts_with(str, prefix) { return search(str, prefix) == 0 } -globalThis.ends_with = function(str, suffix) { +function ends_with(str, suffix) { return search(str, suffix, -length(suffix)) != null } @@ -99,8 +91,7 @@ function use_core(path) { var blob = use_core('blob') -globalThis.actor = function() -{ +function actor() { } @@ -108,7 +99,7 @@ var actor_mod = use_core('actor') var wota = use_core('wota') var nota = use_core('nota') -globalThis.is_actor = function(value) { +function is_actor(value) { return is_object(value) && value[ACTORDATA] } @@ -138,10 +129,10 @@ function console_rec(line, file, msg) { // time: [${time.text("mb d yyyy h:nn:ss")}] } -globalThis.log = function(name, args) { +function log(name, args) { var caller = caller_data(1) var msg = args[0] - + switch(name) { case 'console': os.print(console_rec(caller.line, caller.file, msg)) @@ -149,7 +140,7 @@ globalThis.log = function(name, args) { case 'error': msg = msg ?? Error() if (is_proto(msg, Error)) - msg = msg.name + ": " + msg.message + "\n" + msg.stack + msg = msg.name + ": " + msg.message + "\n" + msg.stack os.print(console_rec(caller.line, caller.file, msg)) break case 'system': @@ -201,9 +192,8 @@ function disrupt(err) actor_mod.on_exception(disrupt) -_cell.args = _cell.hidden.init -_cell.args ??= {} -_cell.id ??= "newguy" +_cell.args = init ?? {} +_cell.id = "newguy" function create_actor(desc = {id:guid()}) { var actor = {} @@ -224,10 +214,30 @@ var json = use_core('json') var time = use_core('time') var pronto = use_core('pronto') -globalThis.fallback = pronto.fallback -globalThis.parallel = pronto.parallel -globalThis.race = pronto.race -globalThis.sequence = pronto.sequence +var fallback = pronto.fallback +var parallel = pronto.parallel +var race = pronto.race +var sequence = pronto.sequence + +// Create runtime environment for modules +var runtime_env = { + logical: logical, + some: some, + every: every, + starts_with: starts_with, + ends_with: ends_with, + actor: actor, + is_actor: is_actor, + log: log, + send: send, + fallback: fallback, + parallel: parallel, + race: race, + sequence: sequence +} + +// Pass to os for shop to access +os.runtime_env = runtime_env $_.time_limit = function(requestor, seconds) { @@ -597,13 +607,13 @@ var need_stop = false var replies = {} -globalThis.send = function send(actor, message, reply) { +function send(actor, message, reply) { if (!is_object(actor)) throw Error(`Must send to an actor object. Provided: ${actor}`); - + if (!is_object(message)) throw Error('Message must be an object') - var send = {type:"user", data: message} + var send_msg = {type:"user", data: message} if (actor[HEADER] && actor[HEADER].replycc) { var header = actor[HEADER] @@ -611,7 +621,7 @@ globalThis.send = function send(actor, message, reply) { throw Error(`Supplied actor had a return, but it's not a valid actor! ${actor[HEADER]}`) actor = header.replycc - send.return = header.reply + send_msg.return = header.reply } if (reply) { @@ -623,12 +633,12 @@ globalThis.send = function send(actor, message, reply) { delete replies[id] } }, REPLYTIMEOUT) - send.reply = id - send.replycc = $_.self + send_msg.reply = id + send_msg.replycc = $_.self } // Instead of sending immediately, queue it - actor_prep(actor,send); + actor_prep(actor, send_msg); } stone(send) @@ -785,8 +795,6 @@ if (!locator) { if (!locator) throw Error(`Main program ${_cell.args.program} could not be found`) -stone(globalThis) - $_.clock(_ => { // Get capabilities for the main program var file_info = shop.file_info ? shop.file_info(locator.path) : null diff --git a/internal/shop.cm b/internal/shop.cm index 60926b2f..6b5fd360 100644 --- a/internal/shop.cm +++ b/internal/shop.cm @@ -379,7 +379,16 @@ Shop.get_script_capabilities = function(path) { } function inject_env(inject) { + // Start with runtime functions from engine var env = {} + var rt = my$_.os ? my$_.os.runtime_env : null + if (rt) { + for (var k in rt) { + env[k] = rt[k] + } + } + + // Add capability injections for (var i = 0; i < length(inject); i++) { var inj = inject[i] var key = trim(inj, '$') @@ -391,6 +400,17 @@ function inject_env(inject) { function inject_bindings_code(inject) { var lines = [] + + // Runtime function bindings + var runtime_fns = ['logical', 'some', 'every', 'starts_with', 'ends_with', + 'actor', 'is_actor', 'log', 'send', + 'fallback', 'parallel', 'race', 'sequence'] + for (var i = 0; i < length(runtime_fns); i++) { + var fn = runtime_fns[i] + push(lines, `var ${fn} = env["${fn}"];`) + } + + // Capability bindings ($delay, $start, etc.) for (var i = 0; i < length(inject); i++) { var inj = inject[i] var key = trim(inj, '$') @@ -428,22 +448,21 @@ function resolve_mod_fn(path, pkg) { var inject = Shop.script_inject_for(file_info) var content = text(fd.slurp(path)) var script = script_form(path, content, file_pkg, inject); - + var obj = pull_from_cache(stone(blob(script))) if (obj) { var fn = js.compile_unblob(obj) - return js.eval_compile(fn) + return js.integrate(fn, null) } - + // Compile name is just for debug/stack traces -// var compile_name = pkg ? pkg + ':' + path : 'local:' + path var compile_name = path - + var fn = js.compile(compile_name, script) - + put_into_cache(stone(blob(script)), js.compile_blob(fn)) - - return js.eval_compile(fn) + + return js.integrate(fn, null) } // given a path and a package context diff --git a/source/cell.c b/source/cell.c index 57df65e9..a27f8280 100644 --- a/source/cell.c +++ b/source/cell.c @@ -121,13 +121,10 @@ JSValue js_math_use(JSContext *js); void script_startup(cell_rt *prt) { - JSRuntime *rt; - - rt = JS_NewRuntime(); - + JSRuntime *rt = JS_NewRuntime(); JSContext *js = JS_NewContextRaw(rt); JS_SetInterruptHandler(rt, (JSInterruptHandler *)actor_interrupt_cb, prt); - + JS_AddIntrinsicBaseObjects(js); JS_AddIntrinsicEval(js); JS_AddIntrinsicRegExp(js); @@ -139,38 +136,7 @@ void script_startup(cell_rt *prt) cell_rt *crt = JS_GetContextOpaque(js); JS_FreeValue(js, js_blob_use(js)); - JSValue globalThis = JS_GetGlobalObject(js); - - JSValue cell = JS_NewObject(js); - JS_SetPropertyStr(js,globalThis,"cell", cell); - - JSValue hidden_fn = JS_NewObject(js); - - JS_SetPropertyStr(js, cell, "hidden", hidden_fn); - JS_SetPropertyStr(js, hidden_fn, "os", js_os_use(js)); - - crt->actor_sym = JS_NewObject(js); - JS_SetPropertyStr(js, hidden_fn, "actorsym", JS_DupValue(js,crt->actor_sym)); - - if (crt->init_wota) { - JS_SetPropertyStr(js, hidden_fn, "init", wota2value(js, crt->init_wota)); - // init wota can now be freed - free(crt->init_wota); - crt->init_wota = NULL; - } - - // Store the core path for scripts to use - JSValue js_cell = JS_GetPropertyStr(js, globalThis, "cell"); - JSValue hidden = JS_GetPropertyStr(js, js_cell, "hidden"); - if (core_path) { - JS_SetPropertyStr(js, hidden, "core_path", JS_NewString(js, core_path)); - } - JS_FreeValue(js, hidden); - JS_FreeValue(js, js_cell); - - JS_FreeValue(js, globalThis); - - // Load engine.cm from the core directory + // Load and compile engine.cm size_t engine_size; char *data = load_core_file(ENGINE, &engine_size); if (!data) { @@ -178,9 +144,39 @@ void script_startup(cell_rt *prt) return; } - crt->state = ACTOR_RUNNING; - JSValue v = JS_Eval(js, data, engine_size, ENGINE, 0); + JSValue bytecode = JS_Compile(js, data, engine_size, ENGINE); free(data); + if (JS_IsException(bytecode)) { + uncaught_exception(js, bytecode); + return; + } + + // Create hidden environment + JSValue hidden_env = JS_NewObject(js); + JS_SetPropertyStr(js, hidden_env, "os", js_os_use(js)); + + crt->actor_sym = JS_NewObject(js); + JS_SetPropertyStr(js, hidden_env, "actorsym", JS_DupValue(js, crt->actor_sym)); + + // Always set init (even if null) + if (crt->init_wota) { + JS_SetPropertyStr(js, hidden_env, "init", wota2value(js, crt->init_wota)); + free(crt->init_wota); + crt->init_wota = NULL; + } else { + JS_SetPropertyStr(js, hidden_env, "init", JS_NULL); + } + + if (core_path) { + JS_SetPropertyStr(js, hidden_env, "core_path", JS_NewString(js, core_path)); + } + + // Stone the environment + hidden_env = JS_Stone(js, hidden_env); + + // Integrate and run + crt->state = ACTOR_RUNNING; + JSValue v = JS_Integrate(js, bytecode, hidden_env); uncaught_exception(js, v); crt->state = ACTOR_IDLE; set_actor_state(crt); @@ -286,55 +282,21 @@ static int run_eval(const char *script_or_file, int print_bytecode) int result = 0; - if (print_bytecode) { - /* Compile only, then dump and optionally execute */ - JSValue func = JS_Eval(ctx, script, strlen(script), filename, JS_EVAL_FLAG_COMPILE_ONLY); - if (JS_IsException(func)) { - uncaught_exception(ctx, func); - result = 1; - } else { - printf("=== Compiled Bytecode ===\n"); - JS_DumpFunctionBytecode(ctx, func); - - /* Link - resolve global references */ - JSValue linked = JS_LinkFunction(ctx, func); - if (JS_IsException(linked)) { - uncaught_exception(ctx, linked); - result = 1; - } else { - printf("\n=== Linked Bytecode ===\n"); - JS_DumpFunctionBytecode(ctx, linked); - - /* Now execute the linked bytecode */ - JSValue v = JS_EvalFunction(ctx, linked); - if (JS_IsException(v)) { - uncaught_exception(ctx, v); - result = 1; - } else { - JS_FreeValue(ctx, v); - } - } - } + JSValue bytecode = JS_Compile(ctx, script, strlen(script), filename); + if (JS_IsException(bytecode)) { + uncaught_exception(ctx, bytecode); + result = 1; } else { - /* Compile, link, execute */ - JSValue func = JS_Eval(ctx, script, strlen(script), filename, JS_EVAL_FLAG_COMPILE_ONLY); - if (JS_IsException(func)) { - uncaught_exception(ctx, func); + if (print_bytecode) { + printf("=== Compiled Bytecode ===\n"); + JS_DumpFunctionBytecode(ctx, bytecode); + } + JSValue v = JS_Integrate(ctx, bytecode, JS_NULL); + if (JS_IsException(v)) { + uncaught_exception(ctx, v); result = 1; } else { - JSValue linked = JS_LinkFunction(ctx, func); - if (JS_IsException(linked)) { - uncaught_exception(ctx, linked); - result = 1; - } else { - JSValue v = JS_EvalFunction(ctx, linked); - if (JS_IsException(v)) { - uncaught_exception(ctx, v); - result = 1; - } else { - JS_FreeValue(ctx, v); - } - } + JS_FreeValue(ctx, v); } } diff --git a/source/quickjs.c b/source/quickjs.c index e2f3ffc1..564ba28f 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -17254,18 +17254,24 @@ static JSValue JS_EvalFunctionInternal (JSContext *ctx, JSValue fun_obj, JSValue return ret_val; } -JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj) { - return JS_EvalFunctionInternal (ctx, fun_obj, ctx->global_obj, NULL); +/* Compile source code to bytecode without executing. + Returns unlinked bytecode on success, JS_EXCEPTION on error. + 'input' must be zero terminated i.e. input[input_len] = '\0'. */ +JSValue JS_Compile (JSContext *ctx, const char *input, size_t input_len, + const char *filename) { + return JS_EvalInternal (ctx, ctx->global_obj, input, input_len, filename, + JS_EVAL_FLAG_COMPILE_ONLY | JS_EVAL_FLAG_BACKTRACE_BARRIER, -1); } -/* Eval function with environment record for variable resolution. - The env must be a stoned record. Variables are resolved env first, - then global intrinsics. */ -JSValue JS_EvalFunctionEnv (JSContext *ctx, JSValue fun_obj, JSValue env) { +/* Link compiled bytecode with environment and execute. + The env should be a stoned record (or null for no env). + Variables resolve: env first, then global intrinsics. */ +JSValue JS_Integrate (JSContext *ctx, JSValue fun_obj, JSValue env) { JSValue ret_val; JSValue saved_env; uint32_t tag; JSGCRef env_ref, fun_ref; + JSFunctionBytecode *tpl, *linked_bc; tag = JS_VALUE_GET_TAG (fun_obj); /* JSFunctionBytecode uses OBJ_CODE type with JS_TAG_PTR */ @@ -17279,13 +17285,15 @@ JSValue JS_EvalFunctionEnv (JSContext *ctx, JSValue fun_obj, JSValue env) { JS_AddGCRef (ctx, &fun_ref); fun_ref.val = fun_obj; - /* Link with environment */ - JSValue linked = JS_LinkFunctionEnv (ctx, fun_ref.val, env_ref.val); - if (JS_IsException (linked)) { + /* Link bytecode with environment */ + tpl = (JSFunctionBytecode *)JS_VALUE_GET_PTR (fun_ref.val); + linked_bc = js_link_bytecode (ctx, tpl, env_ref.val); + if (!linked_bc) { JS_DeleteGCRef (ctx, &fun_ref); JS_DeleteGCRef (ctx, &env_ref); return JS_EXCEPTION; } + JSValue linked = JS_MKPTR (linked_bc); /* Update env from GC ref (may have moved) */ env = env_ref.val; @@ -17306,32 +17314,6 @@ JSValue JS_EvalFunctionEnv (JSContext *ctx, JSValue fun_obj, JSValue env) { return ret_val; } -/* Link compiled bytecode to context - resolves global references. - Returns linked bytecode on success, JS_EXCEPTION on link error. - The linked bytecode is a separate copy that can be modified. */ -JSValue JS_LinkFunction (JSContext *ctx, JSValue fun_obj) { - return JS_LinkFunctionEnv (ctx, fun_obj, JS_NULL); -} - -/* Link compiled bytecode with environment record for variable resolution. - Variables are resolved: env first, then global intrinsics. - Returns linked bytecode on success, JS_EXCEPTION on link error. */ -JSValue JS_LinkFunctionEnv (JSContext *ctx, JSValue fun_obj, JSValue env) { - if (JS_VALUE_GET_TAG (fun_obj) != JS_TAG_PTR) - return JS_ThrowTypeError (ctx, "bytecode function expected"); - - objhdr_t *hdr = (objhdr_t *)JS_VALUE_GET_PTR (fun_obj); - if (objhdr_type (*hdr) != OBJ_CODE) - return JS_ThrowTypeError (ctx, "bytecode function expected"); - - JSFunctionBytecode *tpl = (JSFunctionBytecode *)hdr; - JSFunctionBytecode *linked = js_link_bytecode (ctx, tpl, env); - if (!linked) - return JS_EXCEPTION; - - return JS_MKPTR (linked); -} - /* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ static JSValue __JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int flags, int scope_idx) { JSParseState s1, *s = &s1; @@ -17410,19 +17392,6 @@ static JSValue JS_EvalObject (JSContext *ctx, JSValue this_obj, JSValue val, int return ret; } -JSValue JS_EvalThis (JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int eval_flags) { - int eval_type = eval_flags & JS_EVAL_TYPE_MASK; - JSValue ret; - - assert (eval_type == JS_EVAL_TYPE_GLOBAL); - ret = JS_EvalInternal (ctx, this_obj, input, input_len, filename, eval_flags, -1); - return ret; -} - -JSValue JS_Eval (JSContext *ctx, const char *input, size_t input_len, const char *filename, int eval_flags) { - return JS_EvalThis (ctx, ctx->global_obj, input, input_len, filename, eval_flags); -} - /*******************************************************************/ /* object list */ @@ -24211,7 +24180,7 @@ static JSValue js_cell_eval (JSContext *ctx, JSValue this_val, int argc, JSValue } /* Compile the text */ - JSValue fun = JS_Eval (ctx, str, len, "", JS_EVAL_FLAG_COMPILE_ONLY); + JSValue fun = JS_Compile (ctx, str, len, ""); JS_FreeCString (ctx, str); if (JS_IsException (fun)) { JS_DeleteGCRef (ctx, &env_ref); @@ -24222,8 +24191,8 @@ static JSValue js_cell_eval (JSContext *ctx, JSValue this_val, int argc, JSValue env = env_ref.val; JS_DeleteGCRef (ctx, &env_ref); - /* Eval with environment */ - result = JS_EvalFunctionEnv (ctx, fun, env); + /* Integrate with environment */ + result = JS_Integrate (ctx, fun, env); return result; } diff --git a/source/quickjs.h b/source/quickjs.h index 825faee9..3dd5ec97 100644 --- a/source/quickjs.h +++ b/source/quickjs.h @@ -334,18 +334,13 @@ JS_IsShortFloat (JSValue v) { #define JS_DEFAULT_STACK_SIZE (1024 * 1024) #endif -/* JS_Eval() flags */ +/* Internal eval flags */ #define JS_EVAL_TYPE_GLOBAL (0 << 0) /* global code (default) */ #define JS_EVAL_TYPE_DIRECT (2 << 0) /* direct call (internal use) */ #define JS_EVAL_TYPE_INDIRECT (3 << 0) /* indirect call (internal use) */ #define JS_EVAL_TYPE_MASK (3 << 0) - -/* compile but do not run. The result is an object with a - JS_TAG_FUNCTION_BYTECODE or JS_TAG_MODULE tag. It can be executed - with JS_EvalFunction(). */ -#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) -/* don't include the stack frames before this eval in the Error() backtraces */ -#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) +#define JS_EVAL_FLAG_COMPILE_ONLY (1 << 5) /* internal use */ +#define JS_EVAL_FLAG_BACKTRACE_BARRIER (1 << 6) /* internal use */ typedef JSValue JSCFunction (JSContext *ctx, JSValue this_val, int argc, JSValue *argv); @@ -727,12 +722,17 @@ int JS_SetPropertyInt64 (JSContext *ctx, JSValue this_obj, int64_t idx, JSValue JSValue JS_GetOwnPropertyNames (JSContext *ctx, JSValue obj); JSValue JS_Call (JSContext *ctx, JSValue func_obj, JSValue this_obj, int argc, JSValue *argv); -/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ -JSValue JS_Eval (JSContext *ctx, const char *input, size_t input_len, - const char *filename, int eval_flags); -/* same as JS_Eval() but with an explicit 'this_obj' parameter */ -JSValue JS_EvalThis (JSContext *ctx, JSValue this_obj, const char *input, - size_t input_len, const char *filename, int eval_flags); + +/* Compile source code to bytecode without executing. + 'input' must be zero terminated i.e. input[input_len] = '\0'. + Returns unlinked bytecode on success, JS_EXCEPTION on error. */ +JSValue JS_Compile (JSContext *ctx, const char *input, size_t input_len, + const char *filename); + +/* Link compiled bytecode with environment and execute. + env should be stoned record or null. + Variables resolve: env first, then global intrinsics. */ +JSValue JS_Integrate (JSContext *ctx, JSValue bytecode, JSValue env); JSValue JS_GetGlobalObject (JSContext *ctx); void JS_SetOpaque (JSValue obj, void *opaque); void *JS_GetOpaque (JSValue obj, JSClassID class_id); @@ -779,27 +779,9 @@ uint8_t *JS_WriteObject2 (JSContext *ctx, size_t *psize, JSValue obj, #define JS_READ_OBJ_REFERENCE (1 << 3) /* allow object references */ JSValue JS_ReadObject (JSContext *ctx, const uint8_t *buf, size_t buf_len, int flags); -/* instantiate and evaluate a bytecode function. Only used when - reading a script or module with JS_ReadObject() */ -JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj); - -/* Eval function with environment record for variable resolution. - The env must be a stoned record. Variables are resolved env first, - then global intrinsics. */ -JSValue JS_EvalFunctionEnv (JSContext *ctx, JSValue fun_obj, JSValue env); - /* Dump bytecode of a compiled function (for debugging) */ void JS_DumpFunctionBytecode (JSContext *ctx, JSValue func_val); -/* Link compiled bytecode to context - resolves global references. - Returns linked bytecode on success, JS_EXCEPTION on link error. */ -JSValue JS_LinkFunction (JSContext *ctx, JSValue func_val); - -/* Link compiled bytecode with environment record for variable resolution. - Variables are resolved: env first, then global intrinsics. - Returns linked bytecode on success, JS_EXCEPTION on link error. */ -JSValue JS_LinkFunctionEnv (JSContext *ctx, JSValue func_val, JSValue env); - /* C function definition */ typedef enum JSCFunctionEnum { JS_CFUNC_generic,