get_global

This commit is contained in:
2026-02-03 17:35:24 -06:00
parent 43faad95e0
commit f1117bbd41
3 changed files with 176 additions and 12 deletions

View File

@@ -262,23 +262,48 @@ static int run_eval(const char *script, int print_bytecode)
uncaught_exception(ctx, func); uncaught_exception(ctx, func);
result = 1; result = 1;
} else { } else {
printf("=== Compiled Bytecode ===\n");
JS_DumpFunctionBytecode(ctx, func); JS_DumpFunctionBytecode(ctx, func);
/* Now execute it */
JSValue v = JS_EvalFunction(ctx, func); /* Link - resolve global references */
if (JS_IsException(v)) { JSValue linked = JS_LinkFunction(ctx, func);
uncaught_exception(ctx, v); if (JS_IsException(linked)) {
uncaught_exception(ctx, linked);
result = 1; result = 1;
} else { } else {
JS_FreeValue(ctx, v); 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);
}
} }
} }
} else { } else {
JSValue v = JS_Eval(ctx, script, strlen(script), "<eval>", 0); /* Compile, link, execute */
if (JS_IsException(v)) { JSValue func = JS_Eval(ctx, script, strlen(script), "<eval>", JS_EVAL_FLAG_COMPILE_ONLY);
uncaught_exception(ctx, v); if (JS_IsException(func)) {
uncaught_exception(ctx, func);
result = 1; result = 1;
} else { } else {
JS_FreeValue(ctx, v); 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);
}
}
} }
} }

View File

@@ -9011,9 +9011,8 @@ restart:
CASE (OP_get_global_slot) : { CASE (OP_get_global_slot) : {
int slot = get_u16 (pc); pc += 2; int slot = get_u16 (pc); pc += 2;
(void)slot; JSRecord *global = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_obj);
JS_ThrowInternalError (ctx, "OP_get_global_slot not yet implemented"); *sp++ = global->slots[slot].val;
goto exception;
} }
BREAK; BREAK;
@@ -9480,6 +9479,123 @@ static const JSOpCode opcode_info[OP_COUNT + (OP_TEMP_END - OP_TEMP_START)] = {
#define short_opcode_info(op) opcode_info[op] #define short_opcode_info(op) opcode_info[op]
#endif #endif
/* Clone bytecode and resolve OP_get_var to OP_get_global_slot.
Returns new bytecode on success, NULL on link error.
The linked bytecode is a separate allocation that can be modified. */
static JSFunctionBytecode *js_link_bytecode (JSContext *ctx,
JSFunctionBytecode *tpl) {
/* Calculate total size of bytecode allocation */
int function_size;
int cpool_offset, vardefs_offset, closure_var_offset, byte_code_offset;
if (tpl->has_debug) {
function_size = sizeof (JSFunctionBytecode);
} else {
function_size = offsetof (JSFunctionBytecode, debug);
}
cpool_offset = function_size;
function_size += tpl->cpool_count * sizeof (JSValue);
vardefs_offset = function_size;
if (tpl->vardefs) {
function_size += (tpl->arg_count + tpl->var_count) * sizeof (JSVarDef);
}
closure_var_offset = function_size;
function_size += tpl->closure_var_count * sizeof (JSClosureVar);
byte_code_offset = function_size;
function_size += tpl->byte_code_len;
/* Allocate and copy */
JSFunctionBytecode *linked = pjs_malloc (function_size);
if (!linked) return NULL;
/* Copy base structure */
if (tpl->has_debug) {
memcpy (linked, tpl, sizeof (JSFunctionBytecode));
} else {
memcpy (linked, tpl, offsetof (JSFunctionBytecode, debug));
}
/* Fix up self pointers */
if (tpl->cpool_count > 0) {
linked->cpool = (JSValue *)((uint8_t *)linked + cpool_offset);
memcpy (linked->cpool, tpl->cpool, tpl->cpool_count * sizeof (JSValue));
}
if (tpl->vardefs) {
linked->vardefs = (JSVarDef *)((uint8_t *)linked + vardefs_offset);
memcpy (linked->vardefs, tpl->vardefs,
(tpl->arg_count + tpl->var_count) * sizeof (JSVarDef));
}
if (tpl->closure_var_count > 0) {
linked->closure_var = (JSClosureVar *)((uint8_t *)linked + closure_var_offset);
memcpy (linked->closure_var, tpl->closure_var,
tpl->closure_var_count * sizeof (JSClosureVar));
}
linked->byte_code_buf = (uint8_t *)linked + byte_code_offset;
memcpy (linked->byte_code_buf, tpl->byte_code_buf, tpl->byte_code_len);
/* Mark as writable (for patching) */
linked->read_only_bytecode = 0;
/* Walk bytecode and patch OP_get_var -> OP_get_global_slot */
uint8_t *bc = linked->byte_code_buf;
int pos = 0;
while (pos < linked->byte_code_len) {
uint8_t op = bc[pos];
int len = short_opcode_info (op).size;
if (op == OP_get_var || op == OP_get_var_undef) {
/* Get the variable name from cpool */
uint32_t cpool_idx = get_u32 (bc + pos + 1);
JSValue name = linked->cpool[cpool_idx];
/* Try global_obj first (for built-ins like 'print') */
JSRecord *global = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_obj);
int slot = rec_find_slot (global, name);
if (slot > 0) {
bc[pos] = OP_get_global_slot;
put_u16 (bc + pos + 1, (uint16_t)slot);
bc[pos + 3] = OP_nop;
bc[pos + 4] = OP_nop;
pos += len;
continue;
}
/* Try global_var_obj (let/const declarations) */
JSRecord *global_var = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_var_obj);
slot = rec_find_slot (global_var, name);
if (slot > 0) {
bc[pos] = OP_get_global_slot;
put_u16 (bc + pos + 1, (uint16_t)slot);
bc[pos + 3] = OP_nop;
bc[pos + 4] = OP_nop;
pos += len;
continue;
}
/* Link error: variable not found */
if (op == OP_get_var) {
char buf[64];
JS_ThrowReferenceError (ctx, "'%s' is not defined",
JS_KeyGetStr (ctx, buf, sizeof (buf), name));
pjs_free (linked);
return NULL;
}
/* OP_get_var_undef is ok - leaves as is for runtime check */
}
pos += len;
}
return linked;
}
static __exception int next_token (JSParseState *s); static __exception int next_token (JSParseState *s);
static void free_token (JSParseState *s, JSToken *token) { static void free_token (JSParseState *s, JSToken *token) {
@@ -18002,6 +18118,25 @@ JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj) {
return JS_EvalFunctionInternal (ctx, fun_obj, ctx->global_obj, NULL, NULL); return JS_EvalFunctionInternal (ctx, fun_obj, ctx->global_obj, NULL, NULL);
} }
/* 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) {
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);
if (!linked)
return JS_EXCEPTION;
return JS_MKPTR (linked);
}
/* 'input' must be zero terminated i.e. input[input_len] = '\0'. */ /* '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) { 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; JSParseState s1, *s = &s1;

View File

@@ -786,6 +786,10 @@ JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj);
/* Dump bytecode of a compiled function (for debugging) */ /* Dump bytecode of a compiled function (for debugging) */
void JS_DumpFunctionBytecode (JSContext *ctx, JSValue func_val); 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);
/* C function definition */ /* C function definition */
typedef enum JSCFunctionEnum { typedef enum JSCFunctionEnum {
JS_CFUNC_generic, JS_CFUNC_generic,