mirror of
https://github.com/bellard/quickjs.git
synced 2025-11-17 11:05:26 +03:00
- Closure optimization (go from quadratic to linear time when the number
of closure variables is large) - Separated JSVarDef and JSBytecodeVarDef to simplify the code and save memory - fixed debug info stripping with global variables
This commit is contained in:
443
quickjs.c
443
quickjs.c
@@ -328,7 +328,7 @@ typedef struct JSStackFrame {
|
|||||||
JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
|
JSValue cur_func; /* current function, JS_UNDEFINED if the frame is detached */
|
||||||
JSValue *arg_buf; /* arguments */
|
JSValue *arg_buf; /* arguments */
|
||||||
JSValue *var_buf; /* variables */
|
JSValue *var_buf; /* variables */
|
||||||
struct list_head var_ref_list; /* list of JSVarRef.var_ref_link */
|
struct JSVarRef **var_refs; /* references to arguments or local variables */
|
||||||
const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
|
const uint8_t *cur_pc; /* only used in bytecode functions : PC of the
|
||||||
instruction after the call */
|
instruction after the call */
|
||||||
int arg_count;
|
int arg_count;
|
||||||
@@ -388,8 +388,8 @@ typedef struct JSVarRef {
|
|||||||
union {
|
union {
|
||||||
JSValue value; /* used when is_detached = TRUE */
|
JSValue value; /* used when is_detached = TRUE */
|
||||||
struct {
|
struct {
|
||||||
struct list_head var_ref_link; /* JSStackFrame.var_ref_list list */
|
uint16_t var_ref_idx; /* index in JSStackFrame.var_refs[] */
|
||||||
struct JSAsyncFunctionState *async_func; /* != NULL if async stack frame */
|
JSStackFrame *stack_frame;
|
||||||
}; /* used when is_detached = FALSE */
|
}; /* used when is_detached = FALSE */
|
||||||
};
|
};
|
||||||
} JSVarRef;
|
} JSVarRef;
|
||||||
@@ -563,7 +563,6 @@ typedef struct JSClosureVar {
|
|||||||
uint8_t is_lexical : 1; /* lexical variable */
|
uint8_t is_lexical : 1; /* lexical variable */
|
||||||
uint8_t is_const : 1; /* const variable (is_lexical = 1 if is_const = 1 */
|
uint8_t is_const : 1; /* const variable (is_lexical = 1 if is_const = 1 */
|
||||||
uint8_t var_kind : 4; /* see JSVarKindEnum */
|
uint8_t var_kind : 4; /* see JSVarKindEnum */
|
||||||
/* 8 bits available */
|
|
||||||
uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
|
uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
|
||||||
parent function. otherwise: index to a closure
|
parent function. otherwise: index to a closure
|
||||||
variable of the parent function */
|
variable of the parent function */
|
||||||
@@ -573,11 +572,6 @@ typedef struct JSClosureVar {
|
|||||||
#define ARG_SCOPE_INDEX 1
|
#define ARG_SCOPE_INDEX 1
|
||||||
#define ARG_SCOPE_END (-2)
|
#define ARG_SCOPE_END (-2)
|
||||||
|
|
||||||
typedef struct JSVarScope {
|
|
||||||
int parent; /* index into fd->scopes of the enclosing scope */
|
|
||||||
int first; /* index into fd->vars of the last variable in this scope */
|
|
||||||
} JSVarScope;
|
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
/* XXX: add more variable kinds here instead of using bit fields */
|
/* XXX: add more variable kinds here instead of using bit fields */
|
||||||
JS_VAR_NORMAL,
|
JS_VAR_NORMAL,
|
||||||
@@ -594,35 +588,23 @@ typedef enum {
|
|||||||
JS_VAR_GLOBAL_FUNCTION_DECL, /* global function definition, only in JSVarDef */
|
JS_VAR_GLOBAL_FUNCTION_DECL, /* global function definition, only in JSVarDef */
|
||||||
} JSVarKindEnum;
|
} JSVarKindEnum;
|
||||||
|
|
||||||
/* XXX: could use a different structure in bytecode functions to save
|
typedef struct JSBytecodeVarDef {
|
||||||
memory */
|
|
||||||
typedef struct JSVarDef {
|
|
||||||
JSAtom var_name;
|
JSAtom var_name;
|
||||||
/* index into fd->scopes of this variable lexical scope */
|
/* index into JSFunctionBytecode.vars of the next variable in the same or
|
||||||
int scope_level;
|
enclosing lexical scope
|
||||||
/* during compilation:
|
|
||||||
- if scope_level = 0: scope in which the variable is defined
|
|
||||||
- if scope_level != 0: index into fd->vars of the next
|
|
||||||
variable in the same or enclosing lexical scope
|
|
||||||
in a bytecode function:
|
|
||||||
index into fd->vars of the next
|
|
||||||
variable in the same or enclosing lexical scope
|
|
||||||
*/
|
*/
|
||||||
int scope_next;
|
int scope_next; /* XXX: store on 16 bits */
|
||||||
uint8_t is_const : 1;
|
uint8_t is_const : 1;
|
||||||
uint8_t is_lexical : 1;
|
uint8_t is_lexical : 1;
|
||||||
uint8_t is_captured : 1;
|
uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */
|
||||||
uint8_t is_static_private : 1; /* only used during private class field parsing */
|
uint8_t has_scope: 1; /* true if JSVarDef.scope_level != 0 */
|
||||||
uint8_t var_kind : 4; /* see JSVarKindEnum */
|
uint8_t var_kind : 4; /* see JSVarKindEnum */
|
||||||
/* only used during compilation: function pool index for lexical
|
/* If is_captured = TRUE, provides, the index of the corresponding
|
||||||
variables with var_kind =
|
JSVarRef on stack. It would be more compact to have a separate
|
||||||
JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
|
table with the corresponding inverted table but it requires
|
||||||
the definition of the 'var' variables (they have scope_level =
|
more modifications in the code. */
|
||||||
0) */
|
uint16_t var_ref_idx;
|
||||||
int func_pool_idx : 24; /* only used during compilation : index in
|
} JSBytecodeVarDef;
|
||||||
the constant pool for hoisted function
|
|
||||||
definition */
|
|
||||||
} JSVarDef;
|
|
||||||
|
|
||||||
/* for the encoding of the pc2line table */
|
/* for the encoding of the pc2line table */
|
||||||
#define PC2LINE_BASE (-1)
|
#define PC2LINE_BASE (-1)
|
||||||
@@ -657,12 +639,13 @@ typedef struct JSFunctionBytecode {
|
|||||||
uint8_t *byte_code_buf; /* (self pointer) */
|
uint8_t *byte_code_buf; /* (self pointer) */
|
||||||
int byte_code_len;
|
int byte_code_len;
|
||||||
JSAtom func_name;
|
JSAtom func_name;
|
||||||
JSVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
|
JSBytecodeVarDef *vardefs; /* arguments + local variables (arg_count + var_count) (self pointer) */
|
||||||
JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
|
JSClosureVar *closure_var; /* list of variables in the closure (self pointer) */
|
||||||
uint16_t arg_count;
|
uint16_t arg_count;
|
||||||
uint16_t var_count;
|
uint16_t var_count;
|
||||||
uint16_t defined_arg_count; /* for length function property */
|
uint16_t defined_arg_count; /* for length function property */
|
||||||
uint16_t stack_size; /* maximum stack size */
|
uint16_t stack_size; /* maximum stack size */
|
||||||
|
uint16_t var_ref_count; /* number of local variable references */
|
||||||
JSContext *realm; /* function realm */
|
JSContext *realm; /* function realm */
|
||||||
JSValue *cpool; /* constant pool (self pointer) */
|
JSValue *cpool; /* constant pool (self pointer) */
|
||||||
int cpool_count;
|
int cpool_count;
|
||||||
@@ -744,6 +727,7 @@ typedef struct JSAsyncFunctionState {
|
|||||||
frame is no longer valid */
|
frame is no longer valid */
|
||||||
JSValue resolving_funcs[2]; /* only used in JS async functions */
|
JSValue resolving_funcs[2]; /* only used in JS async functions */
|
||||||
JSStackFrame frame;
|
JSStackFrame frame;
|
||||||
|
/* arg_buf, var_buf, stack_buf and var_refs follow */
|
||||||
} JSAsyncFunctionState;
|
} JSAsyncFunctionState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -5721,9 +5705,13 @@ static void free_var_ref(JSRuntime *rt, JSVarRef *var_ref)
|
|||||||
if (var_ref->is_detached) {
|
if (var_ref->is_detached) {
|
||||||
JS_FreeValueRT(rt, var_ref->value);
|
JS_FreeValueRT(rt, var_ref->value);
|
||||||
} else {
|
} else {
|
||||||
list_del(&var_ref->var_ref_link); /* still on the stack */
|
JSStackFrame *sf = var_ref->stack_frame;
|
||||||
if (var_ref->async_func)
|
assert(sf->var_refs[var_ref->var_ref_idx] == var_ref);
|
||||||
async_func_free(rt, var_ref->async_func);
|
sf->var_refs[var_ref->var_ref_idx] = NULL;
|
||||||
|
if (sf->js_mode & JS_MODE_ASYNC) {
|
||||||
|
JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
|
||||||
|
async_func_free(rt, async_func);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
remove_gc_object(&var_ref->header);
|
remove_gc_object(&var_ref->header);
|
||||||
js_free_rt(rt, var_ref);
|
js_free_rt(rt, var_ref);
|
||||||
@@ -6175,8 +6163,12 @@ static void mark_children(JSRuntime *rt, JSGCObjectHeader *gp,
|
|||||||
JSVarRef *var_ref = (JSVarRef *)gp;
|
JSVarRef *var_ref = (JSVarRef *)gp;
|
||||||
if (var_ref->is_detached) {
|
if (var_ref->is_detached) {
|
||||||
JS_MarkValue(rt, *var_ref->pvalue, mark_func);
|
JS_MarkValue(rt, *var_ref->pvalue, mark_func);
|
||||||
} else if (var_ref->async_func) {
|
} else {
|
||||||
mark_func(rt, &var_ref->async_func->header);
|
JSStackFrame *sf = var_ref->stack_frame;
|
||||||
|
if (sf->js_mode & JS_MODE_ASYNC) {
|
||||||
|
JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
|
||||||
|
mark_func(rt, &async_func->header);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -16513,25 +16505,37 @@ static JSVarRef *js_create_var_ref(JSContext *ctx, BOOL is_lexical)
|
|||||||
return var_ref;
|
return var_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
|
static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf, int var_idx,
|
||||||
int var_idx, BOOL is_arg)
|
BOOL is_arg)
|
||||||
{
|
{
|
||||||
|
JSObject *p;
|
||||||
|
JSFunctionBytecode *b;
|
||||||
JSVarRef *var_ref;
|
JSVarRef *var_ref;
|
||||||
struct list_head *el;
|
|
||||||
JSValue *pvalue;
|
JSValue *pvalue;
|
||||||
|
int var_ref_idx;
|
||||||
if (is_arg)
|
JSBytecodeVarDef *vd;
|
||||||
|
|
||||||
|
p = JS_VALUE_GET_OBJ(sf->cur_func);
|
||||||
|
b = p->u.func.function_bytecode;
|
||||||
|
|
||||||
|
if (is_arg) {
|
||||||
|
vd = &b->vardefs[var_idx];
|
||||||
pvalue = &sf->arg_buf[var_idx];
|
pvalue = &sf->arg_buf[var_idx];
|
||||||
else
|
} else {
|
||||||
|
vd = &b->vardefs[b->arg_count + var_idx];
|
||||||
pvalue = &sf->var_buf[var_idx];
|
pvalue = &sf->var_buf[var_idx];
|
||||||
|
|
||||||
list_for_each(el, &sf->var_ref_list) {
|
|
||||||
var_ref = list_entry(el, JSVarRef, var_ref_link);
|
|
||||||
if (var_ref->pvalue == pvalue) {
|
|
||||||
var_ref->header.ref_count++;
|
|
||||||
return var_ref;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
assert(vd->is_captured);
|
||||||
|
var_ref_idx = vd->var_ref_idx;
|
||||||
|
assert(var_ref_idx < b->var_ref_count);
|
||||||
|
var_ref = sf->var_refs[var_ref_idx];
|
||||||
|
if (var_ref) {
|
||||||
|
/* reference to the already created local variable */
|
||||||
|
assert(var_ref->pvalue == pvalue);
|
||||||
|
var_ref->header.ref_count++;
|
||||||
|
return var_ref;
|
||||||
|
}
|
||||||
|
|
||||||
/* create a new one */
|
/* create a new one */
|
||||||
var_ref = js_malloc(ctx, sizeof(JSVarRef));
|
var_ref = js_malloc(ctx, sizeof(JSVarRef));
|
||||||
if (!var_ref)
|
if (!var_ref)
|
||||||
@@ -16541,8 +16545,11 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
|
|||||||
var_ref->is_detached = FALSE;
|
var_ref->is_detached = FALSE;
|
||||||
var_ref->is_lexical = FALSE;
|
var_ref->is_lexical = FALSE;
|
||||||
var_ref->is_const = FALSE;
|
var_ref->is_const = FALSE;
|
||||||
list_add_tail(&var_ref->var_ref_link, &sf->var_ref_list);
|
var_ref->var_ref_idx = var_ref_idx;
|
||||||
|
var_ref->stack_frame = sf;
|
||||||
|
sf->var_refs[var_ref_idx] = var_ref;
|
||||||
if (sf->js_mode & JS_MODE_ASYNC) {
|
if (sf->js_mode & JS_MODE_ASYNC) {
|
||||||
|
JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
|
||||||
/* The stack frame is detached and may be destroyed at any
|
/* The stack frame is detached and may be destroyed at any
|
||||||
time so its reference count must be increased. Calling
|
time so its reference count must be increased. Calling
|
||||||
close_var_refs() when destroying the stack frame is not
|
close_var_refs() when destroying the stack frame is not
|
||||||
@@ -16551,10 +16558,7 @@ static JSVarRef *get_var_ref(JSContext *ctx, JSStackFrame *sf,
|
|||||||
the JSVarRef of async functions during the GC. It would
|
the JSVarRef of async functions during the GC. It would
|
||||||
have the advantage of allowing the release of unused stack
|
have the advantage of allowing the release of unused stack
|
||||||
frames in a cycle. */
|
frames in a cycle. */
|
||||||
var_ref->async_func = container_of(sf, JSAsyncFunctionState, frame);
|
async_func->header.ref_count++;
|
||||||
var_ref->async_func->header.ref_count++;
|
|
||||||
} else {
|
|
||||||
var_ref->async_func = NULL;
|
|
||||||
}
|
}
|
||||||
var_ref->pvalue = pvalue;
|
var_ref->pvalue = pvalue;
|
||||||
return var_ref;
|
return var_ref;
|
||||||
@@ -17025,41 +17029,41 @@ static int js_op_define_class(JSContext *ctx, JSValue *sp,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_var_refs(JSRuntime *rt, JSStackFrame *sf)
|
static void close_var_ref(JSRuntime *rt, JSStackFrame *sf, JSVarRef *var_ref)
|
||||||
{
|
{
|
||||||
struct list_head *el, *el1;
|
if (sf->js_mode & JS_MODE_ASYNC) {
|
||||||
JSVarRef *var_ref;
|
JSAsyncFunctionState *async_func = container_of(sf, JSAsyncFunctionState, frame);
|
||||||
|
async_func_free(rt, async_func);
|
||||||
|
}
|
||||||
|
var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
|
||||||
|
var_ref->pvalue = &var_ref->value;
|
||||||
|
/* the reference is no longer to a local variable */
|
||||||
|
var_ref->is_detached = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
list_for_each_safe(el, el1, &sf->var_ref_list) {
|
static void close_var_refs(JSRuntime *rt, JSFunctionBytecode *b, JSStackFrame *sf)
|
||||||
var_ref = list_entry(el, JSVarRef, var_ref_link);
|
{
|
||||||
/* no need to unlink var_ref->var_ref_link as the list is never used afterwards */
|
JSVarRef *var_ref;
|
||||||
if (var_ref->async_func)
|
int i;
|
||||||
async_func_free(rt, var_ref->async_func);
|
|
||||||
var_ref->value = JS_DupValueRT(rt, *var_ref->pvalue);
|
for(i = 0; i < b->var_ref_count; i++) {
|
||||||
var_ref->pvalue = &var_ref->value;
|
var_ref = sf->var_refs[i];
|
||||||
/* the reference is no longer to a local variable */
|
if (var_ref)
|
||||||
var_ref->is_detached = TRUE;
|
close_var_ref(rt, sf, var_ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void close_lexical_var(JSContext *ctx, JSStackFrame *sf, int var_idx)
|
static void close_lexical_var(JSContext *ctx, JSFunctionBytecode *b,
|
||||||
|
JSStackFrame *sf, int var_idx)
|
||||||
{
|
{
|
||||||
JSValue *pvalue;
|
|
||||||
struct list_head *el, *el1;
|
|
||||||
JSVarRef *var_ref;
|
JSVarRef *var_ref;
|
||||||
|
int var_ref_idx;
|
||||||
pvalue = &sf->var_buf[var_idx];
|
|
||||||
list_for_each_safe(el, el1, &sf->var_ref_list) {
|
var_ref_idx = b->vardefs[b->arg_count + var_idx].var_ref_idx;
|
||||||
var_ref = list_entry(el, JSVarRef, var_ref_link);
|
var_ref = sf->var_refs[var_ref_idx];
|
||||||
if (var_ref->pvalue == pvalue) {
|
if (var_ref) {
|
||||||
list_del(&var_ref->var_ref_link);
|
close_var_ref(ctx->rt, sf, var_ref);
|
||||||
if (var_ref->async_func)
|
sf->var_refs[var_ref_idx] = NULL;
|
||||||
async_func_free(ctx->rt, var_ref->async_func);
|
|
||||||
var_ref->value = JS_DupValue(ctx, *var_ref->pvalue);
|
|
||||||
var_ref->pvalue = &var_ref->value;
|
|
||||||
/* the reference is no longer to a local variable */
|
|
||||||
var_ref->is_detached = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17330,7 +17334,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
}
|
}
|
||||||
|
|
||||||
alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
|
alloca_size = sizeof(JSValue) * (arg_allocated_size + b->var_count +
|
||||||
b->stack_size);
|
b->stack_size) +
|
||||||
|
sizeof(JSVarRef *) * b->var_ref_count;
|
||||||
if (js_check_stack_overflow(rt, alloca_size))
|
if (js_check_stack_overflow(rt, alloca_size))
|
||||||
return JS_ThrowStackOverflow(caller_ctx);
|
return JS_ThrowStackOverflow(caller_ctx);
|
||||||
|
|
||||||
@@ -17338,7 +17343,6 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
arg_buf = argv;
|
arg_buf = argv;
|
||||||
sf->arg_count = argc;
|
sf->arg_count = argc;
|
||||||
sf->cur_func = (JSValue)func_obj;
|
sf->cur_func = (JSValue)func_obj;
|
||||||
init_list_head(&sf->var_ref_list);
|
|
||||||
var_refs = p->u.func.var_refs;
|
var_refs = p->u.func.var_refs;
|
||||||
|
|
||||||
local_buf = alloca(alloca_size);
|
local_buf = alloca(alloca_size);
|
||||||
@@ -17359,6 +17363,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
var_buf[i] = JS_UNDEFINED;
|
var_buf[i] = JS_UNDEFINED;
|
||||||
|
|
||||||
stack_buf = var_buf + b->var_count;
|
stack_buf = var_buf + b->var_count;
|
||||||
|
sf->var_refs = (JSVarRef **)(stack_buf + b->stack_size);
|
||||||
|
for(i = 0; i < b->var_ref_count; i++)
|
||||||
|
sf->var_refs[i] = NULL;
|
||||||
sp = stack_buf;
|
sp = stack_buf;
|
||||||
pc = b->byte_code_buf;
|
pc = b->byte_code_buf;
|
||||||
sf->prev_frame = rt->current_stack_frame;
|
sf->prev_frame = rt->current_stack_frame;
|
||||||
@@ -18257,7 +18264,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
int idx;
|
int idx;
|
||||||
idx = get_u16(pc);
|
idx = get_u16(pc);
|
||||||
pc += 2;
|
pc += 2;
|
||||||
close_lexical_var(ctx, sf, idx);
|
close_lexical_var(ctx, b, sf, idx);
|
||||||
}
|
}
|
||||||
BREAK;
|
BREAK;
|
||||||
|
|
||||||
@@ -19988,9 +19995,9 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
|
|||||||
sf->cur_sp = sp;
|
sf->cur_sp = sp;
|
||||||
} else {
|
} else {
|
||||||
done:
|
done:
|
||||||
if (unlikely(!list_empty(&sf->var_ref_list))) {
|
if (unlikely(b->var_ref_count != 0)) {
|
||||||
/* variable references reference the stack: must close them */
|
/* variable references reference the stack: must close them */
|
||||||
close_var_refs(rt, sf);
|
close_var_refs(rt, b, sf);
|
||||||
}
|
}
|
||||||
/* free the local variables and stack */
|
/* free the local variables and stack */
|
||||||
for(pval = local_buf; pval < sp; pval++) {
|
for(pval = local_buf; pval < sp; pval++) {
|
||||||
@@ -20185,33 +20192,31 @@ static JSAsyncFunctionState *async_func_init(JSContext *ctx,
|
|||||||
JSObject *p;
|
JSObject *p;
|
||||||
JSFunctionBytecode *b;
|
JSFunctionBytecode *b;
|
||||||
JSStackFrame *sf;
|
JSStackFrame *sf;
|
||||||
int local_count, i, arg_buf_len, n;
|
int i, arg_buf_len, n;
|
||||||
|
|
||||||
s = js_mallocz(ctx, sizeof(*s));
|
p = JS_VALUE_GET_OBJ(func_obj);
|
||||||
|
b = p->u.func.function_bytecode;
|
||||||
|
arg_buf_len = max_int(b->arg_count, argc);
|
||||||
|
s = js_malloc(ctx, sizeof(*s) + sizeof(JSValue) * (arg_buf_len + b->var_count + b->stack_size) + sizeof(JSVarRef *) * b->var_ref_count);
|
||||||
if (!s)
|
if (!s)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
memset(s, 0, sizeof(*s));
|
||||||
s->header.ref_count = 1;
|
s->header.ref_count = 1;
|
||||||
add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
|
add_gc_object(ctx->rt, &s->header, JS_GC_OBJ_TYPE_ASYNC_FUNCTION);
|
||||||
|
|
||||||
sf = &s->frame;
|
sf = &s->frame;
|
||||||
init_list_head(&sf->var_ref_list);
|
|
||||||
p = JS_VALUE_GET_OBJ(func_obj);
|
|
||||||
b = p->u.func.function_bytecode;
|
|
||||||
sf->js_mode = b->js_mode | JS_MODE_ASYNC;
|
sf->js_mode = b->js_mode | JS_MODE_ASYNC;
|
||||||
sf->cur_pc = b->byte_code_buf;
|
sf->cur_pc = b->byte_code_buf;
|
||||||
arg_buf_len = max_int(b->arg_count, argc);
|
sf->arg_buf = (JSValue *)(s + 1);
|
||||||
local_count = arg_buf_len + b->var_count + b->stack_size;
|
|
||||||
sf->arg_buf = js_malloc(ctx, sizeof(JSValue) * max_int(local_count, 1));
|
|
||||||
if (!sf->arg_buf) {
|
|
||||||
js_free(ctx, s);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
sf->cur_func = JS_DupValue(ctx, func_obj);
|
sf->cur_func = JS_DupValue(ctx, func_obj);
|
||||||
s->this_val = JS_DupValue(ctx, this_obj);
|
s->this_val = JS_DupValue(ctx, this_obj);
|
||||||
s->argc = argc;
|
s->argc = argc;
|
||||||
sf->arg_count = arg_buf_len;
|
sf->arg_count = arg_buf_len;
|
||||||
sf->var_buf = sf->arg_buf + arg_buf_len;
|
sf->var_buf = sf->arg_buf + arg_buf_len;
|
||||||
sf->cur_sp = sf->var_buf + b->var_count;
|
sf->cur_sp = sf->var_buf + b->var_count;
|
||||||
|
sf->var_refs = (JSVarRef **)(sf->cur_sp + b->stack_size);
|
||||||
|
for(i = 0; i < b->var_ref_count; i++)
|
||||||
|
sf->var_refs[i] = NULL;
|
||||||
for(i = 0; i < argc; i++)
|
for(i = 0; i < argc; i++)
|
||||||
sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
|
sf->arg_buf[i] = JS_DupValue(ctx, argv[i]);
|
||||||
n = arg_buf_len + b->var_count;
|
n = arg_buf_len + b->var_count;
|
||||||
@@ -20228,14 +20233,10 @@ static void async_func_free_frame(JSRuntime *rt, JSAsyncFunctionState *s)
|
|||||||
JSStackFrame *sf = &s->frame;
|
JSStackFrame *sf = &s->frame;
|
||||||
JSValue *sp;
|
JSValue *sp;
|
||||||
|
|
||||||
if (sf->arg_buf) {
|
/* cannot free the function if it is running */
|
||||||
/* cannot free the function if it is running */
|
assert(sf->cur_sp != NULL);
|
||||||
assert(sf->cur_sp != NULL);
|
for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
|
||||||
for(sp = sf->arg_buf; sp < sf->cur_sp; sp++) {
|
JS_FreeValueRT(rt, *sp);
|
||||||
JS_FreeValueRT(rt, *sp);
|
|
||||||
}
|
|
||||||
js_free_rt(rt, sf->arg_buf);
|
|
||||||
sf->arg_buf = NULL;
|
|
||||||
}
|
}
|
||||||
JS_FreeValueRT(rt, sf->cur_func);
|
JS_FreeValueRT(rt, sf->cur_func);
|
||||||
JS_FreeValueRT(rt, s->this_val);
|
JS_FreeValueRT(rt, s->this_val);
|
||||||
@@ -20257,6 +20258,12 @@ static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
|
|||||||
s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
|
s->argc, sf->arg_buf, JS_CALL_FLAG_GENERATOR);
|
||||||
}
|
}
|
||||||
if (JS_IsException(ret) || JS_IsUndefined(ret)) {
|
if (JS_IsException(ret) || JS_IsUndefined(ret)) {
|
||||||
|
JSObject *p;
|
||||||
|
JSFunctionBytecode *b;
|
||||||
|
|
||||||
|
p = JS_VALUE_GET_OBJ(sf->cur_func);
|
||||||
|
b = p->u.func.function_bytecode;
|
||||||
|
|
||||||
if (JS_IsUndefined(ret)) {
|
if (JS_IsUndefined(ret)) {
|
||||||
ret = sf->cur_sp[-1];
|
ret = sf->cur_sp[-1];
|
||||||
sf->cur_sp[-1] = JS_UNDEFINED;
|
sf->cur_sp[-1] = JS_UNDEFINED;
|
||||||
@@ -20265,8 +20272,8 @@ static JSValue async_func_resume(JSContext *ctx, JSAsyncFunctionState *s)
|
|||||||
s->is_completed = TRUE;
|
s->is_completed = TRUE;
|
||||||
|
|
||||||
/* close the closure variables. */
|
/* close the closure variables. */
|
||||||
close_var_refs(rt, sf);
|
close_var_refs(rt, b, sf);
|
||||||
|
|
||||||
async_func_free_frame(rt, s);
|
async_func_free_frame(rt, s);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -21252,6 +21259,35 @@ typedef enum JSParseExportEnum {
|
|||||||
JS_PARSE_EXPORT_DEFAULT,
|
JS_PARSE_EXPORT_DEFAULT,
|
||||||
} JSParseExportEnum;
|
} JSParseExportEnum;
|
||||||
|
|
||||||
|
typedef struct JSVarScope {
|
||||||
|
int parent; /* index into fd->scopes of the enclosing scope */
|
||||||
|
int first; /* index into fd->vars of the last variable in this scope */
|
||||||
|
} JSVarScope;
|
||||||
|
|
||||||
|
typedef struct JSVarDef {
|
||||||
|
JSAtom var_name;
|
||||||
|
/* index into fd->scopes of this variable lexical scope */
|
||||||
|
int scope_level;
|
||||||
|
/* - if scope_level = 0: scope in which the variable is defined
|
||||||
|
- if scope_level != 0: index into fd->vars of the next
|
||||||
|
variable in the same or enclosing lexical scope
|
||||||
|
*/
|
||||||
|
int scope_next;
|
||||||
|
uint8_t is_const : 1;
|
||||||
|
uint8_t is_lexical : 1;
|
||||||
|
uint8_t is_captured : 1; /* XXX: could remove and use a var_ref_idx value */
|
||||||
|
uint8_t is_static_private : 1; /* only used during private class field parsing */
|
||||||
|
uint8_t var_kind : 4; /* see JSVarKindEnum */
|
||||||
|
/* if is_captured = TRUE, provides, the index of the corresponding
|
||||||
|
JSVarRef on stack */
|
||||||
|
uint16_t var_ref_idx;
|
||||||
|
/* function pool index for lexical variables with var_kind =
|
||||||
|
JS_VAR_FUNCTION_DECL/JS_VAR_NEW_FUNCTION_DECL or scope level of
|
||||||
|
the definition of the 'var' variables (they have scope_level =
|
||||||
|
0) */
|
||||||
|
int func_pool_idx;
|
||||||
|
} JSVarDef;
|
||||||
|
|
||||||
typedef struct JSFunctionDef {
|
typedef struct JSFunctionDef {
|
||||||
JSContext *ctx;
|
JSContext *ctx;
|
||||||
struct JSFunctionDef *parent;
|
struct JSFunctionDef *parent;
|
||||||
@@ -21295,6 +21331,7 @@ typedef struct JSFunctionDef {
|
|||||||
int arg_size; /* allocated size for args[] */
|
int arg_size; /* allocated size for args[] */
|
||||||
int arg_count; /* number of arguments */
|
int arg_count; /* number of arguments */
|
||||||
int defined_arg_count;
|
int defined_arg_count;
|
||||||
|
int var_ref_count; /* number of local/arg variable references */
|
||||||
int var_object_idx; /* -1 if none */
|
int var_object_idx; /* -1 if none */
|
||||||
int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
|
int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
|
||||||
int arguments_var_idx; /* -1 if none */
|
int arguments_var_idx; /* -1 if none */
|
||||||
@@ -31494,6 +31531,7 @@ static void print_lines(const char *source, int line, int line1) {
|
|||||||
|
|
||||||
static void dump_byte_code(JSContext *ctx, int pass,
|
static void dump_byte_code(JSContext *ctx, int pass,
|
||||||
const uint8_t *tab, int len,
|
const uint8_t *tab, int len,
|
||||||
|
const JSBytecodeVarDef *vardefs,
|
||||||
const JSVarDef *args, int arg_count,
|
const JSVarDef *args, int arg_count,
|
||||||
const JSVarDef *vars, int var_count,
|
const JSVarDef *vars, int var_count,
|
||||||
const JSClosureVar *closure_var, int closure_var_count,
|
const JSClosureVar *closure_var, int closure_var_count,
|
||||||
@@ -31730,7 +31768,7 @@ static void dump_byte_code(JSContext *ctx, int pass,
|
|||||||
has_loc:
|
has_loc:
|
||||||
printf(" %d: ", idx);
|
printf(" %d: ", idx);
|
||||||
if (idx < var_count) {
|
if (idx < var_count) {
|
||||||
print_atom(ctx, vars[idx].var_name);
|
print_atom(ctx, vars ? vars[idx].var_name : vardefs[arg_count + idx].var_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_FMT_none_arg:
|
case OP_FMT_none_arg:
|
||||||
@@ -31741,7 +31779,7 @@ static void dump_byte_code(JSContext *ctx, int pass,
|
|||||||
has_arg:
|
has_arg:
|
||||||
printf(" %d: ", idx);
|
printf(" %d: ", idx);
|
||||||
if (idx < arg_count) {
|
if (idx < arg_count) {
|
||||||
print_atom(ctx, args[idx].var_name);
|
print_atom(ctx, args ? args[idx].var_name : vardefs[idx].var_name);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OP_FMT_none_var_ref:
|
case OP_FMT_none_var_ref:
|
||||||
@@ -31861,7 +31899,7 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
|
|||||||
if (b->var_count && b->vardefs) {
|
if (b->var_count && b->vardefs) {
|
||||||
printf(" locals:\n");
|
printf(" locals:\n");
|
||||||
for(i = 0; i < b->var_count; i++) {
|
for(i = 0; i < b->var_count; i++) {
|
||||||
JSVarDef *vd = &b->vardefs[b->arg_count + i];
|
JSBytecodeVarDef *vd = &b->vardefs[b->arg_count + i];
|
||||||
printf("%5d: %s %s", i,
|
printf("%5d: %s %s", i,
|
||||||
vd->var_kind == JS_VAR_CATCH ? "catch" :
|
vd->var_kind == JS_VAR_CATCH ? "catch" :
|
||||||
(vd->var_kind == JS_VAR_FUNCTION_DECL ||
|
(vd->var_kind == JS_VAR_FUNCTION_DECL ||
|
||||||
@@ -31869,8 +31907,8 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
|
|||||||
vd->is_const ? "const" :
|
vd->is_const ? "const" :
|
||||||
vd->is_lexical ? "let" : "var",
|
vd->is_lexical ? "let" : "var",
|
||||||
JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
|
JS_AtomGetStr(ctx, atom_buf, sizeof(atom_buf), vd->var_name));
|
||||||
if (vd->scope_level)
|
if (vd->has_scope)
|
||||||
printf(" [level:%d next:%d]", vd->scope_level, vd->scope_next);
|
printf(" [next:%d]", vd->scope_next);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31914,10 +31952,12 @@ static __maybe_unused void js_dump_function_bytecode(JSContext *ctx, JSFunctionB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf(" stack_size: %d\n", b->stack_size);
|
printf(" stack_size: %d\n", b->stack_size);
|
||||||
|
printf(" var_ref_count: %d\n", b->var_ref_count);
|
||||||
printf(" opcodes:\n");
|
printf(" opcodes:\n");
|
||||||
dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
|
dump_byte_code(ctx, 3, b->byte_code_buf, b->byte_code_len,
|
||||||
b->vardefs, b->arg_count,
|
b->vardefs,
|
||||||
b->vardefs ? b->vardefs + b->arg_count : NULL, b->var_count,
|
NULL, b->arg_count,
|
||||||
|
NULL, b->var_count,
|
||||||
b->closure_var, b->closure_var_count,
|
b->closure_var, b->closure_var_count,
|
||||||
b->cpool, b->cpool_count,
|
b->cpool, b->cpool_count,
|
||||||
b->has_debug ? b->debug.source : NULL,
|
b->has_debug ? b->debug.source : NULL,
|
||||||
@@ -32143,6 +32183,14 @@ static void var_object_test(JSContext *ctx, JSFunctionDef *s,
|
|||||||
s->jump_size++;
|
s->jump_size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void capture_var(JSFunctionDef *s, JSVarDef *vd)
|
||||||
|
{
|
||||||
|
if (!vd->is_captured) {
|
||||||
|
vd->is_captured = 1;
|
||||||
|
vd->var_ref_idx = s->var_ref_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* return the position of the next opcode or -1 if error */
|
/* return the position of the next opcode or -1 if error */
|
||||||
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
||||||
JSAtom var_name, int scope_level, int op,
|
JSAtom var_name, int scope_level, int op,
|
||||||
@@ -32252,10 +32300,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* Create a dummy object with a named slot that is
|
/* Create a dummy object with a named slot that is
|
||||||
a reference to the local variable */
|
a reference to the local variable */
|
||||||
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
||||||
|
capture_var(s, &s->args[var_idx - ARGUMENT_VAR_OFFSET]);
|
||||||
dbuf_putc(bc, OP_make_arg_ref);
|
dbuf_putc(bc, OP_make_arg_ref);
|
||||||
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
|
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
|
||||||
dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
|
dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
|
||||||
} else {
|
} else {
|
||||||
|
capture_var(s, &s->vars[var_idx]);
|
||||||
dbuf_putc(bc, OP_make_loc_ref);
|
dbuf_putc(bc, OP_make_loc_ref);
|
||||||
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
|
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
|
||||||
dbuf_put_u16(bc, var_idx);
|
dbuf_put_u16(bc, var_idx);
|
||||||
@@ -32349,7 +32399,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
|||||||
var_idx = idx;
|
var_idx = idx;
|
||||||
break;
|
break;
|
||||||
} else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
|
} else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
|
||||||
vd->is_captured = 1;
|
capture_var(fd, vd);
|
||||||
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
dbuf_putc(bc, OP_get_var_ref);
|
dbuf_putc(bc, OP_get_var_ref);
|
||||||
@@ -32386,7 +32436,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* check eval object */
|
/* check eval object */
|
||||||
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
|
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
|
||||||
vd = &fd->vars[fd->var_object_idx];
|
vd = &fd->vars[fd->var_object_idx];
|
||||||
vd->is_captured = 1;
|
capture_var(fd, vd);
|
||||||
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
|
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
|
||||||
fd->var_object_idx, vd->var_name,
|
fd->var_object_idx, vd->var_name,
|
||||||
FALSE, FALSE, JS_VAR_NORMAL);
|
FALSE, FALSE, JS_VAR_NORMAL);
|
||||||
@@ -32398,7 +32448,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* check eval object in argument scope */
|
/* check eval object in argument scope */
|
||||||
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
|
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
|
||||||
vd = &fd->vars[fd->arg_var_object_idx];
|
vd = &fd->vars[fd->arg_var_object_idx];
|
||||||
vd->is_captured = 1;
|
capture_var(fd, vd);
|
||||||
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
|
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
|
||||||
fd->arg_var_object_idx, vd->var_name,
|
fd->arg_var_object_idx, vd->var_name,
|
||||||
FALSE, FALSE, JS_VAR_NORMAL);
|
FALSE, FALSE, JS_VAR_NORMAL);
|
||||||
@@ -32513,12 +32563,12 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
|
|||||||
} else {
|
} else {
|
||||||
/* find the corresponding closure variable */
|
/* find the corresponding closure variable */
|
||||||
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
if (var_idx & ARGUMENT_VAR_OFFSET) {
|
||||||
fd->args[var_idx - ARGUMENT_VAR_OFFSET].is_captured = 1;
|
capture_var(fd, &fd->args[var_idx - ARGUMENT_VAR_OFFSET]);
|
||||||
idx = get_closure_var(ctx, s, fd,
|
idx = get_closure_var(ctx, s, fd,
|
||||||
JS_CLOSURE_ARG, var_idx - ARGUMENT_VAR_OFFSET,
|
JS_CLOSURE_ARG, var_idx - ARGUMENT_VAR_OFFSET,
|
||||||
var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
var_name, FALSE, FALSE, JS_VAR_NORMAL);
|
||||||
} else {
|
} else {
|
||||||
fd->vars[var_idx].is_captured = 1;
|
capture_var(fd, &fd->vars[var_idx]);
|
||||||
idx = get_closure_var(ctx, s, fd,
|
idx = get_closure_var(ctx, s, fd,
|
||||||
JS_CLOSURE_LOCAL, var_idx,
|
JS_CLOSURE_LOCAL, var_idx,
|
||||||
var_name,
|
var_name,
|
||||||
@@ -32665,6 +32715,7 @@ static int resolve_scope_private_field1(JSContext *ctx,
|
|||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
var_kind = fd->vars[idx].var_kind;
|
var_kind = fd->vars[idx].var_kind;
|
||||||
if (is_ref) {
|
if (is_ref) {
|
||||||
|
capture_var(fd, &fd->vars[idx]);
|
||||||
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, var_name,
|
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, var_name,
|
||||||
TRUE, TRUE, JS_VAR_NORMAL);
|
TRUE, TRUE, JS_VAR_NORMAL);
|
||||||
if (idx < 0)
|
if (idx < 0)
|
||||||
@@ -32819,20 +32870,20 @@ static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
|
|||||||
|
|
||||||
for (idx = s->scopes[scope_level].first; idx >= 0;) {
|
for (idx = s->scopes[scope_level].first; idx >= 0;) {
|
||||||
vd = &s->vars[idx];
|
vd = &s->vars[idx];
|
||||||
vd->is_captured = 1;
|
capture_var(s, vd);
|
||||||
idx = vd->scope_next;
|
idx = vd->scope_next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: should handle the argument scope generically */
|
/* XXX: should handle the argument scope generically */
|
||||||
static BOOL is_var_in_arg_scope(const JSVarDef *vd)
|
static BOOL is_var_in_arg_scope(JSAtom var_name, JSVarKindEnum var_kind)
|
||||||
{
|
{
|
||||||
return (vd->var_name == JS_ATOM_home_object ||
|
return (var_name == JS_ATOM_home_object ||
|
||||||
vd->var_name == JS_ATOM_this_active_func ||
|
var_name == JS_ATOM_this_active_func ||
|
||||||
vd->var_name == JS_ATOM_new_target ||
|
var_name == JS_ATOM_new_target ||
|
||||||
vd->var_name == JS_ATOM_this ||
|
var_name == JS_ATOM_this ||
|
||||||
vd->var_name == JS_ATOM__arg_var_ ||
|
var_name == JS_ATOM__arg_var_ ||
|
||||||
vd->var_kind == JS_VAR_FUNCTION_NAME);
|
var_kind == JS_VAR_FUNCTION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
||||||
@@ -32877,6 +32928,20 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
|
if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
|
||||||
add_func_var(ctx, s, s->func_name);
|
add_func_var(ctx, s, s->func_name);
|
||||||
|
|
||||||
|
for(i = 0; i < s->arg_count; i++) {
|
||||||
|
vd = &s->args[i];
|
||||||
|
capture_var(s, vd);
|
||||||
|
}
|
||||||
|
for(i = 0; i < s->var_count; i++) {
|
||||||
|
vd = &s->vars[i];
|
||||||
|
/* do not close top level last result */
|
||||||
|
if (vd->scope_level == 0 &&
|
||||||
|
vd->var_name != JS_ATOM__ret_ &&
|
||||||
|
vd->var_name != JS_ATOM_NULL) {
|
||||||
|
capture_var(s, vd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* eval can use all the variables of the enclosing functions, so
|
/* eval can use all the variables of the enclosing functions, so
|
||||||
they must be all put in the closure. The closure variables are
|
they must be all put in the closure. The closure variables are
|
||||||
ordered by scope. It works only because no closure are created
|
ordered by scope. It works only because no closure are created
|
||||||
@@ -32915,7 +32980,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
scope_idx = fd->scopes[scope_level].first;
|
scope_idx = fd->scopes[scope_level].first;
|
||||||
while (scope_idx >= 0) {
|
while (scope_idx >= 0) {
|
||||||
vd = &fd->vars[scope_idx];
|
vd = &fd->vars[scope_idx];
|
||||||
vd->is_captured = 1;
|
capture_var(fd, vd);
|
||||||
get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
|
get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
|
||||||
vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
|
vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
|
||||||
scope_idx = vd->scope_next;
|
scope_idx = vd->scope_next;
|
||||||
@@ -32927,6 +32992,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
for(i = 0; i < fd->arg_count; i++) {
|
for(i = 0; i < fd->arg_count; i++) {
|
||||||
vd = &fd->args[i];
|
vd = &fd->args[i];
|
||||||
if (vd->var_name != JS_ATOM_NULL) {
|
if (vd->var_name != JS_ATOM_NULL) {
|
||||||
|
capture_var(fd, vd);
|
||||||
get_closure_var(ctx, s, fd,
|
get_closure_var(ctx, s, fd,
|
||||||
JS_CLOSURE_ARG, i, vd->var_name, FALSE,
|
JS_CLOSURE_ARG, i, vd->var_name, FALSE,
|
||||||
vd->is_lexical, JS_VAR_NORMAL);
|
vd->is_lexical, JS_VAR_NORMAL);
|
||||||
@@ -32938,6 +33004,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
if (vd->scope_level == 0 &&
|
if (vd->scope_level == 0 &&
|
||||||
vd->var_name != JS_ATOM__ret_ &&
|
vd->var_name != JS_ATOM__ret_ &&
|
||||||
vd->var_name != JS_ATOM_NULL) {
|
vd->var_name != JS_ATOM_NULL) {
|
||||||
|
capture_var(fd, vd);
|
||||||
get_closure_var(ctx, s, fd,
|
get_closure_var(ctx, s, fd,
|
||||||
JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
|
JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
|
||||||
vd->is_lexical, JS_VAR_NORMAL);
|
vd->is_lexical, JS_VAR_NORMAL);
|
||||||
@@ -32947,7 +33014,8 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
for(i = 0; i < fd->var_count; i++) {
|
for(i = 0; i < fd->var_count; i++) {
|
||||||
vd = &fd->vars[i];
|
vd = &fd->vars[i];
|
||||||
/* do not close top level last result */
|
/* do not close top level last result */
|
||||||
if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
|
if (vd->scope_level == 0 && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {
|
||||||
|
capture_var(fd, vd);
|
||||||
get_closure_var(ctx, s, fd,
|
get_closure_var(ctx, s, fd,
|
||||||
JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
|
JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
|
||||||
vd->is_lexical, JS_VAR_NORMAL);
|
vd->is_lexical, JS_VAR_NORMAL);
|
||||||
@@ -32976,7 +33044,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
|
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
|
||||||
JSVarDef *vd, int var_idx)
|
JSBytecodeVarDef *vd, int var_idx)
|
||||||
{
|
{
|
||||||
cv->closure_type = JS_CLOSURE_LOCAL;
|
cv->closure_type = JS_CLOSURE_LOCAL;
|
||||||
cv->is_const = vd->is_const;
|
cv->is_const = vd->is_const;
|
||||||
@@ -32992,7 +33060,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
|
|||||||
JSFunctionBytecode *b, int scope_idx)
|
JSFunctionBytecode *b, int scope_idx)
|
||||||
{
|
{
|
||||||
int i, count;
|
int i, count;
|
||||||
JSVarDef *vd;
|
JSBytecodeVarDef *vd;
|
||||||
BOOL is_arg_scope;
|
BOOL is_arg_scope;
|
||||||
|
|
||||||
count = b->arg_count + b->var_count + b->closure_var_count;
|
count = b->arg_count + b->var_count + b->closure_var_count;
|
||||||
@@ -33007,7 +33075,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* Add lexical variables in scope at the point of evaluation */
|
/* Add lexical variables in scope at the point of evaluation */
|
||||||
for (i = scope_idx; i >= 0;) {
|
for (i = scope_idx; i >= 0;) {
|
||||||
vd = &b->vardefs[b->arg_count + i];
|
vd = &b->vardefs[b->arg_count + i];
|
||||||
if (vd->scope_level > 0) {
|
if (vd->has_scope) {
|
||||||
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
||||||
set_closure_from_var(ctx, cv, vd, i);
|
set_closure_from_var(ctx, cv, vd, i);
|
||||||
}
|
}
|
||||||
@@ -33029,7 +33097,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* Add local non lexical variables */
|
/* Add local non lexical variables */
|
||||||
for(i = 0; i < b->var_count; i++) {
|
for(i = 0; i < b->var_count; i++) {
|
||||||
vd = &b->vardefs[b->arg_count + i];
|
vd = &b->vardefs[b->arg_count + i];
|
||||||
if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
|
if (!vd->has_scope && vd->var_name != JS_ATOM__ret_) {
|
||||||
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
||||||
set_closure_from_var(ctx, cv, vd, i);
|
set_closure_from_var(ctx, cv, vd, i);
|
||||||
}
|
}
|
||||||
@@ -33038,7 +33106,7 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
|
|||||||
/* only add pseudo variables */
|
/* only add pseudo variables */
|
||||||
for(i = 0; i < b->var_count; i++) {
|
for(i = 0; i < b->var_count; i++) {
|
||||||
vd = &b->vardefs[b->arg_count + i];
|
vd = &b->vardefs[b->arg_count + i];
|
||||||
if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
|
if (!vd->has_scope && is_var_in_arg_scope(vd->var_name, vd->var_kind)) {
|
||||||
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
|
||||||
set_closure_from_var(ctx, cv, vd, i);
|
set_closure_from_var(ctx, cv, vd, i);
|
||||||
}
|
}
|
||||||
@@ -34078,6 +34146,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
|
|||||||
} else {
|
} else {
|
||||||
dbuf_putc(&bc_out, OP_special_object);
|
dbuf_putc(&bc_out, OP_special_object);
|
||||||
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
|
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
|
||||||
|
/* the arguments are implicitly captured because
|
||||||
|
references to them are created with the 'argument'
|
||||||
|
object */
|
||||||
|
for(i = 0; i < s->arg_count; i++)
|
||||||
|
capture_var(s, &s->args[i]);
|
||||||
}
|
}
|
||||||
if (s->arguments_arg_idx >= 0)
|
if (s->arguments_arg_idx >= 0)
|
||||||
put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
|
put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
|
||||||
@@ -35234,7 +35307,8 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
int stack_size, scope, idx;
|
int stack_size, scope, idx;
|
||||||
int function_size, byte_code_offset, cpool_offset;
|
int function_size, byte_code_offset, cpool_offset;
|
||||||
int closure_var_offset, vardefs_offset;
|
int closure_var_offset, vardefs_offset;
|
||||||
|
BOOL strip_var_debug;
|
||||||
|
|
||||||
/* recompute scope linkage */
|
/* recompute scope linkage */
|
||||||
for (scope = 0; scope < fd->scope_count; scope++) {
|
for (scope = 0; scope < fd->scope_count; scope++) {
|
||||||
fd->scopes[scope].first = -1;
|
fd->scopes[scope].first = -1;
|
||||||
@@ -35293,7 +35367,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
if (!fd->strip_debug) {
|
if (!fd->strip_debug) {
|
||||||
printf("pass 1\n");
|
printf("pass 1\n");
|
||||||
dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
|
dump_byte_code(ctx, 1, fd->byte_code.buf, fd->byte_code.size,
|
||||||
fd->args, fd->arg_count, fd->vars, fd->var_count,
|
NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,
|
||||||
fd->closure_var, fd->closure_var_count,
|
fd->closure_var, fd->closure_var_count,
|
||||||
fd->cpool, fd->cpool_count, fd->source,
|
fd->cpool, fd->cpool_count, fd->source,
|
||||||
fd->label_slots, NULL);
|
fd->label_slots, NULL);
|
||||||
@@ -35308,7 +35382,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
if (!fd->strip_debug) {
|
if (!fd->strip_debug) {
|
||||||
printf("pass 2\n");
|
printf("pass 2\n");
|
||||||
dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
|
dump_byte_code(ctx, 2, fd->byte_code.buf, fd->byte_code.size,
|
||||||
fd->args, fd->arg_count, fd->vars, fd->var_count,
|
NULL, fd->args, fd->arg_count, fd->vars, fd->var_count,
|
||||||
fd->closure_var, fd->closure_var_count,
|
fd->closure_var, fd->closure_var_count,
|
||||||
fd->cpool, fd->cpool_count, fd->source,
|
fd->cpool, fd->cpool_count, fd->source,
|
||||||
fd->label_slots, NULL);
|
fd->label_slots, NULL);
|
||||||
@@ -35330,9 +35404,7 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
cpool_offset = function_size;
|
cpool_offset = function_size;
|
||||||
function_size += fd->cpool_count * sizeof(*fd->cpool);
|
function_size += fd->cpool_count * sizeof(*fd->cpool);
|
||||||
vardefs_offset = function_size;
|
vardefs_offset = function_size;
|
||||||
if (!fd->strip_debug || fd->has_eval_call) {
|
function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
|
||||||
function_size += (fd->arg_count + fd->var_count) * sizeof(*b->vardefs);
|
|
||||||
}
|
|
||||||
closure_var_offset = function_size;
|
closure_var_offset = function_size;
|
||||||
function_size += fd->closure_var_count * sizeof(*fd->closure_var);
|
function_size += fd->closure_var_count * sizeof(*fd->closure_var);
|
||||||
byte_code_offset = function_size;
|
byte_code_offset = function_size;
|
||||||
@@ -35349,29 +35421,50 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
js_free(ctx, fd->byte_code.buf);
|
js_free(ctx, fd->byte_code.buf);
|
||||||
fd->byte_code.buf = NULL;
|
fd->byte_code.buf = NULL;
|
||||||
|
|
||||||
|
strip_var_debug = fd->strip_debug && !fd->has_eval_call; /* XXX: check */
|
||||||
b->func_name = fd->func_name;
|
b->func_name = fd->func_name;
|
||||||
if (fd->arg_count + fd->var_count > 0) {
|
if (fd->arg_count + fd->var_count > 0) {
|
||||||
if (fd->strip_debug && !fd->has_eval_call) {
|
int i;
|
||||||
/* Strip variable definitions not needed at runtime */
|
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
|
||||||
int i;
|
for(i = 0; i < fd->arg_count; i++) {
|
||||||
for(i = 0; i < fd->var_count; i++) {
|
JSVarDef *vd = &fd->args[i];
|
||||||
JS_FreeAtom(ctx, fd->vars[i].var_name);
|
JSBytecodeVarDef *vd1 = &b->vardefs[i];
|
||||||
|
if (strip_var_debug) {
|
||||||
|
JS_FreeAtom(ctx, vd->var_name);
|
||||||
|
vd1->var_name = JS_ATOM_NULL;
|
||||||
|
} else {
|
||||||
|
vd1->var_name = vd->var_name;
|
||||||
}
|
}
|
||||||
for(i = 0; i < fd->arg_count; i++) {
|
vd1->has_scope = (vd->scope_level != 0);
|
||||||
JS_FreeAtom(ctx, fd->args[i].var_name);
|
vd1->scope_next = vd->scope_next;
|
||||||
|
vd1->is_const = vd->is_const;
|
||||||
|
vd1->is_lexical = vd->is_lexical;
|
||||||
|
vd1->is_captured = vd->is_captured;
|
||||||
|
vd1->var_kind = vd->var_kind;
|
||||||
|
vd1->var_ref_idx = vd->var_ref_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i = 0; i < fd->var_count; i++) {
|
||||||
|
JSVarDef *vd = &fd->vars[i];
|
||||||
|
JSBytecodeVarDef *vd1 = &b->vardefs[i + fd->arg_count];
|
||||||
|
if (strip_var_debug) {
|
||||||
|
JS_FreeAtom(ctx, vd->var_name);
|
||||||
|
vd1->var_name = JS_ATOM_NULL;
|
||||||
|
} else {
|
||||||
|
vd1->var_name = vd->var_name;
|
||||||
}
|
}
|
||||||
for(i = 0; i < fd->closure_var_count; i++) {
|
vd1->has_scope = (vd->scope_level != 0);
|
||||||
JS_FreeAtom(ctx, fd->closure_var[i].var_name);
|
vd1->scope_next = vd->scope_next;
|
||||||
fd->closure_var[i].var_name = JS_ATOM_NULL;
|
vd1->is_const = vd->is_const;
|
||||||
}
|
vd1->is_lexical = vd->is_lexical;
|
||||||
} else {
|
vd1->is_captured = vd->is_captured;
|
||||||
b->vardefs = (void *)((uint8_t*)b + vardefs_offset);
|
vd1->var_kind = vd->var_kind;
|
||||||
memcpy_no_ub(b->vardefs, fd->args, fd->arg_count * sizeof(fd->args[0]));
|
vd1->var_ref_idx = vd->var_ref_idx;
|
||||||
memcpy_no_ub(b->vardefs + fd->arg_count, fd->vars, fd->var_count * sizeof(fd->vars[0]));
|
|
||||||
}
|
}
|
||||||
b->var_count = fd->var_count;
|
b->var_count = fd->var_count;
|
||||||
b->arg_count = fd->arg_count;
|
b->arg_count = fd->arg_count;
|
||||||
b->defined_arg_count = fd->defined_arg_count;
|
b->defined_arg_count = fd->defined_arg_count;
|
||||||
|
b->var_ref_count = fd->var_ref_count;
|
||||||
js_free(ctx, fd->args);
|
js_free(ctx, fd->args);
|
||||||
js_free(ctx, fd->vars);
|
js_free(ctx, fd->vars);
|
||||||
}
|
}
|
||||||
@@ -35410,6 +35503,20 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
|
|||||||
|
|
||||||
b->closure_var_count = fd->closure_var_count;
|
b->closure_var_count = fd->closure_var_count;
|
||||||
if (b->closure_var_count) {
|
if (b->closure_var_count) {
|
||||||
|
if (strip_var_debug) {
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < fd->closure_var_count; i++) {
|
||||||
|
JSClosureVar *cv = &fd->closure_var[i];
|
||||||
|
if (cv->closure_type != JS_CLOSURE_GLOBAL_REF &&
|
||||||
|
cv->closure_type != JS_CLOSURE_GLOBAL_DECL &&
|
||||||
|
cv->closure_type != JS_CLOSURE_GLOBAL &&
|
||||||
|
cv->closure_type != JS_CLOSURE_MODULE_DECL &&
|
||||||
|
cv->closure_type != JS_CLOSURE_MODULE_IMPORT) {
|
||||||
|
JS_FreeAtom(ctx, cv->var_name);
|
||||||
|
cv->var_name = JS_ATOM_NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
b->closure_var = (void *)((uint8_t*)b + closure_var_offset);
|
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));
|
memcpy(b->closure_var, fd->closure_var, b->closure_var_count * sizeof(*b->closure_var));
|
||||||
}
|
}
|
||||||
@@ -37023,22 +37130,23 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
|
|||||||
bc_put_leb128(s, b->var_count);
|
bc_put_leb128(s, b->var_count);
|
||||||
bc_put_leb128(s, b->defined_arg_count);
|
bc_put_leb128(s, b->defined_arg_count);
|
||||||
bc_put_leb128(s, b->stack_size);
|
bc_put_leb128(s, b->stack_size);
|
||||||
|
bc_put_leb128(s, b->var_ref_count);
|
||||||
bc_put_leb128(s, b->closure_var_count);
|
bc_put_leb128(s, b->closure_var_count);
|
||||||
bc_put_leb128(s, b->cpool_count);
|
bc_put_leb128(s, b->cpool_count);
|
||||||
bc_put_leb128(s, b->byte_code_len);
|
bc_put_leb128(s, b->byte_code_len);
|
||||||
if (b->vardefs) {
|
if (b->vardefs) {
|
||||||
/* XXX: this field is redundant */
|
|
||||||
bc_put_leb128(s, b->arg_count + b->var_count);
|
bc_put_leb128(s, b->arg_count + b->var_count);
|
||||||
for(i = 0; i < b->arg_count + b->var_count; i++) {
|
for(i = 0; i < b->arg_count + b->var_count; i++) {
|
||||||
JSVarDef *vd = &b->vardefs[i];
|
JSBytecodeVarDef *vd = &b->vardefs[i];
|
||||||
bc_put_atom(s, vd->var_name);
|
bc_put_atom(s, vd->var_name);
|
||||||
bc_put_leb128(s, vd->scope_level);
|
|
||||||
bc_put_leb128(s, vd->scope_next + 1);
|
bc_put_leb128(s, vd->scope_next + 1);
|
||||||
|
bc_put_leb128(s, vd->var_ref_idx);
|
||||||
flags = idx = 0;
|
flags = idx = 0;
|
||||||
bc_set_flags(&flags, &idx, vd->var_kind, 4);
|
bc_set_flags(&flags, &idx, vd->var_kind, 4);
|
||||||
bc_set_flags(&flags, &idx, vd->is_const, 1);
|
bc_set_flags(&flags, &idx, vd->is_const, 1);
|
||||||
bc_set_flags(&flags, &idx, vd->is_lexical, 1);
|
bc_set_flags(&flags, &idx, vd->is_lexical, 1);
|
||||||
bc_set_flags(&flags, &idx, vd->is_captured, 1);
|
bc_set_flags(&flags, &idx, vd->is_captured, 1);
|
||||||
|
bc_set_flags(&flags, &idx, vd->has_scope, 1);
|
||||||
assert(idx <= 8);
|
assert(idx <= 8);
|
||||||
bc_put_u8(s, flags);
|
bc_put_u8(s, flags);
|
||||||
}
|
}
|
||||||
@@ -37916,6 +38024,8 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
|
|||||||
goto fail;
|
goto fail;
|
||||||
if (bc_get_leb128_u16(s, &bc.stack_size))
|
if (bc_get_leb128_u16(s, &bc.stack_size))
|
||||||
goto fail;
|
goto fail;
|
||||||
|
if (bc_get_leb128_u16(s, &bc.var_ref_count))
|
||||||
|
goto fail;
|
||||||
if (bc_get_leb128_int(s, &bc.closure_var_count))
|
if (bc_get_leb128_int(s, &bc.closure_var_count))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (bc_get_leb128_int(s, &bc.cpool_count))
|
if (bc_get_leb128_int(s, &bc.cpool_count))
|
||||||
@@ -37973,14 +38083,14 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
|
|||||||
if (local_count != 0) {
|
if (local_count != 0) {
|
||||||
bc_read_trace(s, "vars {\n");
|
bc_read_trace(s, "vars {\n");
|
||||||
for(i = 0; i < local_count; i++) {
|
for(i = 0; i < local_count; i++) {
|
||||||
JSVarDef *vd = &b->vardefs[i];
|
JSBytecodeVarDef *vd = &b->vardefs[i];
|
||||||
if (bc_get_atom(s, &vd->var_name))
|
if (bc_get_atom(s, &vd->var_name))
|
||||||
goto fail;
|
goto fail;
|
||||||
if (bc_get_leb128_int(s, &vd->scope_level))
|
|
||||||
goto fail;
|
|
||||||
if (bc_get_leb128_int(s, &vd->scope_next))
|
if (bc_get_leb128_int(s, &vd->scope_next))
|
||||||
goto fail;
|
goto fail;
|
||||||
vd->scope_next--;
|
vd->scope_next--;
|
||||||
|
if (bc_get_leb128_u16(s, &vd->var_ref_idx))
|
||||||
|
goto fail;
|
||||||
if (bc_get_u8(s, &v8))
|
if (bc_get_u8(s, &v8))
|
||||||
goto fail;
|
goto fail;
|
||||||
idx = 0;
|
idx = 0;
|
||||||
@@ -37988,6 +38098,7 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
|
|||||||
vd->is_const = bc_get_flags(v8, &idx, 1);
|
vd->is_const = bc_get_flags(v8, &idx, 1);
|
||||||
vd->is_lexical = bc_get_flags(v8, &idx, 1);
|
vd->is_lexical = bc_get_flags(v8, &idx, 1);
|
||||||
vd->is_captured = bc_get_flags(v8, &idx, 1);
|
vd->is_captured = bc_get_flags(v8, &idx, 1);
|
||||||
|
vd->has_scope = bc_get_flags(v8, &idx, 1);
|
||||||
#ifdef DUMP_READ_OBJECT
|
#ifdef DUMP_READ_OBJECT
|
||||||
bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
|
bc_read_trace(s, "name: "); print_atom(s->ctx, vd->var_name); printf("\n");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user