s->jump_size++;
}
-static inline void capture_var(JSFunctionDef *s, JSVarDef *vd)
+static inline __exception int capture_var(JSFunctionDef *s, JSVarDef *vd)
{
if (!vd->is_captured) {
+ /* the variable reference indexes are currently stored on 16 bits */
+ if (unlikely(s->var_ref_count >= JS_MAX_LOCAL_VARS)) {
+ JS_ThrowInternalError(s->ctx, "too variable references");
+ return -1;
+ }
vd->is_captured = 1;
vd->var_ref_idx = s->var_ref_count++;
}
+ return 0;
}
/* return the position of the next opcode or -1 if error */
/* Create a dummy object with a named slot that is
a reference to the local variable */
if (var_idx & ARGUMENT_VAR_OFFSET) {
- capture_var(s, &s->args[var_idx - ARGUMENT_VAR_OFFSET]);
+ if (capture_var(s, &s->args[var_idx - ARGUMENT_VAR_OFFSET]))
+ return -1;
dbuf_putc(bc, OP_make_arg_ref);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
} else {
- capture_var(s, &s->vars[var_idx]);
+ if (capture_var(s, &s->vars[var_idx]))
+ return -1;
dbuf_putc(bc, OP_make_loc_ref);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_put_u16(bc, var_idx);
var_idx = idx;
break;
} else if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
- capture_var(fd, vd);
+ if (capture_var(fd, vd))
+ return -1;
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, vd->var_name, FALSE, FALSE, JS_VAR_NORMAL);
if (idx >= 0) {
dbuf_putc(bc, OP_get_var_ref);
/* check eval object */
if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
vd = &fd->vars[fd->var_object_idx];
- capture_var(fd, vd);
+ if (capture_var(fd, vd))
+ return -1;
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
fd->var_object_idx, vd->var_name,
FALSE, FALSE, JS_VAR_NORMAL);
/* check eval object in argument scope */
if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
vd = &fd->vars[fd->arg_var_object_idx];
- capture_var(fd, vd);
+ if (capture_var(fd, vd))
+ return -1;
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL,
fd->arg_var_object_idx, vd->var_name,
FALSE, FALSE, JS_VAR_NORMAL);
} else {
/* find the corresponding closure variable */
if (var_idx & ARGUMENT_VAR_OFFSET) {
- capture_var(fd, &fd->args[var_idx - ARGUMENT_VAR_OFFSET]);
+ if (capture_var(fd, &fd->args[var_idx - ARGUMENT_VAR_OFFSET]))
+ return -1;
idx = get_closure_var(ctx, s, fd,
JS_CLOSURE_ARG, var_idx - ARGUMENT_VAR_OFFSET,
var_name, FALSE, FALSE, JS_VAR_NORMAL);
} else {
- capture_var(fd, &fd->vars[var_idx]);
+ if (capture_var(fd, &fd->vars[var_idx]))
+ return -1;
idx = get_closure_var(ctx, s, fd,
JS_CLOSURE_LOCAL, var_idx,
var_name,
if (idx >= 0) {
var_kind = fd->vars[idx].var_kind;
if (is_ref) {
- capture_var(fd, &fd->vars[idx]);
+ if (capture_var(fd, &fd->vars[idx]))
+ return -1;
idx = get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, idx, var_name,
TRUE, TRUE, JS_VAR_NORMAL);
if (idx < 0)
return 0;
}
-static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
- int scope_level)
+static __exception int mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
+ int scope_level)
{
int idx;
JSVarDef *vd;
for (idx = s->scopes[scope_level].first; idx >= 0;) {
vd = &s->vars[idx];
- capture_var(s, vd);
+ if (capture_var(s, vd))
+ return -1;
idx = vd->scope_next;
}
+ return 0;
}
/* XXX: should handle the argument scope generically */
var_kind == JS_VAR_FUNCTION_NAME);
}
-static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
+static __exception int add_eval_variables(JSContext *ctx, JSFunctionDef *s)
{
JSFunctionDef *fd;
JSVarDef *vd;
for(i = 0; i < s->arg_count; i++) {
vd = &s->args[i];
- capture_var(s, vd);
+ if (capture_var(s, vd))
+ return -1;
}
for(i = 0; i < s->var_count; i++) {
vd = &s->vars[i];
if (vd->scope_level == 0 &&
vd->var_name != JS_ATOM__ret_ &&
vd->var_name != JS_ATOM_NULL) {
- capture_var(s, vd);
+ if (capture_var(s, vd))
+ return -1;
}
}
scope_idx = fd->scopes[scope_level].first;
while (scope_idx >= 0) {
vd = &fd->vars[scope_idx];
- capture_var(fd, vd);
- get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
- vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
+ if (capture_var(fd, vd))
+ return -1;
+ if (get_closure_var(ctx, s, fd, JS_CLOSURE_LOCAL, scope_idx,
+ vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind) < 0)
+ return -1;
scope_idx = vd->scope_next;
}
is_arg_scope = (scope_idx == ARG_SCOPE_END);
for(i = 0; i < fd->arg_count; i++) {
vd = &fd->args[i];
if (vd->var_name != JS_ATOM_NULL) {
- capture_var(fd, vd);
- get_closure_var(ctx, s, fd,
- JS_CLOSURE_ARG, i, vd->var_name, FALSE,
- vd->is_lexical, JS_VAR_NORMAL);
+ if (capture_var(fd, vd))
+ return -1;
+ if (get_closure_var(ctx, s, fd,
+ JS_CLOSURE_ARG, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL) < 0)
+ return -1;
}
}
for(i = 0; i < fd->var_count; i++) {
if (vd->scope_level == 0 &&
vd->var_name != JS_ATOM__ret_ &&
vd->var_name != JS_ATOM_NULL) {
- capture_var(fd, vd);
- get_closure_var(ctx, s, fd,
- JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
- vd->is_lexical, JS_VAR_NORMAL);
+ if (capture_var(fd, vd))
+ return -1;
+ if (get_closure_var(ctx, s, fd,
+ JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL) < 0)
+ return -1;
}
}
} else {
vd = &fd->vars[i];
/* do not close top level last result */
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,
- JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
- vd->is_lexical, JS_VAR_NORMAL);
+ if (capture_var(fd, vd))
+ return -1;
+ if (get_closure_var(ctx, s, fd,
+ JS_CLOSURE_LOCAL, i, vd->var_name, FALSE,
+ vd->is_lexical, JS_VAR_NORMAL) < 0)
+ return -1;
}
}
}
}
}
}
+ return 0;
}
static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
{
int call_argc = get_u16(bc_buf + pos + 1);
scope = get_u16(bc_buf + pos + 1 + 2);
- mark_eval_captured_variables(ctx, s, scope);
+ if (mark_eval_captured_variables(ctx, s, scope))
+ goto fail;
dbuf_putc(&bc_out, op);
dbuf_put_u16(&bc_out, call_argc);
dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
break;
case OP_apply_eval: /* convert scope index to adjusted variable index */
scope = get_u16(bc_buf + pos + 1);
- mark_eval_captured_variables(ctx, s, scope);
+ if (mark_eval_captured_variables(ctx, s, scope))
+ goto fail;
dbuf_putc(&bc_out, op);
dbuf_put_u16(&bc_out, s->scopes[scope].first - ARG_SCOPE_END);
break;
scope = get_u16(bc_buf + pos + 5);
pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
NULL, NULL, pos_next);
+ if (pos_next < 0)
+ goto fail;
JS_FreeAtom(ctx, var_name);
break;
case OP_scope_make_ref:
ls->ref_count--; /* always remove label reference */
pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
bc_buf, ls, pos_next);
+ if (pos_next < 0)
+ goto fail;
JS_FreeAtom(ctx, var_name);
}
break;
if (s->jump_size) {
s->jump_slots = js_mallocz(s->ctx, sizeof(*s->jump_slots) * s->jump_size);
if (s->jump_slots == NULL)
- return -1;
+ goto fail;
}
#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);
if (s->line_number_slots == NULL)
- return -1;
+ goto fail;
s->line_number_last = s->source_pos;
s->line_number_last_pc = 0;
}
/* 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]);
+ for(i = 0; i < s->arg_count; i++) {
+ if (capture_var(s, &s->args[i]))
+ goto fail;
+ }
}
if (s->arguments_arg_idx >= 0)
put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
are used to compile the eval and they must be ordered by scope,
so it is necessary to create the closure variables before any
other variable lookup is done. */
- if (fd->has_eval_call)
- add_eval_variables(ctx, fd);
+ if (fd->has_eval_call) {
+ if (add_eval_variables(ctx, fd))
+ goto fail;
+ }
/* add the module global variables in the closure */
if (fd->is_eval) {