diff --git a/source/cell.c b/source/cell.c index f99da595..57df65e9 100644 --- a/source/cell.c +++ b/source/cell.c @@ -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 = ""; + + 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), "", 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), "", 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; } diff --git a/source/quickjs.c b/source/quickjs.c index 9370ea20..64bfab83 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -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;