get_global
This commit is contained in:
@@ -262,23 +262,48 @@ static int run_eval(const char *script, int print_bytecode)
|
||||
uncaught_exception(ctx, func);
|
||||
result = 1;
|
||||
} else {
|
||||
printf("=== Compiled Bytecode ===\n");
|
||||
JS_DumpFunctionBytecode(ctx, func);
|
||||
/* Now execute it */
|
||||
JSValue v = JS_EvalFunction(ctx, func);
|
||||
if (JS_IsException(v)) {
|
||||
uncaught_exception(ctx, v);
|
||||
|
||||
/* Link - resolve global references */
|
||||
JSValue linked = JS_LinkFunction(ctx, func);
|
||||
if (JS_IsException(linked)) {
|
||||
uncaught_exception(ctx, linked);
|
||||
result = 1;
|
||||
} 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 {
|
||||
JSValue v = JS_Eval(ctx, script, strlen(script), "<eval>", 0);
|
||||
if (JS_IsException(v)) {
|
||||
uncaught_exception(ctx, v);
|
||||
/* Compile, link, execute */
|
||||
JSValue func = JS_Eval(ctx, script, strlen(script), "<eval>", JS_EVAL_FLAG_COMPILE_ONLY);
|
||||
if (JS_IsException(func)) {
|
||||
uncaught_exception(ctx, func);
|
||||
result = 1;
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
141
source/quickjs.c
141
source/quickjs.c
@@ -9011,9 +9011,8 @@ restart:
|
||||
|
||||
CASE (OP_get_global_slot) : {
|
||||
int slot = get_u16 (pc); pc += 2;
|
||||
(void)slot;
|
||||
JS_ThrowInternalError (ctx, "OP_get_global_slot not yet implemented");
|
||||
goto exception;
|
||||
JSRecord *global = (JSRecord *)JS_VALUE_GET_OBJ (ctx->global_obj);
|
||||
*sp++ = global->slots[slot].val;
|
||||
}
|
||||
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]
|
||||
#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 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);
|
||||
}
|
||||
|
||||
/* 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'. */
|
||||
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;
|
||||
|
||||
@@ -786,6 +786,10 @@ JSValue JS_EvalFunction (JSContext *ctx, JSValue fun_obj);
|
||||
/* 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);
|
||||
|
||||
/* C function definition */
|
||||
typedef enum JSCFunctionEnum {
|
||||
JS_CFUNC_generic,
|
||||
|
||||
Reference in New Issue
Block a user