lexer
This commit is contained in:
284
source/quickjs.c
284
source/quickjs.c
@@ -82,7 +82,7 @@
|
||||
*/
|
||||
// #define DUMP_BYTECODE (1)
|
||||
/* dump GC summary: old/new heap, recovery %, heap growth */
|
||||
#define DUMP_GC
|
||||
// #define DUMP_GC
|
||||
/* dump detailed GC: roots, scanning, object traversal (implies DUMP_GC) */
|
||||
// #define DUMP_GC_DETAIL
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
@@ -97,7 +97,7 @@
|
||||
// #define DUMP_ROPE_REBALANCE
|
||||
|
||||
/* test the GC by forcing it before each object allocation */
|
||||
//#define FORCE_GC_AT_MALLOC
|
||||
#define FORCE_GC_AT_MALLOC
|
||||
|
||||
#define POISON_HEAP
|
||||
/* POISON_HEAP: Use ASan's memory poisoning to detect stale pointer access */
|
||||
@@ -856,6 +856,9 @@ struct JSContext {
|
||||
|
||||
JSInterruptHandler *interrupt_handler;
|
||||
void *interrupt_opaque;
|
||||
|
||||
/* Parser state (for GC to scan cpool during parsing) */
|
||||
struct JSFunctionDef *current_parse_fd;
|
||||
};
|
||||
|
||||
/* ============================================================
|
||||
@@ -1864,6 +1867,7 @@ static JSValue js_cell_number_max (JSContext *ctx, JSValue this_val, int argc, J
|
||||
static JSValue js_cell_number_remainder (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||
static JSValue js_cell_object (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||
static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||
static JSValue js_print (JSContext *ctx, JSValue this_val, int argc, JSValue *argv);
|
||||
JSValue JS_ThrowOutOfMemory (JSContext *ctx);
|
||||
static JSVarRef *get_var_ref (JSContext *ctx, JSStackFrame *sf, int var_idx, BOOL is_arg);
|
||||
static JSValue JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *input, size_t input_len, const char *filename, int flags, int scope_idx);
|
||||
@@ -1958,6 +1962,50 @@ void js_free (JSContext *ctx, void *ptr) {
|
||||
(void)ptr;
|
||||
}
|
||||
|
||||
/* Parser memory functions - use system allocator to avoid GC issues */
|
||||
static void *pjs_malloc (size_t size) {
|
||||
return malloc (size);
|
||||
}
|
||||
|
||||
static void *pjs_mallocz (size_t size) {
|
||||
void *ptr = malloc (size);
|
||||
if (ptr) memset (ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static void *pjs_realloc (void *ptr, size_t size) {
|
||||
return realloc (ptr, size);
|
||||
}
|
||||
|
||||
static void pjs_free (void *ptr) {
|
||||
free (ptr);
|
||||
}
|
||||
|
||||
/* Parser-specific resize array using system allocator */
|
||||
static no_inline int pjs_realloc_array (void **parray, int elem_size, int *psize, int req_size) {
|
||||
int new_size;
|
||||
void *new_array;
|
||||
size_t old_size;
|
||||
new_size = max_int (req_size, *psize * 3 / 2);
|
||||
old_size = (size_t)(*psize) * elem_size;
|
||||
new_array = pjs_realloc (*parray, (size_t)new_size * elem_size);
|
||||
if (!new_array) return -1;
|
||||
/* Zero newly allocated memory */
|
||||
if (new_size > *psize) {
|
||||
memset ((char *)new_array + old_size, 0, (size_t)(new_size - *psize) * elem_size);
|
||||
}
|
||||
*psize = new_size;
|
||||
*parray = new_array;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pjs_resize_array (void **parray, int elem_size, int *psize, int req_size) {
|
||||
if (unlikely (req_size > *psize))
|
||||
return pjs_realloc_array (parray, elem_size, psize, req_size);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static no_inline int js_realloc_array (JSContext *ctx, void **parray, int elem_size, int *psize, int req_size) {
|
||||
int new_size;
|
||||
void *new_array;
|
||||
@@ -2422,7 +2470,19 @@ static void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8
|
||||
JSFunction *fn = (JSFunction *)ptr;
|
||||
/* Scan the function name */
|
||||
fn->name = gc_copy_value (ctx, fn->name, from_base, from_end, to_base, to_free, to_end);
|
||||
/* Note: function_bytecode and var_refs are allocated via js_malloc, not bump allocator */
|
||||
/* Scan bytecode's cpool - it contains JSValues that may reference GC objects */
|
||||
if (fn->kind == JS_FUNC_KIND_BYTECODE && fn->u.func.function_bytecode) {
|
||||
JSFunctionBytecode *b = fn->u.func.function_bytecode;
|
||||
/* Scan cpool entries */
|
||||
for (int i = 0; i < b->cpool_count; i++) {
|
||||
b->cpool[i] = gc_copy_value (ctx, b->cpool[i], from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
/* Scan func_name and filename */
|
||||
b->func_name = gc_copy_value (ctx, b->func_name, from_base, from_end, to_base, to_free, to_end);
|
||||
if (b->has_debug) {
|
||||
b->debug.filename = gc_copy_value (ctx, b->debug.filename, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OBJ_TEXT:
|
||||
@@ -2446,6 +2506,34 @@ static void gc_scan_object (JSContext *ctx, void *ptr, uint8_t *from_base, uint8
|
||||
}
|
||||
}
|
||||
|
||||
/* Forward declaration - defined after JSFunctionDef */
|
||||
static void gc_scan_parser_cpool (JSContext *ctx, uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end);
|
||||
|
||||
/* Scan OBJ_CODE cpool for bytecode objects outside GC heap */
|
||||
static void gc_scan_bytecode_cpool (JSContext *ctx, JSValue v, uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end) {
|
||||
if (!JS_IsPtr (v)) return;
|
||||
void *ptr = JS_VALUE_GET_PTR (v);
|
||||
if (ptr_in_range (ptr, from_base, from_end)) return; /* On GC heap, handled normally */
|
||||
if (is_stone_ptr (ctx, ptr)) return; /* Stone memory */
|
||||
|
||||
/* Check if this is an OBJ_CODE outside GC heap */
|
||||
objhdr_t hdr = *(objhdr_t *)ptr;
|
||||
if (objhdr_type (hdr) == OBJ_CODE) {
|
||||
JSFunctionBytecode *bc = (JSFunctionBytecode *)ptr;
|
||||
/* Scan cpool entries */
|
||||
for (int i = 0; i < bc->cpool_count; i++) {
|
||||
bc->cpool[i] = gc_copy_value (ctx, bc->cpool[i], from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
/* Scan func_name and filename */
|
||||
bc->func_name = gc_copy_value (ctx, bc->func_name, from_base, from_end, to_base, to_free, to_end);
|
||||
if (bc->has_debug) {
|
||||
bc->debug.filename = gc_copy_value (ctx, bc->debug.filename, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Cheney copying GC - collect garbage and compact live objects
|
||||
allow_grow: if true, grow heap when <20% recovered; if false, keep same size */
|
||||
static int ctx_gc (JSContext *ctx, int allow_grow) {
|
||||
@@ -2509,6 +2597,12 @@ static int ctx_gc (JSContext *ctx, int allow_grow) {
|
||||
#endif
|
||||
ctx->eval_obj = gc_copy_value (ctx, ctx->eval_obj, from_base, from_end, to_base, &to_free, to_end);
|
||||
|
||||
/* Copy current exception if pending */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: current_exception\n"); fflush(stdout);
|
||||
#endif
|
||||
rt->current_exception = gc_copy_value (ctx, rt->current_exception, from_base, from_end, to_base, &to_free, to_end);
|
||||
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: native_error_proto\n"); fflush(stdout);
|
||||
#endif
|
||||
@@ -2542,11 +2636,24 @@ static int ctx_gc (JSContext *ctx, int allow_grow) {
|
||||
frame->this_obj = gc_copy_value (ctx, frame->this_obj, from_base, from_end, to_base, &to_free, to_end);
|
||||
}
|
||||
|
||||
/* Copy JSStackFrame chain (C stack frames) */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: current_stack_frame chain\n"); fflush(stdout);
|
||||
#endif
|
||||
for (JSStackFrame *sf = rt->current_stack_frame; sf != NULL; sf = sf->prev_frame) {
|
||||
sf->cur_func = gc_copy_value (ctx, sf->cur_func, from_base, from_end, to_base, &to_free, to_end);
|
||||
/* Also scan bytecode cpool if it's a bytecode object outside GC heap */
|
||||
gc_scan_bytecode_cpool (ctx, sf->cur_func, from_base, from_end, to_base, &to_free, to_end);
|
||||
/* Scan arg_buf and var_buf - they point into value_stack which is scanned separately,
|
||||
but we should update cur_func which may be a function/bytecode */
|
||||
}
|
||||
|
||||
/* Copy JS_PUSH_VALUE/JS_POP_VALUE roots */
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
printf(" roots: top_gc_ref\n"); fflush(stdout);
|
||||
#endif
|
||||
for (JSGCRef *ref = ctx->top_gc_ref; ref != NULL; ref = ref->prev) {
|
||||
gc_scan_bytecode_cpool (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
||||
ref->val = gc_copy_value (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
||||
}
|
||||
|
||||
@@ -2555,9 +2662,15 @@ static int ctx_gc (JSContext *ctx, int allow_grow) {
|
||||
printf(" roots: last_gc_ref\n"); fflush(stdout);
|
||||
#endif
|
||||
for (JSGCRef *ref = ctx->last_gc_ref; ref != NULL; ref = ref->prev) {
|
||||
gc_scan_bytecode_cpool (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
||||
ref->val = gc_copy_value (ctx, ref->val, from_base, from_end, to_base, &to_free, to_end);
|
||||
}
|
||||
|
||||
/* Scan parser's cpool (if parsing is in progress) */
|
||||
if (ctx->current_parse_fd) {
|
||||
gc_scan_parser_cpool (ctx, from_base, from_end, to_base, &to_free, to_end);
|
||||
}
|
||||
|
||||
/* Cheney scan: scan copied objects to find more references */
|
||||
uint8_t *scan = to_base;
|
||||
#ifdef DUMP_GC_DETAIL
|
||||
@@ -4095,26 +4208,35 @@ static void build_backtrace (JSContext *ctx, JSValue error_obj, const char *file
|
||||
const char *func_name_str;
|
||||
const char *str1;
|
||||
JSRecord *p;
|
||||
JSGCRef err_ref;
|
||||
|
||||
if (!JS_IsObject (error_obj))
|
||||
return; /* protection in the out of memory case */
|
||||
|
||||
/* Protect error_obj from GC during backtrace building */
|
||||
JS_PushGCRef (ctx, &err_ref);
|
||||
err_ref.val = error_obj;
|
||||
|
||||
js_dbuf_init (ctx, &dbuf);
|
||||
if (filename) {
|
||||
dbuf_printf (&dbuf, " at %s", filename);
|
||||
if (line_num != -1) dbuf_printf (&dbuf, ":%d:%d", line_num, col_num);
|
||||
dbuf_putc (&dbuf, '\n');
|
||||
str = JS_NewString (ctx, filename);
|
||||
if (JS_IsException (str)) return;
|
||||
if (JS_IsException (str)) {
|
||||
JS_PopGCRef (ctx, &err_ref);
|
||||
return;
|
||||
}
|
||||
/* Note: SpiderMonkey does that, could update once there is a standard */
|
||||
JSValue key_fileName = JS_KEY_STR (ctx, "fileName");
|
||||
JSValue key_lineNumber = JS_KEY_STR (ctx, "lineNumber");
|
||||
JSValue key_columnNumber = JS_KEY_STR (ctx, "columnNumber");
|
||||
if (JS_SetPropertyInternal (ctx, error_obj, key_fileName, str) < 0
|
||||
|| JS_SetPropertyInternal (ctx, error_obj, key_lineNumber, JS_NewInt32 (ctx, line_num))
|
||||
if (JS_SetPropertyInternal (ctx, err_ref.val, key_fileName, str) < 0
|
||||
|| JS_SetPropertyInternal (ctx, err_ref.val, key_lineNumber, JS_NewInt32 (ctx, line_num))
|
||||
< 0
|
||||
|| JS_SetPropertyInternal (ctx, error_obj, key_columnNumber, JS_NewInt32 (ctx, col_num))
|
||||
|| JS_SetPropertyInternal (ctx, err_ref.val, key_columnNumber, JS_NewInt32 (ctx, col_num))
|
||||
< 0) {
|
||||
JS_PopGCRef (ctx, &err_ref);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4163,7 +4285,8 @@ static void build_backtrace (JSContext *ctx, JSValue error_obj, const char *file
|
||||
else
|
||||
str = JS_NewString (ctx, (char *)dbuf.buf);
|
||||
dbuf_free (&dbuf);
|
||||
JS_SetPropertyInternal (ctx, error_obj, JS_KEY_stack, str);
|
||||
JS_SetPropertyInternal (ctx, err_ref.val, JS_KEY_stack, str);
|
||||
JS_PopGCRef (ctx, &err_ref);
|
||||
}
|
||||
|
||||
/* Note: it is important that no exception is returned by this function */
|
||||
@@ -6618,12 +6741,20 @@ static JSValue js_closure (JSContext *ctx, JSValue bfunc, JSVarRef **cur_var_ref
|
||||
JSFunctionBytecode *b;
|
||||
JSValue func_obj;
|
||||
JSFunction *f;
|
||||
JSGCRef bfunc_ref;
|
||||
|
||||
/* Protect bfunc from GC during function allocation */
|
||||
JS_PUSH_VALUE (ctx, bfunc);
|
||||
|
||||
b = JS_VALUE_GET_PTR (bfunc);
|
||||
func_obj = js_new_function (ctx, JS_FUNC_KIND_BYTECODE);
|
||||
if (JS_IsException (func_obj)) {
|
||||
JS_POP_VALUE (ctx, bfunc);
|
||||
return JS_EXCEPTION;
|
||||
}
|
||||
|
||||
JS_POP_VALUE (ctx, bfunc);
|
||||
b = JS_VALUE_GET_PTR (bfunc);
|
||||
|
||||
func_obj = js_closure2 (ctx, func_obj, b, cur_var_refs, sf);
|
||||
if (JS_IsException (func_obj)) {
|
||||
/* bfunc has been freed */
|
||||
@@ -6853,8 +6984,8 @@ static JSValue JS_CallInternal (JSContext *caller_ctx, JSValue func_obj, JSValue
|
||||
return JS_ThrowTypeError (caller_ctx, "not a function");
|
||||
}
|
||||
f = JS_VALUE_GET_FUNCTION (func_obj);
|
||||
/* Strict arity enforcement: too many arguments throws */
|
||||
if (unlikely (argc > f->length)) {
|
||||
/* Strict arity enforcement: too many arguments throws (length < 0 means variadic) */
|
||||
if (unlikely (f->length >= 0 && argc > f->length)) {
|
||||
char buf[KEY_GET_STR_BUF_SIZE];
|
||||
return JS_ThrowTypeError (
|
||||
caller_ctx, "too many arguments for %s: expected %d, got %d", JS_KeyGetStr (caller_ctx, buf, KEY_GET_STR_BUF_SIZE, f->name), f->length, argc);
|
||||
@@ -7167,7 +7298,6 @@ restart:
|
||||
ret_val = JS_CallInternal (ctx, call_argv[-1], JS_NULL, call_argc, call_argv, 0);
|
||||
if (unlikely (JS_IsException (ret_val))) goto exception;
|
||||
if (opcode == OP_tail_call) goto done;
|
||||
for (i = -1; i < call_argc; i++)
|
||||
sp -= call_argc + 1;
|
||||
*sp++ = ret_val;
|
||||
}
|
||||
@@ -9115,6 +9245,33 @@ typedef struct JSFunctionDef {
|
||||
int source_len;
|
||||
} JSFunctionDef;
|
||||
|
||||
/* Scan a single JSFunctionDef's cpool and recursively scan its children */
|
||||
static void gc_scan_parser_fd (JSContext *ctx, JSFunctionDef *fd,
|
||||
uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end) {
|
||||
if (!fd) return;
|
||||
/* Scan constant pool */
|
||||
for (int i = 0; i < fd->cpool_count; i++) {
|
||||
fd->cpool[i] = gc_copy_value (ctx, fd->cpool[i], from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
/* Scan func_name */
|
||||
fd->func_name = gc_copy_value (ctx, fd->func_name, from_base, from_end, to_base, to_free, to_end);
|
||||
/* Scan filename */
|
||||
fd->filename = gc_copy_value (ctx, fd->filename, from_base, from_end, to_base, to_free, to_end);
|
||||
/* Recursively scan child functions */
|
||||
struct list_head *el;
|
||||
list_for_each (el, &fd->child_list) {
|
||||
JSFunctionDef *child = list_entry (el, JSFunctionDef, link);
|
||||
gc_scan_parser_fd (ctx, child, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan parser's cpool values during GC - called when parsing is in progress */
|
||||
static void gc_scan_parser_cpool (JSContext *ctx, uint8_t *from_base, uint8_t *from_end,
|
||||
uint8_t *to_base, uint8_t **to_free, uint8_t *to_end) {
|
||||
gc_scan_parser_fd (ctx, ctx->current_parse_fd, from_base, from_end, to_base, to_free, to_end);
|
||||
}
|
||||
|
||||
typedef struct JSToken {
|
||||
int val;
|
||||
const uint8_t *ptr; /* position in the source */
|
||||
@@ -10854,7 +11011,7 @@ static int new_label_fd (JSFunctionDef *fd) {
|
||||
int label;
|
||||
LabelSlot *ls;
|
||||
|
||||
if (js_resize_array (fd->ctx, (void *)&fd->label_slots, sizeof (fd->label_slots[0]), &fd->label_size, fd->label_count + 1))
|
||||
if (pjs_resize_array ((void **)&fd->label_slots, sizeof (fd->label_slots[0]), &fd->label_size, fd->label_count + 1))
|
||||
return -1;
|
||||
label = fd->label_count++;
|
||||
ls = &fd->label_slots[label];
|
||||
@@ -10909,7 +11066,8 @@ static int emit_goto (JSParseState *s, int opcode, int label) {
|
||||
|
||||
/* return the constant pool index. 'val' is not duplicated. */
|
||||
static int fd_cpool_add (JSContext *ctx, JSFunctionDef *fd, JSValue val) {
|
||||
if (js_resize_array (ctx, (void *)&fd->cpool, sizeof (fd->cpool[0]), &fd->cpool_size, fd->cpool_count + 1))
|
||||
(void)ctx;
|
||||
if (pjs_resize_array ((void **)&fd->cpool, sizeof (fd->cpool[0]), &fd->cpool_size, fd->cpool_count + 1))
|
||||
return -1;
|
||||
fd->cpool[fd->cpool_count++] = val;
|
||||
return fd->cpool_count - 1;
|
||||
@@ -11015,11 +11173,11 @@ static int push_scope (JSParseState *s) {
|
||||
/* XXX: potential arithmetic overflow */
|
||||
new_size = max_int (fd->scope_count + 1, fd->scope_size * 3 / 2);
|
||||
if (fd->scopes == fd->def_scope_array) {
|
||||
new_buf = js_realloc (s->ctx, NULL, new_size * sizeof (*fd->scopes));
|
||||
new_buf = pjs_malloc (new_size * sizeof (*fd->scopes));
|
||||
if (!new_buf) return -1;
|
||||
memcpy (new_buf, fd->scopes, fd->scope_count * sizeof (*fd->scopes));
|
||||
} else {
|
||||
new_buf = js_realloc (s->ctx, fd->scopes, new_size * sizeof (*fd->scopes));
|
||||
new_buf = pjs_realloc (fd->scopes, new_size * sizeof (*fd->scopes));
|
||||
if (!new_buf) return -1;
|
||||
}
|
||||
fd->scopes = new_buf;
|
||||
@@ -11073,7 +11231,7 @@ static int add_var (JSContext *ctx, JSFunctionDef *fd, JSValue name) {
|
||||
JS_ThrowInternalError (ctx, "too many local variables");
|
||||
return -1;
|
||||
}
|
||||
if (js_resize_array (ctx, (void **)&fd->vars, sizeof (fd->vars[0]), &fd->var_size, fd->var_count + 1))
|
||||
if (pjs_resize_array ((void **)&fd->vars, sizeof (fd->vars[0]), &fd->var_size, fd->var_count + 1))
|
||||
return -1;
|
||||
vd = &fd->vars[fd->var_count++];
|
||||
memset (vd, 0, sizeof (*vd));
|
||||
@@ -11113,7 +11271,7 @@ static int add_arg (JSContext *ctx, JSFunctionDef *fd, JSValue name) {
|
||||
JS_ThrowInternalError (ctx, "too many arguments");
|
||||
return -1;
|
||||
}
|
||||
if (js_resize_array (ctx, (void **)&fd->args, sizeof (fd->args[0]), &fd->arg_size, fd->arg_count + 1))
|
||||
if (pjs_resize_array ((void **)&fd->args, sizeof (fd->args[0]), &fd->arg_size, fd->arg_count + 1))
|
||||
return -1;
|
||||
vd = &fd->args[fd->arg_count++];
|
||||
memset (vd, 0, sizeof (*vd));
|
||||
@@ -11125,8 +11283,9 @@ static int add_arg (JSContext *ctx, JSFunctionDef *fd, JSValue name) {
|
||||
/* add a global variable definition */
|
||||
static JSGlobalVar *add_global_var (JSContext *ctx, JSFunctionDef *s, JSValue name) {
|
||||
JSGlobalVar *hf;
|
||||
(void)ctx;
|
||||
|
||||
if (js_resize_array (ctx, (void **)&s->global_vars, sizeof (s->global_vars[0]), &s->global_var_size, s->global_var_count + 1))
|
||||
if (pjs_resize_array ((void **)&s->global_vars, sizeof (s->global_vars[0]), &s->global_var_size, s->global_var_count + 1))
|
||||
return NULL;
|
||||
hf = &s->global_vars[s->global_var_count++];
|
||||
hf->cpool_idx = -1;
|
||||
@@ -13936,7 +14095,7 @@ static JSFunctionDef *
|
||||
js_new_function_def (JSContext *ctx, JSFunctionDef *parent, BOOL is_eval, BOOL is_func_expr, const char *filename, const uint8_t *source_ptr, GetLineColCache *get_line_col_cache) {
|
||||
JSFunctionDef *fd;
|
||||
|
||||
fd = js_mallocz (ctx, sizeof (*fd));
|
||||
fd = pjs_mallocz (sizeof (*fd));
|
||||
if (!fd) return NULL;
|
||||
|
||||
fd->ctx = ctx;
|
||||
@@ -14027,42 +14186,43 @@ static void js_free_function_def (JSContext *ctx, JSFunctionDef *fd) {
|
||||
|
||||
free_bytecode_atoms (ctx->rt, fd->byte_code.buf, fd->byte_code.size, fd->use_short_opcodes);
|
||||
dbuf_free (&fd->byte_code);
|
||||
js_free (ctx, fd->jump_slots);
|
||||
js_free (ctx, fd->label_slots);
|
||||
js_free (ctx, fd->line_number_slots);
|
||||
pjs_free (fd->jump_slots);
|
||||
pjs_free (fd->label_slots);
|
||||
pjs_free (fd->line_number_slots);
|
||||
|
||||
for (i = 0; i < fd->cpool_count; i++) {
|
||||
}
|
||||
js_free (ctx, fd->cpool);
|
||||
pjs_free (fd->cpool);
|
||||
|
||||
|
||||
for (i = 0; i < fd->var_count; i++) {
|
||||
}
|
||||
js_free (ctx, fd->vars);
|
||||
pjs_free (fd->vars);
|
||||
for (i = 0; i < fd->arg_count; i++) {
|
||||
}
|
||||
js_free (ctx, fd->args);
|
||||
pjs_free (fd->args);
|
||||
|
||||
for (i = 0; i < fd->global_var_count; i++) {
|
||||
}
|
||||
js_free (ctx, fd->global_vars);
|
||||
pjs_free (fd->global_vars);
|
||||
|
||||
for (i = 0; i < fd->closure_var_count; i++) {
|
||||
JSClosureVar *cv = &fd->closure_var[i];
|
||||
(void)cv;
|
||||
}
|
||||
js_free (ctx, fd->closure_var);
|
||||
pjs_free (fd->closure_var);
|
||||
|
||||
if (fd->scopes != fd->def_scope_array) js_free (ctx, fd->scopes);
|
||||
if (fd->scopes != fd->def_scope_array) pjs_free (fd->scopes);
|
||||
|
||||
dbuf_free (&fd->pc2line);
|
||||
|
||||
js_free (ctx, fd->source);
|
||||
pjs_free (fd->source);
|
||||
|
||||
if (fd->parent) {
|
||||
/* remove in parent list */
|
||||
list_del (&fd->link);
|
||||
}
|
||||
js_free (ctx, fd);
|
||||
pjs_free (fd);
|
||||
}
|
||||
|
||||
#ifdef DUMP_BYTECODE
|
||||
@@ -14461,7 +14621,7 @@ static int add_closure_var (JSContext *ctx, JSFunctionDef *s, BOOL is_local, BOO
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (js_resize_array (ctx, (void **)&s->closure_var, sizeof (s->closure_var[0]), &s->closure_var_size, s->closure_var_count + 1))
|
||||
if (pjs_resize_array ((void **)&s->closure_var, sizeof (s->closure_var[0]), &s->closure_var_size, s->closure_var_count + 1))
|
||||
return -1;
|
||||
cv = &s->closure_var[s->closure_var_count++];
|
||||
cv->is_local = is_local;
|
||||
@@ -16092,13 +16252,13 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
#if SHORT_OPCODES
|
||||
if (s->jump_size) {
|
||||
s->jump_slots
|
||||
= js_mallocz (s->ctx, sizeof (*s->jump_slots) * s->jump_size);
|
||||
= pjs_mallocz (sizeof (*s->jump_slots) * s->jump_size);
|
||||
if (s->jump_slots == NULL) return -1;
|
||||
}
|
||||
#endif
|
||||
/* XXX: Should skip this phase if not generating SHORT_OPCODES */
|
||||
if (s->line_number_size && !s->strip_debug) {
|
||||
s->line_number_slots = js_mallocz (s->ctx, sizeof (*s->line_number_slots) * s->line_number_size);
|
||||
s->line_number_slots = pjs_mallocz (sizeof (*s->line_number_slots) * s->line_number_size);
|
||||
if (s->line_number_slots == NULL) return -1;
|
||||
s->line_number_last = s->source_pos;
|
||||
s->line_number_last_pc = 0;
|
||||
@@ -16725,14 +16885,14 @@ static __exception int resolve_labels (JSContext *ctx, JSFunctionDef *s) {
|
||||
}
|
||||
}
|
||||
}
|
||||
js_free (ctx, s->jump_slots);
|
||||
pjs_free (s->jump_slots);
|
||||
s->jump_slots = NULL;
|
||||
#endif
|
||||
js_free (ctx, s->label_slots);
|
||||
pjs_free (s->label_slots);
|
||||
s->label_slots = NULL;
|
||||
/* XXX: should delay until copying to runtime bytecode function */
|
||||
compute_pc2line_info (s);
|
||||
js_free (ctx, s->line_number_slots);
|
||||
pjs_free (s->line_number_slots);
|
||||
s->line_number_slots = NULL;
|
||||
/* set the new byte code */
|
||||
dbuf_free (&s->byte_code);
|
||||
@@ -16792,7 +16952,7 @@ static __exception int ss_check (JSContext *ctx, StackSizeState *s, int pos, int
|
||||
s->catch_pos_tab[pos] = catch_pos;
|
||||
|
||||
/* queue the new PC to explore */
|
||||
if (js_resize_array (ctx, (void **)&s->pc_stack, sizeof (s->pc_stack[0]), &s->pc_stack_size, s->pc_stack_len + 1))
|
||||
if (pjs_resize_array ((void **)&s->pc_stack, sizeof (s->pc_stack[0]), &s->pc_stack_size, s->pc_stack_len + 1))
|
||||
return -1;
|
||||
s->pc_stack[s->pc_stack_len++] = pos;
|
||||
return 0;
|
||||
@@ -16808,12 +16968,12 @@ static __exception int compute_stack_size (JSContext *ctx, JSFunctionDef *fd, in
|
||||
s->bc_len = fd->byte_code.size;
|
||||
/* bc_len > 0 */
|
||||
s->stack_level_tab
|
||||
= js_malloc (ctx, sizeof (s->stack_level_tab[0]) * s->bc_len);
|
||||
= pjs_malloc (sizeof (s->stack_level_tab[0]) * s->bc_len);
|
||||
if (!s->stack_level_tab) return -1;
|
||||
for (i = 0; i < s->bc_len; i++)
|
||||
s->stack_level_tab[i] = 0xffff;
|
||||
s->pc_stack = NULL;
|
||||
s->catch_pos_tab = js_malloc (ctx, sizeof (s->catch_pos_tab[0]) * s->bc_len);
|
||||
s->catch_pos_tab = pjs_malloc (sizeof (s->catch_pos_tab[0]) * s->bc_len);
|
||||
if (!s->catch_pos_tab) goto fail;
|
||||
|
||||
s->stack_len_max = 0;
|
||||
@@ -16942,15 +17102,15 @@ static __exception int compute_stack_size (JSContext *ctx, JSFunctionDef *fd, in
|
||||
if (ss_check (ctx, s, pos_next, op, stack_len, catch_pos)) goto fail;
|
||||
done_insn:;
|
||||
}
|
||||
js_free (ctx, s->pc_stack);
|
||||
js_free (ctx, s->catch_pos_tab);
|
||||
js_free (ctx, s->stack_level_tab);
|
||||
pjs_free (s->pc_stack);
|
||||
pjs_free (s->catch_pos_tab);
|
||||
pjs_free (s->stack_level_tab);
|
||||
*pstack_size = s->stack_len_max;
|
||||
return 0;
|
||||
fail:
|
||||
js_free (ctx, s->pc_stack);
|
||||
js_free (ctx, s->catch_pos_tab);
|
||||
js_free (ctx, s->stack_level_tab);
|
||||
pjs_free (s->pc_stack);
|
||||
pjs_free (s->catch_pos_tab);
|
||||
pjs_free (s->stack_level_tab);
|
||||
*pstack_size = 0;
|
||||
return -1;
|
||||
}
|
||||
@@ -17049,7 +17209,8 @@ static JSValue js_create_function (JSContext *ctx, JSFunctionDef *fd) {
|
||||
byte_code_offset = function_size;
|
||||
function_size += fd->byte_code.size;
|
||||
|
||||
b = js_mallocz (ctx, function_size);
|
||||
/* Bytecode is immutable - allocate outside GC heap */
|
||||
b = pjs_mallocz (function_size);
|
||||
if (!b) goto fail;
|
||||
b->header = objhdr_make (0, OBJ_CODE, false, false, false, false);
|
||||
|
||||
@@ -17104,20 +17265,21 @@ static JSValue js_create_function (JSContext *ctx, JSFunctionDef *fd) {
|
||||
// DynBuf pc2line;
|
||||
// compute_pc2line_info(fd, &pc2line);
|
||||
// js_free(ctx, fd->line_number_slots)
|
||||
b->debug.pc2line_buf = js_realloc (ctx, fd->pc2line.buf, fd->pc2line.size);
|
||||
if (!b->debug.pc2line_buf) b->debug.pc2line_buf = fd->pc2line.buf;
|
||||
/* pc2line.buf is allocated by dbuf (system realloc), so just use it directly */
|
||||
b->debug.pc2line_buf = fd->pc2line.buf;
|
||||
fd->pc2line.buf = NULL; /* Transfer ownership */
|
||||
b->debug.pc2line_len = fd->pc2line.size;
|
||||
b->debug.source = fd->source;
|
||||
b->debug.source_len = fd->source_len;
|
||||
}
|
||||
if (fd->scopes != fd->def_scope_array) js_free (ctx, fd->scopes);
|
||||
if (fd->scopes != fd->def_scope_array) pjs_free (fd->scopes);
|
||||
|
||||
b->closure_var_count = fd->closure_var_count;
|
||||
if (b->closure_var_count) {
|
||||
b->closure_var = (void *)((uint8_t *)b + closure_var_offset);
|
||||
memcpy (b->closure_var, fd->closure_var, b->closure_var_count * sizeof (*b->closure_var));
|
||||
}
|
||||
js_free (ctx, fd->closure_var);
|
||||
pjs_free (fd->closure_var);
|
||||
fd->closure_var = NULL;
|
||||
|
||||
b->has_prototype = fd->has_prototype;
|
||||
@@ -17740,6 +17902,7 @@ static JSValue __JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *
|
||||
fd = js_new_function_def (ctx, NULL, TRUE, FALSE, filename, s->buf_start, &s->get_line_col_cache);
|
||||
if (!fd) goto fail1;
|
||||
s->cur_func = fd;
|
||||
ctx->current_parse_fd = fd; /* Set GC root for parser's cpool */
|
||||
fd->eval_type = eval_type;
|
||||
fd->has_this_binding = (eval_type != JS_EVAL_TYPE_DIRECT);
|
||||
fd->js_mode = js_mode;
|
||||
@@ -17755,11 +17918,13 @@ static JSValue __JS_EvalInternal (JSContext *ctx, JSValue this_obj, const char *
|
||||
if (err) {
|
||||
fail:
|
||||
free_token (s, &s->token);
|
||||
ctx->current_parse_fd = NULL; /* Clear GC root before freeing */
|
||||
js_free_function_def (ctx, fd);
|
||||
goto fail1;
|
||||
}
|
||||
|
||||
/* create the function object and all the enclosed functions */
|
||||
ctx->current_parse_fd = NULL; /* Clear GC root - fd ownership transfers to js_create_function */
|
||||
fun_obj = js_create_function (ctx, fd);
|
||||
if (JS_IsException (fun_obj)) goto fail1;
|
||||
/* Could add a flag to avoid resolution if necessary */
|
||||
@@ -22544,6 +22709,20 @@ static JSValue js_cell_text_format (JSContext *ctx, JSValue this_val, int argc,
|
||||
return pretext_end (ctx, result);
|
||||
}
|
||||
|
||||
/* print(args...) - print arguments to stdout */
|
||||
static JSValue js_print (JSContext *ctx, JSValue this_val, int argc, JSValue *argv) {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
const char *str = JS_ToCString (ctx, argv[i]);
|
||||
if (str) {
|
||||
fputs (str, stdout);
|
||||
JS_FreeCString (ctx, str);
|
||||
}
|
||||
if (i < argc - 1) fputc (' ', stdout);
|
||||
}
|
||||
fputc ('\n', stdout);
|
||||
return JS_NULL;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* array function and sub-functions
|
||||
* ----------------------------------------------------------------------------
|
||||
@@ -25377,6 +25556,9 @@ void JS_AddIntrinsicBaseObjects (JSContext *ctx) {
|
||||
js_set_global_cfunc(ctx, "push", js_cell_push, 2);
|
||||
js_set_global_cfunc(ctx, "pop", js_cell_pop, 1);
|
||||
js_set_global_cfunc(ctx, "meme", js_cell_meme, 2);
|
||||
|
||||
/* I/O functions */
|
||||
js_set_global_cfunc(ctx, "print", js_print, -1); /* variadic: length < 0 means no arg limit */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user