optimize lref

This commit is contained in:
2026-02-03 21:37:17 -06:00
parent fd5e4d155e
commit dc348d023f
2 changed files with 78 additions and 46 deletions

View File

@@ -231,13 +231,43 @@ static int run_test_suite(size_t heap_size)
}
/* Run an immediate script string */
static int run_eval(const char *script, int print_bytecode)
static int run_eval(const char *script_or_file, int print_bytecode)
{
if (!find_cell_shop()) return 1;
/* Check if argument is a file path */
struct stat st;
char *script = NULL;
char *allocated_script = NULL;
const char *filename = "<eval>";
if (stat(script_or_file, &st) == 0 && S_ISREG(st.st_mode)) {
/* It's a file, read its contents */
FILE *f = fopen(script_or_file, "r");
if (!f) {
printf("Failed to open file: %s\n", script_or_file);
return 1;
}
allocated_script = malloc(st.st_size + 1);
if (!allocated_script) {
fclose(f);
printf("Failed to allocate memory for script\n");
return 1;
}
size_t read_size = fread(allocated_script, 1, st.st_size, f);
fclose(f);
allocated_script[read_size] = '\0';
script = allocated_script;
filename = script_or_file;
} else {
/* Treat as inline script */
script = (char *)script_or_file;
}
JSRuntime *rt = JS_NewRuntime();
if (!rt) {
printf("Failed to create JS runtime\n");
free(allocated_script);
return 1;
}
@@ -245,6 +275,7 @@ static int run_eval(const char *script, int print_bytecode)
if (!ctx) {
printf("Failed to create JS context\n");
JS_FreeRuntime(rt);
free(allocated_script);
return 1;
}
@@ -257,7 +288,7 @@ static int run_eval(const char *script, int print_bytecode)
if (print_bytecode) {
/* Compile only, then dump and optionally execute */
JSValue func = JS_Eval(ctx, script, strlen(script), "<eval>", JS_EVAL_FLAG_COMPILE_ONLY);
JSValue func = JS_Eval(ctx, script, strlen(script), filename, JS_EVAL_FLAG_COMPILE_ONLY);
if (JS_IsException(func)) {
uncaught_exception(ctx, func);
result = 1;
@@ -286,7 +317,7 @@ static int run_eval(const char *script, int print_bytecode)
}
} else {
/* Compile, link, execute */
JSValue func = JS_Eval(ctx, script, strlen(script), "<eval>", JS_EVAL_FLAG_COMPILE_ONLY);
JSValue func = JS_Eval(ctx, script, strlen(script), filename, JS_EVAL_FLAG_COMPILE_ONLY);
if (JS_IsException(func)) {
uncaught_exception(ctx, func);
result = 1;
@@ -309,6 +340,7 @@ static int run_eval(const char *script, int print_bytecode)
JS_FreeContext(ctx);
JS_FreeRuntime(rt);
free(allocated_script);
return result;
}

View File

@@ -12007,7 +12007,8 @@ static __exception int get_lvalue (JSParseState *s, int *popcode, int *pscope, J
|| js_key_equal_str (name, "new.target")) {
goto invalid_lvalue;
}
depth = 2; /* will generate OP_get_ref_value */
/* Variable lvalue: depth=0, no reference objects on stack */
depth = 0;
break;
}
case OP_get_field: {
@@ -12040,15 +12041,11 @@ static __exception int get_lvalue (JSParseState *s, int *popcode, int *pscope, J
/* get the value but keep the object/fields on the stack */
switch (opcode) {
case OP_scope_get_var:
label = new_label (s);
if (label < 0) return -1;
emit_op (s, OP_scope_make_ref);
/* For variable lvalues, just re-emit the get to have the value on stack.
No reference objects needed - put_lvalue will emit scope_put_var directly. */
emit_op (s, OP_scope_get_var);
emit_key (s, name);
emit_u32 (s, label);
emit_u16 (s, scope);
update_label (fd, label, 1);
emit_op (s, OP_get_ref_value);
opcode = OP_get_ref_value;
break;
case OP_get_field:
emit_op (s, OP_get_field2);
@@ -12060,27 +12057,13 @@ static __exception int get_lvalue (JSParseState *s, int *popcode, int *pscope, J
default:
abort ();
}
} else {
switch (opcode) {
case OP_scope_get_var:
label = new_label (s);
if (label < 0) return -1;
emit_op (s, OP_scope_make_ref);
emit_key (s, name);
emit_u32 (s, label);
emit_u16 (s, scope);
update_label (fd, label, 1);
opcode = OP_get_ref_value;
break;
default:
break;
}
}
/* For variable lvalues without keep, nothing needs to be emitted.
put_lvalue will handle the store with just the value on stack. */
*popcode = opcode;
*pscope = scope;
/* name has refcount for OP_get_field and OP_get_ref_value,
and JS_NULL for other opcodes */
/* name is set for OP_get_field, OP_scope_get_var, and JS_NULL for array_el */
*pname = name;
*plabel = label;
if (pdepth) *pdepth = depth;
@@ -12097,9 +12080,31 @@ typedef enum {
} PutLValueEnum;
/* name has a live reference. 'is_let' is only used with opcode =
OP_scope_get_var which is never generated by get_lvalue(). */
OP_scope_get_var for variable lvalues (no reference objects on stack). */
static void put_lvalue (JSParseState *s, int opcode, int scope, JSValue name, int label, PutLValueEnum special, BOOL is_let) {
switch (opcode) {
case OP_scope_get_var:
/* depth = 0 for variable lvalues - no reference objects on stack */
switch (special) {
case PUT_LVALUE_NOKEEP:
case PUT_LVALUE_NOKEEP_DEPTH:
/* val -> (store, nothing left) */
break;
case PUT_LVALUE_KEEP_TOP:
/* val -> val (dup before store) */
emit_op (s, OP_dup);
break;
case PUT_LVALUE_KEEP_SECOND:
/* v0 v -> v0 (store v, keep v0) - for postfix ++/-- */
/* stack: old_val new_val, store new_val, result is old_val */
break;
case PUT_LVALUE_NOKEEP_BOTTOM:
/* val -> (same as NOKEEP for depth=0) */
break;
default:
abort ();
}
break;
case OP_get_field:
/* depth = 1 */
switch (special) {
@@ -12120,11 +12125,7 @@ static void put_lvalue (JSParseState *s, int opcode, int scope, JSValue name, in
}
break;
case OP_get_array_el:
case OP_get_ref_value:
/* depth = 2 */
if (opcode == OP_get_ref_value) {
emit_label (s, label);
}
switch (special) {
case PUT_LVALUE_NOKEEP:
emit_op (s, OP_nop); /* will trigger optimization */
@@ -12149,9 +12150,7 @@ static void put_lvalue (JSParseState *s, int opcode, int scope, JSValue name, in
}
switch (opcode) {
case OP_scope_get_var: /* val -- */
assert (special == PUT_LVALUE_NOKEEP
|| special == PUT_LVALUE_NOKEEP_DEPTH);
case OP_scope_get_var: /* val -> */
emit_op (s, is_let ? OP_scope_put_var_init : OP_scope_put_var);
emit_key (s, name); /* emit cpool index */
emit_u16 (s, scope);
@@ -12163,9 +12162,6 @@ static void put_lvalue (JSParseState *s, int opcode, int scope, JSValue name, in
case OP_get_array_el:
emit_op (s, OP_put_array_el);
break;
case OP_get_ref_value:
emit_op (s, OP_put_ref_value);
break;
default:
abort ();
}
@@ -13225,7 +13221,7 @@ next:
}
if (op == '=') {
if (opcode == OP_get_ref_value && js_key_equal (name, name0)) {
if (opcode == OP_scope_get_var && js_key_equal (name, name0)) {
set_object_name (s, name);
}
} else {
@@ -13266,11 +13262,16 @@ next:
return -1;
}
if (opcode == OP_get_ref_value && js_key_equal (name, name0)) {
if (opcode == OP_scope_get_var && js_key_equal (name, name0)) {
set_object_name (s, name);
}
/* For depth=0 (variable lvalues), dup to keep result on stack after put.
For depth>=1, insert to put value below reference objects. */
switch (depth_lvalue) {
case 0:
emit_op (s, OP_dup);
break;
case 1:
emit_op (s, OP_insert2);
break;
@@ -13284,14 +13285,12 @@ next:
abort ();
}
/* XXX: we disable the OP_put_ref_value optimization by not
using put_lvalue() otherwise depth_lvalue is not correct */
put_lvalue (s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, FALSE);
label2 = emit_goto (s, OP_goto, -1);
emit_label (s, label1);
/* remove the lvalue stack entries */
/* remove the lvalue stack entries (none for depth=0 variables) */
while (depth_lvalue != 0) {
emit_op (s, OP_nip);
depth_lvalue--;
@@ -16196,7 +16195,8 @@ static void compute_pc2line_info (JSFunctionDef *s) {
static RelocEntry *add_reloc (JSContext *ctx, LabelSlot *ls, uint32_t addr, int size) {
RelocEntry *re;
re = js_malloc (ctx, sizeof (*re));
(void)ctx;
re = pjs_malloc (sizeof (*re));
if (!re) return NULL;
re->addr = addr;
re->size = size;
@@ -16451,7 +16451,7 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
put_u8 (bc_out.buf + re->addr, diff);
break;
}
js_free (ctx, re);
pjs_free (re);
}
ls->first_reloc = NULL;
} break;