optimize lref
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user