summaryrefslogtreecommitdiff
path: root/quickjs.c
diff options
context:
space:
mode:
authorbellard <6490144+bellard@users.noreply.github.com>2020-11-08 14:30:56 +0100
committerbellard <6490144+bellard@users.noreply.github.com>2020-11-08 14:30:56 +0100
commitb1f67dfc1a7372dd665246cf1c203528e5057e42 (patch)
treeb68346b1d20aa2e709c44a4f7ea902dd3ba6336f /quickjs.c
parent7c312df422572cf867f29a1d80693e8a77f7fb2a (diff)
downloadquickjs-b1f67dfc1a7372dd665246cf1c203528e5057e42.tar.gz
quickjs-b1f67dfc1a7372dd665246cf1c203528e5057e42.zip
2020-11-08 release
Diffstat (limited to 'quickjs.c')
-rw-r--r--quickjs.c2541
1 files changed, 1383 insertions, 1158 deletions
diff --git a/quickjs.c b/quickjs.c
index efc1d54..a39ff8f 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -199,7 +199,7 @@ typedef enum JSErrorEnum {
} JSErrorEnum;
#define JS_MAX_LOCAL_VARS 65536
-#define JS_STACK_SIZE_MAX 65536
+#define JS_STACK_SIZE_MAX 65534
#define JS_STRING_LEN_MAX ((1 << 30) - 1)
#define __exception __attribute__((warn_unused_result))
@@ -506,14 +506,17 @@ typedef struct JSClosureVar {
uint8_t is_arg : 1;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
- uint8_t var_kind : 3; /* see JSVarKindEnum */
- /* 9 bits available */
+ uint8_t var_kind : 4; /* see JSVarKindEnum */
+ /* 8 bits available */
uint16_t var_idx; /* is_local = TRUE: index to a normal variable of the
parent function. otherwise: index to a closure
variable of the parent function */
JSAtom var_name;
} JSClosureVar;
+#define ARG_SCOPE_INDEX 1
+#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 */
@@ -526,6 +529,7 @@ typedef enum {
JS_VAR_NEW_FUNCTION_DECL, /* lexical var with async/generator
function declaration */
JS_VAR_CATCH,
+ JS_VAR_FUNCTION_NAME, /* function expression name */
JS_VAR_PRIVATE_FIELD,
JS_VAR_PRIVATE_METHOD,
JS_VAR_PRIVATE_GETTER,
@@ -533,12 +537,21 @@ typedef enum {
JS_VAR_PRIVATE_GETTER_SETTER, /* must come after JS_VAR_PRIVATE_SETTER */
} JSVarKindEnum;
+/* XXX: could use a different structure in bytecode functions to save
+ memory */
typedef struct JSVarDef {
JSAtom var_name;
- int scope_level; /* index into fd->scopes of this variable lexical scope */
- int scope_next; /* index into fd->vars of the next variable in the
- * same or enclosing lexical scope */
- uint8_t is_func_var : 1; /* used for the function self reference */
+ /* index into fd->scopes of this variable lexical scope */
+ int scope_level;
+ /* 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;
uint8_t is_const : 1;
uint8_t is_lexical : 1;
uint8_t is_captured : 1;
@@ -548,7 +561,9 @@ typedef struct JSVarDef {
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_or_scope_idx : 24; /* only used during compilation */
+ int func_pool_idx : 24; /* only used during compilation : index in
+ the constant pool for hoisted function
+ definition */
} JSVarDef;
/* for the encoding of the pc2line table */
@@ -855,7 +870,7 @@ struct JSObject {
uint8_t extensible : 1;
uint8_t free_mark : 1; /* only used when freeing objects with cycles */
uint8_t is_exotic : 1; /* TRUE if object has exotic property handlers */
- uint8_t fast_array : 1; /* TRUE if u.array is used for get/put */
+ uint8_t fast_array : 1; /* TRUE if u.array is used for get/put (for JS_CLASS_ARRAY, JS_CLASS_ARGUMENTS and typed arrays) */
uint8_t is_constructor : 1; /* TRUE if object is a constructor function */
uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */
uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */
@@ -1000,7 +1015,7 @@ static JSValue JS_CallFree(JSContext *ctx, JSValue func_obj, JSValueConst this_o
static JSValue JS_InvokeFree(JSContext *ctx, JSValue this_val, JSAtom atom,
int argc, JSValueConst *argv);
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val);
+ JSValue val, BOOL is_array_ctor);
static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
JSValueConst val, int flags, int scope_idx);
JSValue __attribute__((format(printf, 2, 3))) JS_ThrowInternalError(JSContext *ctx, const char *fmt, ...);
@@ -1226,11 +1241,11 @@ static void add_gc_object(JSRuntime *rt, JSGCObjectHeader *h,
JSGCObjectTypeEnum type);
static void remove_gc_object(JSGCObjectHeader *h);
static void js_async_function_free0(JSRuntime *rt, JSAsyncFunctionData *s);
-static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
-static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
void *opaque);
-static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque);
+static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque);
void JS_SetUncatchableError(JSContext *ctx, JSValueConst val, BOOL flag);
static const JSClassExoticMethods js_arguments_exotic_methods;
@@ -6710,6 +6725,21 @@ static JSValue JS_ThrowReferenceErrorUninitialized(JSContext *ctx, JSAtom name)
JS_AtomGetStr(ctx, buf, sizeof(buf), name));
}
+static JSValue JS_ThrowReferenceErrorUninitialized2(JSContext *ctx,
+ JSFunctionBytecode *b,
+ int idx, BOOL is_ref)
+{
+ JSAtom atom = JS_ATOM_NULL;
+ if (is_ref) {
+ atom = b->closure_var[idx].var_name;
+ } else {
+ /* not present if the function is stripped and contains no eval() */
+ if (b->vardefs)
+ atom = b->vardefs[b->arg_count + idx].var_name;
+ }
+ return JS_ThrowReferenceErrorUninitialized(ctx, atom);
+}
+
static JSValue JS_ThrowTypeErrorInvalidClass(JSContext *ctx, int class_id)
{
JSRuntime *rt = ctx->rt;
@@ -6986,25 +7016,37 @@ int JS_IsInstanceOf(JSContext *ctx, JSValueConst val, JSValueConst obj)
return JS_OrdinaryIsInstanceOf(ctx, val, obj);
}
-typedef int JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
+/* return the value associated to the autoinit property or an exception */
+typedef JSValue JSAutoInitFunc(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque);
static JSAutoInitFunc *js_autoinit_func_table[] = {
js_instantiate_prototype, /* JS_AUTOINIT_ID_PROTOTYPE */
js_module_ns_autoinit, /* JS_AUTOINIT_ID_MODULE_NS */
- JS_InstantiateFunctionListItem, /* JS_AUTOINIT_ID_PROP */
+ JS_InstantiateFunctionListItem2, /* JS_AUTOINIT_ID_PROP */
};
+/* warning: 'prs' is reallocated after it */
static int JS_AutoInitProperty(JSContext *ctx, JSObject *p, JSAtom prop,
- JSProperty *pr)
+ JSProperty *pr, JSShapeProperty *prs)
{
- int ret;
+ JSValue val;
JSContext *realm;
JSAutoInitFunc *func;
-
+
+ if (js_shape_prepare_update(ctx, p, &prs))
+ return -1;
+
realm = js_autoinit_get_realm(pr);
func = js_autoinit_func_table[js_autoinit_get_id(pr)];
- ret = func(realm, p, prop, pr->u.init.opaque);
- return ret;
+ /* 'func' shall not modify the object properties 'pr' */
+ val = func(realm, p, prop, pr->u.init.opaque);
+ js_autoinit_free(ctx->rt, pr);
+ prs->flags &= ~JS_PROP_TMASK;
+ pr->u.value = JS_UNDEFINED;
+ if (JS_IsException(val))
+ return -1;
+ pr->u.value = val;
+ return 0;
}
JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
@@ -7075,7 +7117,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
return JS_DupValue(ctx, val);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr))
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
return JS_EXCEPTION;
continue;
}
@@ -7093,7 +7135,7 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
return JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
} else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
- goto typed_array_oob;
+ return JS_UNDEFINED;
}
} else if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
@@ -7102,9 +7144,6 @@ JSValue JS_GetPropertyInternal(JSContext *ctx, JSValueConst obj,
if (ret != 0) {
if (ret < 0)
return JS_EXCEPTION;
- typed_array_oob:
- if (typed_array_is_detached(ctx, p))
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
return JS_UNDEFINED;
}
}
@@ -7337,6 +7376,22 @@ static int JS_CheckBrand(JSContext *ctx, JSValueConst obj, JSValueConst func)
return 0;
}
+static uint32_t js_string_obj_get_length(JSContext *ctx,
+ JSValueConst obj)
+{
+ JSObject *p;
+ JSString *p1;
+ uint32_t len = 0;
+
+ /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
+ p = JS_VALUE_GET_OBJ(obj);
+ if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
+ p1 = JS_VALUE_GET_STRING(p->u.object_data);
+ len = p1->len;
+ }
+ return len;
+}
+
static int num_keys_cmp(const void *p1, const void *p2, void *opaque)
{
JSContext *ctx = opaque;
@@ -7379,7 +7434,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
JSPropertyEnum *tab_atom, *tab_exotic;
JSAtom atom;
uint32_t num_keys_count, str_keys_count, sym_keys_count, atom_count;
- uint32_t num_index, str_index, sym_index, exotic_count;
+ uint32_t num_index, str_index, sym_index, exotic_count, exotic_keys_count;
BOOL is_enumerable, num_sorted;
uint32_t num_key;
JSAtomKindEnum kind;
@@ -7392,6 +7447,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
num_keys_count = 0;
str_keys_count = 0;
sym_keys_count = 0;
+ exotic_keys_count = 0;
exotic_count = 0;
tab_exotic = NULL;
sh = p->shape;
@@ -7425,19 +7481,13 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
if (p->is_exotic) {
if (p->fast_array) {
- /* the implicit GetOwnProperty raises an exception if the
- typed array is detached */
- if ((flags & (JS_GPN_SET_ENUM | JS_GPN_ENUM_ONLY)) &&
- (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
- typed_array_is_detached(ctx, p) &&
- typed_array_get_length(ctx, p) != 0) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
if (flags & JS_GPN_STRING_MASK) {
num_keys_count += p->u.array.count;
}
+ } else if (p->class_id == JS_CLASS_STRING) {
+ if (flags & JS_GPN_STRING_MASK) {
+ num_keys_count += js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ }
} else {
const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
if (em && em->get_own_property_names) {
@@ -7466,13 +7516,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
tab_exotic[i].is_enumerable = is_enumerable;
}
if (!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) {
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- num_keys_count++;
- } else if (kind == JS_ATOM_KIND_STRING) {
- str_keys_count++;
- } else {
- sym_keys_count++;
- }
+ exotic_keys_count++;
}
}
}
@@ -7482,7 +7526,7 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
/* fill them */
- atom_count = num_keys_count + str_keys_count + sym_keys_count;
+ atom_count = num_keys_count + str_keys_count + sym_keys_count + exotic_keys_count;
/* avoid allocating 0 bytes */
tab_atom = js_malloc(ctx, sizeof(tab_atom[0]) * max_int(atom_count, 1));
if (!tab_atom) {
@@ -7518,12 +7562,19 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
}
if (p->is_exotic) {
+ int len;
if (p->fast_array) {
if (flags & JS_GPN_STRING_MASK) {
- for(i = 0; i < p->u.array.count; i++) {
+ len = p->u.array.count;
+ goto add_array_keys;
+ }
+ } else if (p->class_id == JS_CLASS_STRING) {
+ if (flags & JS_GPN_STRING_MASK) {
+ len = js_string_obj_get_length(ctx, JS_MKPTR(JS_TAG_OBJECT, p));
+ add_array_keys:
+ for(i = 0; i < len; i++) {
tab_atom[num_index].atom = __JS_AtomFromUInt32(i);
if (tab_atom[num_index].atom == JS_ATOM_NULL) {
- js_free_prop_enum(ctx, tab_exotic, exotic_count);
js_free_prop_enum(ctx, tab_atom, num_index);
return -1;
}
@@ -7531,30 +7582,23 @@ static int __exception JS_GetOwnPropertyNamesInternal(JSContext *ctx,
num_index++;
}
}
- }
- if (exotic_count > 0) {
+ } else {
+ /* Note: exotic keys are not reordered and comes after the object own properties. */
for(i = 0; i < exotic_count; i++) {
atom = tab_exotic[i].atom;
is_enumerable = tab_exotic[i].is_enumerable;
kind = JS_AtomGetKind(ctx, atom);
if ((!(flags & JS_GPN_ENUM_ONLY) || is_enumerable) &&
((flags >> kind) & 1) != 0) {
- if (JS_AtomIsArrayIndex(ctx, &num_key, atom)) {
- j = num_index++;
- num_sorted = FALSE;
- } else if (kind == JS_ATOM_KIND_STRING) {
- j = str_index++;
- } else {
- j = sym_index++;
- }
- tab_atom[j].atom = atom;
- tab_atom[j].is_enumerable = is_enumerable;
+ tab_atom[sym_index].atom = atom;
+ tab_atom[sym_index].is_enumerable = is_enumerable;
+ sym_index++;
} else {
JS_FreeAtom(ctx, atom);
}
}
+ js_free(ctx, tab_exotic);
}
- js_free(ctx, tab_exotic);
}
assert(num_index == num_keys_count);
@@ -7614,7 +7658,7 @@ retry:
desc->value = JS_DupValue(ctx, val);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry */
- if (JS_AutoInitProperty(ctx, p, prop, pr))
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
return -1;
goto retry;
}
@@ -7642,10 +7686,8 @@ retry:
idx = __JS_AtomToUInt32(prop);
if (idx < p->u.array.count) {
if (desc) {
- desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE;
- if (p->class_id == JS_CLASS_ARRAY ||
- p->class_id == JS_CLASS_ARGUMENTS)
- desc->flags |= JS_PROP_CONFIGURABLE;
+ desc->flags = JS_PROP_WRITABLE | JS_PROP_ENUMERABLE |
+ JS_PROP_CONFIGURABLE;
desc->getter = JS_UNDEFINED;
desc->setter = JS_UNDEFINED;
desc->value = JS_GetPropertyUint32(ctx, JS_MKPTR(JS_TAG_OBJECT, p), idx);
@@ -7653,19 +7695,6 @@ retry:
return TRUE;
}
}
- if (p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) {
- int ret;
- ret = JS_AtomIsNumericIndex(ctx, prop);
- if (ret != 0) {
- if (ret < 0)
- return -1;
- if (typed_array_is_detached(ctx, p)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
- }
- }
} else {
const JSClassExoticMethods *em = ctx->rt->class_array[p->class_id].exotic;
if (em && em->get_own_property) {
@@ -7748,8 +7777,6 @@ int JS_HasProperty(JSContext *ctx, JSValueConst obj, JSAtom prop)
if (ret != 0) {
if (ret < 0)
return -1;
- /* the detached array test was done in
- JS_GetOwnPropertyInternal() */
return FALSE;
}
}
@@ -8074,7 +8101,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom)
return -1;
goto redo;
} else {
- return FALSE; /* not configurable */
+ return FALSE;
}
}
} else {
@@ -8114,15 +8141,19 @@ static int call_setter(JSContext *ctx, JSObject *setter,
}
/* set the array length and remove the array elements if necessary. */
-static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags)
+static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
+ int flags)
{
uint32_t len, idx, cur_len;
int i, ret;
/* Note: this call can reallocate the properties of 'p' */
- ret = JS_ToArrayLengthFree(ctx, &len, val);
+ ret = JS_ToArrayLengthFree(ctx, &len, val, FALSE);
if (ret)
return -1;
+ /* JS_ToArrayLengthFree() must be done before the read-only test */
+ if (unlikely(!(p->shape->prop[0].flags & JS_PROP_WRITABLE)))
+ return JS_ThrowTypeErrorReadOnly(ctx, flags, JS_ATOM_length);
if (likely(p->fast_array)) {
uint32_t old_len = p->u.array.count;
@@ -8382,8 +8413,7 @@ retry:
/* fast case */
set_value(ctx, &pr->u.value, val);
return TRUE;
- } else if ((prs->flags & (JS_PROP_LENGTH | JS_PROP_WRITABLE)) ==
- (JS_PROP_LENGTH | JS_PROP_WRITABLE)) {
+ } else if (prs->flags & JS_PROP_LENGTH) {
assert(p->class_id == JS_CLASS_ARRAY);
assert(prop == JS_ATOM_length);
return set_array_length(ctx, p, val, flags);
@@ -8399,7 +8429,7 @@ retry:
return TRUE;
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p, prop, pr)) {
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs)) {
JS_FreeValue(ctx, val);
return -1;
}
@@ -8437,10 +8467,6 @@ retry:
JS_FreeValue(ctx, val);
if (JS_IsException(val))
return -1;
- if (typed_array_is_detached(ctx, p1)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- }
return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
}
}
@@ -8509,7 +8535,7 @@ retry:
return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags);
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
/* Instantiate property and retry (potentially useless) */
- if (JS_AutoInitProperty(ctx, p1, prop, pr))
+ if (JS_AutoInitProperty(ctx, p1, prop, pr, prs))
return -1;
goto retry2;
} else if (!(prs->flags & JS_PROP_WRITABLE)) {
@@ -8677,12 +8703,7 @@ static int JS_SetPropertyValue(JSContext *ctx, JSValueConst this_obj,
return -1;
if (unlikely(idx >= (uint32_t)p->u.array.count)) {
ta_out_of_bound:
- if (typed_array_is_detached(ctx, p)) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- return -1;
- } else {
- return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
- }
+ return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound numeric index");
}
p->u.array.u.double_ptr[idx] = d;
break;
@@ -8967,13 +8988,32 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
redo_prop_update:
prs = find_own_property(&pr, p, prop);
if (prs) {
+ /* the range of the Array length property is always tested before */
+ if ((prs->flags & JS_PROP_LENGTH) && (flags & JS_PROP_HAS_VALUE)) {
+ uint32_t array_length;
+ if (JS_ToArrayLengthFree(ctx, &array_length,
+ JS_DupValue(ctx, val), FALSE)) {
+ return -1;
+ }
+ /* this code relies on the fact that Uint32 are never allocated */
+ val = (JSValueConst)JS_NewUint32(ctx, array_length);
+ /* prs may have been modified */
+ prs = find_own_property(&pr, p, prop);
+ assert(prs != NULL);
+ }
/* property already exists */
if (!check_define_prop_flags(prs->flags, flags)) {
not_configurable:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "property is not configurable");
}
- retry:
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
+ /* Instantiate property and retry */
+ if (JS_AutoInitProperty(ctx, p, prop, pr, prs))
+ return -1;
+ goto redo_prop_update;
+ }
+
if (flags & (JS_PROP_HAS_VALUE | JS_PROP_HAS_WRITABLE |
JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET)) {
@@ -8996,14 +9036,6 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
/* convert to getset */
if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
free_var_ref(ctx->rt, pr->u.var_ref);
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* clear property and update */
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- js_autoinit_free(ctx->rt, pr);
- prs->flags &= ~JS_PROP_TMASK;
- pr->u.value = JS_UNDEFINED;
- goto retry;
} else {
JS_FreeValue(ctx, pr->u.value);
}
@@ -9051,39 +9083,17 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
pr->u.value = JS_UNDEFINED;
} else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
/* Note: JS_PROP_VARREF is always writable */
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* clear property and update */
- if (js_shape_prepare_update(ctx, p, &prs))
- return -1;
- js_autoinit_free(ctx->rt, pr);
- prs->flags &= ~JS_PROP_TMASK;
- pr->u.value = JS_UNDEFINED;
} else {
if ((prs->flags & (JS_PROP_CONFIGURABLE | JS_PROP_WRITABLE)) == 0 &&
- (flags & JS_PROP_HAS_VALUE) &&
- !js_same_value(ctx, val, pr->u.value)) {
- goto not_configurable;
+ (flags & JS_PROP_HAS_VALUE)) {
+ if (!js_same_value(ctx, val, pr->u.value)) {
+ goto not_configurable;
+ } else {
+ return TRUE;
+ }
}
}
- if (prs->flags & JS_PROP_LENGTH) {
- if (flags & JS_PROP_HAS_VALUE) {
- res = set_array_length(ctx, p, JS_DupValue(ctx, val),
- flags);
- } else {
- res = TRUE;
- }
- /* still need to reset the writable flag if needed.
- The JS_PROP_LENGTH is reset to have the correct
- read-only behavior in JS_SetProperty(). */
- if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
- JS_PROP_HAS_WRITABLE) {
- prs = get_shape_prop(p->shape);
- if (js_update_property_flags(ctx, p, &prs,
- prs->flags & ~(JS_PROP_WRITABLE | JS_PROP_LENGTH)))
- return -1;
- }
- return res;
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
+ if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) {
if (flags & JS_PROP_HAS_VALUE) {
if (p->class_id == JS_CLASS_MODULE_NS) {
/* JS_PROP_WRITABLE is always true for variable
@@ -9107,9 +9117,27 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
pr->u.value = val1;
prs->flags &= ~(JS_PROP_TMASK | JS_PROP_WRITABLE);
}
- } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_AUTOINIT) {
- /* XXX: should never happen, type was reset above */
- abort();
+ } else if (prs->flags & JS_PROP_LENGTH) {
+ if (flags & JS_PROP_HAS_VALUE) {
+ /* Note: no JS code is executable because
+ 'val' is guaranted to be a Uint32 */
+ res = set_array_length(ctx, p, JS_DupValue(ctx, val),
+ flags);
+ } else {
+ res = TRUE;
+ }
+ /* still need to reset the writable flag if
+ needed. The JS_PROP_LENGTH is kept because the
+ Uint32 test is still done if the length
+ property is read-only. */
+ if ((flags & (JS_PROP_HAS_WRITABLE | JS_PROP_WRITABLE)) ==
+ JS_PROP_HAS_WRITABLE) {
+ prs = get_shape_prop(p->shape);
+ if (js_update_property_flags(ctx, p, &prs,
+ prs->flags & ~JS_PROP_WRITABLE))
+ return -1;
+ }
+ return res;
} else {
if (flags & JS_PROP_HAS_VALUE) {
JS_FreeValue(ctx, pr->u.value);
@@ -9194,9 +9222,9 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj,
typed_array_oob:
return JS_ThrowTypeErrorOrFalse(ctx, flags, "out-of-bound index in typed array");
}
- prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE);
+ prop_flags = get_prop_flags(flags, JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
if (flags & (JS_PROP_HAS_GET | JS_PROP_HAS_SET) ||
- prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE)) {
+ prop_flags != (JS_PROP_ENUMERABLE | JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE)) {
return JS_ThrowTypeErrorOrFalse(ctx, flags, "invalid descriptor flags");
}
if (flags & JS_PROP_HAS_VALUE) {
@@ -9581,9 +9609,8 @@ static int JS_SetGlobalVar(JSContext *ctx, JSAtom prop, JSValue val,
set_value(ctx, &pr->u.value, val);
return 0;
}
-
flags = JS_PROP_THROW_STRICT;
- if (flag != 2 && is_strict_mode(ctx))
+ if (is_strict_mode(ctx))
flags |= JS_PROP_NO_ADD;
return JS_SetPropertyInternal(ctx, ctx->global_obj, prop, val, flags);
}
@@ -10918,11 +10945,10 @@ static int JS_ToUint8ClampFree(JSContext *ctx, int32_t *pres, JSValue val)
}
static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
- JSValue val)
+ JSValue val, BOOL is_array_ctor)
{
uint32_t tag, len;
- redo:
tag = JS_VALUE_GET_TAG(val);
switch(tag) {
case JS_TAG_INT:
@@ -10959,16 +10985,36 @@ static __exception int JS_ToArrayLengthFree(JSContext *ctx, uint32_t *plen,
double d;
d = JS_VALUE_GET_FLOAT64(val);
len = (uint32_t)d;
- if (len != d) {
- fail:
- JS_ThrowRangeError(ctx, "invalid array length");
- return -1;
- }
+ if (len != d)
+ goto fail;
} else {
- val = JS_ToNumberFree(ctx, val);
- if (JS_IsException(val))
- return -1;
- goto redo;
+ uint32_t len1;
+
+ if (is_array_ctor) {
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len, val, TRUE))
+ return -1;
+ } else {
+ /* legacy behavior: must do the conversion twice and compare */
+ if (JS_ToUint32(ctx, &len, val)) {
+ JS_FreeValue(ctx, val);
+ return -1;
+ }
+ val = JS_ToNumberFree(ctx, val);
+ if (JS_IsException(val))
+ return -1;
+ /* cannot recurse because val is a number */
+ if (JS_ToArrayLengthFree(ctx, &len1, val, FALSE))
+ return -1;
+ if (len1 != len) {
+ fail:
+ JS_ThrowRangeError(ctx, "invalid array length");
+ return -1;
+ }
+ }
}
break;
}
@@ -15031,15 +15077,6 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
if (prs->flags & JS_PROP_ENUMERABLE)
goto normal_case;
}
- /* the implicit GetOwnProperty raises an exception if the
- typed array is detached */
- if ((p->class_id >= JS_CLASS_UINT8C_ARRAY &&
- p->class_id <= JS_CLASS_FLOAT64_ARRAY) &&
- typed_array_is_detached(ctx, p) &&
- typed_array_get_length(ctx, p) != 0) {
- JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
- goto fail;
- }
/* for fast arrays, we only store the number of elements */
it->is_array = TRUE;
it->array_length = p->u.array.count;
@@ -15349,16 +15386,6 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset)
return 0;
}
-static __exception int js_for_await_of_next(JSContext *ctx, JSValue *sp)
-{
- JSValue result;
- result = JS_Call(ctx, sp[-2], sp[-3], 0, NULL);
- if (JS_IsException(result))
- return -1;
- sp[0] = result;
- return 0;
-}
-
static JSValue JS_IteratorGetCompleteValue(JSContext *ctx, JSValueConst obj,
BOOL *pdone)
{
@@ -15663,7 +15690,7 @@ static JSValue js_closure2(JSContext *ctx, JSValue func_obj,
return JS_EXCEPTION;
}
-static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
+static JSValue js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, void *opaque)
{
JSValue obj, this_val;
int ret;
@@ -15671,15 +15698,17 @@ static int js_instantiate_prototype(JSContext *ctx, JSObject *p, JSAtom atom, vo
this_val = JS_MKPTR(JS_TAG_OBJECT, p);
obj = JS_NewObject(ctx);
if (JS_IsException(obj))
- return -1;
+ return JS_EXCEPTION;
set_cycle_flag(ctx, obj);
set_cycle_flag(ctx, this_val);
ret = JS_DefinePropertyValue(ctx, obj, JS_ATOM_constructor,
JS_DupValue(ctx, this_val),
JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE);
- if (JS_DefinePropertyValue(ctx, this_val, atom, obj, JS_PROP_WRITABLE) < 0 || ret < 0)
- return -1;
- return 0;
+ if (ret < 0) {
+ JS_FreeValue(ctx, obj);
+ return JS_EXCEPTION;
+ }
+ return obj;
}
static const uint16_t func_kind_to_class_id[] = {
@@ -16645,11 +16674,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
JS_Throw(ctx, *--sp);
goto exception;
- CASE(OP_throw_var):
+ CASE(OP_throw_error):
#define JS_THROW_VAR_RO 0
#define JS_THROW_VAR_REDECL 1
#define JS_THROW_VAR_UNINITIALIZED 2
-#define JS_THROW_VAR_DELETE_SUPER 3
+#define JS_THROW_ERROR_DELETE_SUPER 3
+#define JS_THROW_ERROR_ITERATOR_THROW 4
{
JSAtom atom;
int type;
@@ -16665,9 +16695,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
if (type == JS_THROW_VAR_UNINITIALIZED)
JS_ThrowReferenceErrorUninitialized(ctx, atom);
else
- if (type == JS_THROW_VAR_DELETE_SUPER)
+ if (type == JS_THROW_ERROR_DELETE_SUPER)
JS_ThrowReferenceError(ctx, "unsupported reference to 'super'");
else
+ if (type == JS_THROW_ERROR_ITERATOR_THROW)
+ JS_ThrowTypeError(ctx, "iterator does not have a throw method");
+ else
JS_ThrowInternalError(ctx, "invalid throw var type %d", type);
}
goto exception;
@@ -16995,7 +17028,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
pc += 2;
val = *var_refs[idx]->pvalue;
if (unlikely(JS_IsUninitialized(val))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
sp[0] = JS_DupValue(ctx, val);
@@ -17008,7 +17041,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
@@ -17021,7 +17054,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(!JS_IsUninitialized(*var_refs[idx]->pvalue))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, TRUE);
goto exception;
}
set_value(ctx, var_refs[idx]->pvalue, sp[-1]);
@@ -17042,7 +17075,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
goto exception;
}
sp[0] = JS_DupValue(ctx, var_buf[idx]);
@@ -17055,7 +17088,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
idx = get_u16(pc);
pc += 2;
if (unlikely(JS_IsUninitialized(var_buf[idx]))) {
- JS_ThrowReferenceErrorUninitialized(ctx, JS_ATOM_NULL);
+ JS_ThrowReferenceErrorUninitialized2(ctx, b, idx, FALSE);
goto exception;
}
set_value(ctx, &var_buf[idx], sp[-1]);
@@ -17294,16 +17327,17 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
sp += 1;
*sp++ = JS_NewCatchOffset(ctx, 0);
BREAK;
- CASE(OP_for_await_of_next):
- if (js_for_await_of_next(ctx, sp))
- goto exception;
- sp += 1;
- BREAK;
CASE(OP_iterator_get_value_done):
if (js_iterator_get_value_done(ctx, sp))
goto exception;
sp += 1;
BREAK;
+ CASE(OP_iterator_check_object):
+ if (unlikely(!JS_IsObject(sp[-1]))) {
+ JS_ThrowTypeError(ctx, "iterator must return an object");
+ goto exception;
+ }
+ BREAK;
CASE(OP_iterator_close):
/* iter_obj next catch_offset -> */
@@ -17340,37 +17374,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
- CASE(OP_async_iterator_close):
- /* iter_obj next catch_offset -> value flag */
- {
- JSValue ret, method;
- int ret_flag;
- sp--; /* remove the catch offset */
- method = JS_GetProperty(ctx, sp[-2], JS_ATOM_return);
- if (JS_IsException(method))
- goto exception;
- if (JS_IsUndefined(method) || JS_IsNull(method)) {
- ret = JS_UNDEFINED;
- ret_flag = TRUE;
- } else {
- ret = JS_CallFree(ctx, method, sp[-2], 0, NULL);
- if (JS_IsException(ret))
- goto exception;
- if (!JS_IsObject(ret)) {
- JS_FreeValue(ctx, ret);
- JS_ThrowTypeErrorNotAnObject(ctx);
- goto exception;
- }
- ret_flag = FALSE;
- }
- JS_FreeValue(ctx, sp[-2]);
- JS_FreeValue(ctx, sp[-1]);
- sp[-2] = ret;
- sp[-1] = JS_NewBool(ctx, ret_flag);
- }
- BREAK;
-
- CASE(OP_async_iterator_next):
+ CASE(OP_iterator_next):
/* stack: iter_obj next catch_offset val */
{
JSValue ret;
@@ -17383,26 +17387,28 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
}
BREAK;
- CASE(OP_async_iterator_get):
+ CASE(OP_iterator_call):
/* stack: iter_obj next catch_offset val */
{
JSValue method, ret;
BOOL ret_flag;
int flags;
flags = *pc++;
- /* XXX: use another opcode such as OP_throw_var */
- if (flags == 2) {
- JS_ThrowTypeError(ctx, "iterator does not have a throw method");
- goto exception;
- }
- method = JS_GetProperty(ctx, sp[-4], flags ? JS_ATOM_throw : JS_ATOM_return);
+ method = JS_GetProperty(ctx, sp[-4], (flags & 1) ?
+ JS_ATOM_throw : JS_ATOM_return);
if (JS_IsException(method))
goto exception;
if (JS_IsUndefined(method) || JS_IsNull(method)) {
ret_flag = TRUE;
} else {
- ret = JS_CallFree(ctx, method, sp[-4],
- 1, (JSValueConst *)(sp - 1));
+ if (flags & 2) {
+ /* no argument */
+ ret = JS_CallFree(ctx, method, sp[-4],
+ 0, NULL);
+ } else {
+ ret = JS_CallFree(ctx, method, sp[-4],
+ 1, (JSValueConst *)(sp - 1));
+ }
if (JS_IsException(ret))
goto exception;
JS_FreeValue(ctx, sp[-1]);
@@ -17728,7 +17734,8 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
CASE(OP_put_ref_value):
{
- int ret;
+ int ret, flags;
+ flags = JS_PROP_THROW_STRICT;
if (unlikely(JS_IsUndefined(sp[-3]))) {
if (is_strict_mode(ctx)) {
JSAtom atom = JS_ValueToAtom(ctx, sp[-2]);
@@ -17740,8 +17747,11 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
} else {
sp[-3] = JS_DupValue(ctx, ctx->global_obj);
}
+ } else {
+ if (is_strict_mode(ctx))
+ flags |= JS_PROP_NO_ADD;
}
- ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], JS_PROP_THROW_STRICT);
+ ret = JS_SetPropertyValue(ctx, sp[-3], sp[-2], sp[-1], flags);
JS_FreeValue(ctx, sp[-3]);
sp -= 3;
if (unlikely(ret < 0))
@@ -18084,8 +18094,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val + 1);
} else {
inc_loc_slow:
- if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_inc))
+ /* must duplicate otherwise the variable value may
+ be destroyed before JS code accesses it */
+ op1 = JS_DupValue(ctx, op1);
+ if (js_unary_arith_slow(ctx, &op1 + 1, OP_inc))
goto exception;
+ set_value(ctx, &var_buf[idx], op1);
}
}
BREAK;
@@ -18105,8 +18119,12 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
var_buf[idx] = JS_NewInt32(ctx, val - 1);
} else {
dec_loc_slow:
- if (js_unary_arith_slow(ctx, var_buf + idx + 1, OP_dec))
+ /* must duplicate otherwise the variable value may
+ be destroyed before JS code accesses it */
+ op1 = JS_DupValue(ctx, op1);
+ if (js_unary_arith_slow(ctx, &op1 + 1, OP_dec))
goto exception;
+ set_value(ctx, &var_buf[idx], op1);
}
}
BREAK;
@@ -18432,6 +18450,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
set_value(ctx, &sp[-1], val);
break;
case OP_with_put_var:
+ /* XXX: check if strict mode */
ret = JS_SetPropertyInternal(ctx, obj, atom, sp[-2],
JS_PROP_THROW_STRICT);
JS_FreeValue(ctx, sp[-1]);
@@ -18922,13 +18941,11 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
JSGeneratorData *s = JS_GetOpaque(this_val, JS_CLASS_GENERATOR);
JSStackFrame *sf;
JSValue ret, func_ret;
- JSValueConst iter_args[1];
*pdone = TRUE;
if (!s)
return JS_ThrowTypeError(ctx, "not a generator");
sf = &s->func_state.frame;
- redo:
switch(s->state) {
default:
case JS_GENERATOR_STATE_SUSPENDED_START:
@@ -18940,85 +18957,16 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
}
break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR:
- {
- int done;
- JSValue method, iter_obj;
-
- iter_obj = sf->cur_sp[-2];
- if (magic == GEN_MAGIC_NEXT) {
- method = JS_DupValue(ctx, sf->cur_sp[-1]);
- } else {
- method = JS_GetProperty(ctx, iter_obj,
- magic == GEN_MAGIC_RETURN ?
- JS_ATOM_return : JS_ATOM_throw);
- if (JS_IsException(method))
- goto iter_exception;
- }
- if (magic != GEN_MAGIC_NEXT &&
- (JS_IsUndefined(method) || JS_IsNull(method))) {
- /* default action */
- if (magic == GEN_MAGIC_RETURN) {
- ret = JS_DupValue(ctx, argv[0]);
- goto iter_done;
- } else {
- if (JS_IteratorClose(ctx, iter_obj, FALSE))
- goto iter_exception;
- JS_ThrowTypeError(ctx, "iterator does not have a throw method");
- goto iter_exception;
- }
- }
- ret = JS_IteratorNext2(ctx, iter_obj, method, argc, argv, &done);
- JS_FreeValue(ctx, method);
- if (JS_IsException(ret)) {
- iter_exception:
- goto exec_throw;
- }
- /* if not done, the iterator returns the exact object
- returned by 'method' */
- if (done == 2) {
- JSValue done_val, value;
- done_val = JS_GetProperty(ctx, ret, JS_ATOM_done);
- if (JS_IsException(done_val)) {
- JS_FreeValue(ctx, ret);
- goto iter_exception;
- }
- done = JS_ToBoolFree(ctx, done_val);
- if (done) {
- value = JS_GetProperty(ctx, ret, JS_ATOM_value);
- JS_FreeValue(ctx, ret);
- if (JS_IsException(value))
- goto iter_exception;
- ret = value;
- goto iter_done;
- } else {
- *pdone = 2;
- }
- } else {
- if (done) {
- /* 'yield *' returns the value associated to done = true */
- iter_done:
- JS_FreeValue(ctx, sf->cur_sp[-2]);
- JS_FreeValue(ctx, sf->cur_sp[-1]);
- sf->cur_sp--;
- goto exec_arg;
- } else {
- *pdone = FALSE;
- }
- }
- break;
- }
- break;
case JS_GENERATOR_STATE_SUSPENDED_YIELD:
/* cur_sp[-1] was set to JS_UNDEFINED in the previous call */
ret = JS_DupValue(ctx, argv[0]);
- if (magic == GEN_MAGIC_THROW) {
+ if (magic == GEN_MAGIC_THROW &&
+ s->state == JS_GENERATOR_STATE_SUSPENDED_YIELD) {
JS_Throw(ctx, ret);
- exec_throw:
s->func_state.throw_flag = TRUE;
} else {
- exec_arg:
sf->cur_sp[-1] = ret;
- sf->cur_sp[0] = JS_NewBool(ctx, (magic == GEN_MAGIC_RETURN));
+ sf->cur_sp[0] = JS_NewInt32(ctx, magic);
sf->cur_sp++;
exec_no_arg:
s->func_state.throw_flag = FALSE;
@@ -19032,17 +18980,14 @@ static JSValue js_generator_next(JSContext *ctx, JSValueConst this_val,
return func_ret;
}
if (JS_VALUE_GET_TAG(func_ret) == JS_TAG_INT) {
+ /* get the returned yield value at the top of the stack */
+ ret = sf->cur_sp[-1];
+ sf->cur_sp[-1] = JS_UNDEFINED;
if (JS_VALUE_GET_INT(func_ret) == FUNC_RET_YIELD_STAR) {
- /* 'yield *' */
s->state = JS_GENERATOR_STATE_SUSPENDED_YIELD_STAR;
- iter_args[0] = JS_UNDEFINED;
- argc = 1;
- argv = iter_args;
- goto redo;
+ /* return (value, done) object */
+ *pdone = 2;
} else {
- /* get the return the yield value at the top of the stack */
- ret = sf->cur_sp[-1];
- sf->cur_sp[-1] = JS_UNDEFINED;
*pdone = FALSE;
}
} else {
@@ -19853,15 +19798,15 @@ typedef struct BlockEnv {
int has_iterator;
} BlockEnv;
-typedef struct JSHoistedDef {
- int cpool_idx; /* -1 means variable global definition */
- uint8_t force_init : 1; /* initialize to undefined */
+typedef struct JSGlobalVar {
+ int cpool_idx; /* if >= 0, index in the constant pool for hoisted
+ function defintion*/
+ uint8_t force_init : 1; /* force initialization to undefined */
uint8_t is_lexical : 1; /* global let/const definition */
uint8_t is_const : 1; /* const definition */
- int var_idx; /* function object index if cpool_idx >= 0 */
int scope_level; /* scope of definition */
- JSAtom var_name; /* variable name if cpool_idx < 0 */
-} JSHoistedDef;
+ JSAtom var_name; /* variable name */
+} JSGlobalVar;
typedef struct RelocEntry {
struct RelocEntry *next;
@@ -19924,6 +19869,7 @@ typedef struct JSFunctionDef {
BOOL has_home_object; /* TRUE if the home object is available */
BOOL has_prototype; /* true if a prototype field is necessary */
BOOL has_simple_parameter_list;
+ BOOL has_parameter_expressions; /* if true, an argument scope is created */
BOOL has_use_strict; /* to reject directive in special cases */
BOOL has_eval_call; /* true if the function contains a call to eval() */
BOOL has_arguments_binding; /* true if the 'arguments' binding is
@@ -19951,7 +19897,10 @@ typedef struct JSFunctionDef {
int arg_count; /* number of arguments */
int defined_arg_count;
int var_object_idx; /* -1 if none */
+ int arg_var_object_idx; /* -1 if none (var object for the argument scope) */
int arguments_var_idx; /* -1 if none */
+ int arguments_arg_idx; /* argument variable definition in argument scope,
+ -1 if none */
int func_var_idx; /* variable containing the current function (-1
if none, only used if is_func_expr is true) */
int eval_ret_idx; /* variable containing the return value of the eval, -1 if none */
@@ -19967,10 +19916,11 @@ typedef struct JSFunctionDef {
int scope_count; /* number of entries used in the fd->scopes array */
JSVarScope *scopes;
JSVarScope def_scope_array[4];
+ int body_scope; /* scope of the body of the function or eval */
- int hoisted_def_count;
- int hoisted_def_size;
- JSHoistedDef *hoisted_def;
+ int global_var_count;
+ int global_var_size;
+ JSGlobalVar *global_vars;
DynBuf byte_code;
int last_opcode_pos; /* -1 if no last opcode */
@@ -21475,7 +21425,7 @@ static BOOL js_is_live_code(JSParseState *s) {
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_goto:
#if SHORT_OPCODES
case OP_goto8:
@@ -21647,6 +21597,21 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
return find_arg(ctx, fd, name);
}
+/* find a variable declaration in a given scope */
+static int find_var_in_scope(JSContext *ctx, JSFunctionDef *fd,
+ JSAtom name, int scope_level)
+{
+ int scope_idx;
+ for(scope_idx = fd->scopes[scope_level].first; scope_idx >= 0;
+ scope_idx = fd->vars[scope_idx].scope_next) {
+ if (fd->vars[scope_idx].scope_level != scope_level)
+ break;
+ if (fd->vars[scope_idx].var_name == name)
+ return scope_idx;
+ }
+ return -1;
+}
+
/* return true if scope == parent_scope or if scope is a child of
parent_scope */
static BOOL is_child_scope(JSContext *ctx, JSFunctionDef *fd,
@@ -21668,7 +21633,7 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
for(i = 0; i < fd->var_count; i++) {
JSVarDef *vd = &fd->vars[i];
if (vd->var_name == name && vd->scope_level == 0) {
- if (is_child_scope(ctx, fd, vd->func_pool_or_scope_idx,
+ if (is_child_scope(ctx, fd, vd->scope_next,
scope_level))
return i;
}
@@ -21677,11 +21642,11 @@ static int find_var_in_child_scope(JSContext *ctx, JSFunctionDef *fd,
}
-static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name)
+static JSGlobalVar *find_global_var(JSFunctionDef *fd, JSAtom name)
{
int i;
- for(i = 0; i < fd->hoisted_def_count; i++) {
- JSHoistedDef *hf = &fd->hoisted_def[i];
+ for(i = 0; i < fd->global_var_count; i++) {
+ JSGlobalVar *hf = &fd->global_vars[i];
if (hf->var_name == name)
return hf;
}
@@ -21689,9 +21654,9 @@ static JSHoistedDef *find_hoisted_def(JSFunctionDef *fd, JSAtom name)
}
-static JSHoistedDef *find_lexical_hoisted_def(JSFunctionDef *fd, JSAtom name)
+static JSGlobalVar *find_lexical_global_var(JSFunctionDef *fd, JSAtom name)
{
- JSHoistedDef *hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf = find_global_var(fd, name);
if (hf && hf->is_lexical)
return hf;
else
@@ -21711,7 +21676,7 @@ static int find_lexical_decl(JSContext *ctx, JSFunctionDef *fd, JSAtom name,
}
if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_GLOBAL) {
- if (find_lexical_hoisted_def(fd, name))
+ if (find_lexical_global_var(fd, name))
return GLOBAL_VAR_OFFSET;
}
return -1;
@@ -21800,6 +21765,7 @@ static int add_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
vd = &fd->vars[fd->var_count++];
memset(vd, 0, sizeof(*vd));
vd->var_name = JS_DupAtom(ctx, name);
+ vd->func_pool_idx = -1;
return fd->var_count - 1;
}
@@ -21823,22 +21789,47 @@ static int add_func_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
int idx = fd->func_var_idx;
if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
fd->func_var_idx = idx;
- fd->vars[idx].is_func_var = TRUE;
+ fd->vars[idx].var_kind = JS_VAR_FUNCTION_NAME;
if (fd->js_mode & JS_MODE_STRICT)
fd->vars[idx].is_const = TRUE;
}
return idx;
}
-static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
+static int add_arguments_var(JSContext *ctx, JSFunctionDef *fd)
{
int idx = fd->arguments_var_idx;
- if (idx < 0 && (idx = add_var(ctx, fd, name)) >= 0) {
+ if (idx < 0 && (idx = add_var(ctx, fd, JS_ATOM_arguments)) >= 0) {
fd->arguments_var_idx = idx;
}
return idx;
}
+/* add an argument definition in the argument scope. Only needed when
+ "eval()" may be called in the argument scope. Return 0 if OK. */
+static int add_arguments_arg(JSContext *ctx, JSFunctionDef *fd)
+{
+ int idx;
+ if (fd->arguments_arg_idx < 0) {
+ idx = find_var_in_scope(ctx, fd, JS_ATOM_arguments, ARG_SCOPE_INDEX);
+ if (idx < 0) {
+ /* XXX: the scope links are not fully updated. May be an
+ issue if there are child scopes of the argument
+ scope */
+ idx = add_var(ctx, fd, JS_ATOM_arguments);
+ if (idx < 0)
+ return -1;
+ fd->vars[idx].scope_next = fd->scopes[ARG_SCOPE_INDEX].first;
+ fd->scopes[ARG_SCOPE_INDEX].first = idx;
+ fd->vars[idx].scope_level = ARG_SCOPE_INDEX;
+ fd->vars[idx].is_lexical = TRUE;
+
+ fd->arguments_arg_idx = idx;
+ }
+ }
+ return 0;
+}
+
static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
{
JSVarDef *vd;
@@ -21854,32 +21845,27 @@ static int add_arg(JSContext *ctx, JSFunctionDef *fd, JSAtom name)
vd = &fd->args[fd->arg_count++];
memset(vd, 0, sizeof(*vd));
vd->var_name = JS_DupAtom(ctx, name);
+ vd->func_pool_idx = -1;
return fd->arg_count - 1;
}
-/* add a Hoisted definition for a function (cpool_idx >= 0) or a
- global variable (cpool_idx = -1) */
-static JSHoistedDef *add_hoisted_def(JSContext *ctx,
- JSFunctionDef *s, int cpool_idx,
- JSAtom name, int var_idx, BOOL is_lexical)
+/* add a global variable definition */
+static JSGlobalVar *add_global_var(JSContext *ctx, JSFunctionDef *s,
+ JSAtom name)
{
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
- if (js_resize_array(ctx, (void **)&s->hoisted_def,
- sizeof(s->hoisted_def[0]),
- &s->hoisted_def_size, s->hoisted_def_count + 1))
+ if (js_resize_array(ctx, (void **)&s->global_vars,
+ sizeof(s->global_vars[0]),
+ &s->global_var_size, s->global_var_count + 1))
return NULL;
- hf = &s->hoisted_def[s->hoisted_def_count++];
- hf->cpool_idx = cpool_idx;
- hf->force_init = 0;
- hf->is_lexical = is_lexical;
+ hf = &s->global_vars[s->global_var_count++];
+ hf->cpool_idx = -1;
+ hf->force_init = FALSE;
+ hf->is_lexical = FALSE;
hf->is_const = FALSE;
- hf->var_idx = var_idx;
hf->scope_level = s->scope_level;
- hf->var_name = JS_ATOM_NULL;
- if (name != JS_ATOM_NULL) {
- hf->var_name = JS_DupAtom(ctx, name);
- }
+ hf->var_name = JS_DupAtom(ctx, name);
return hf;
}
@@ -21924,7 +21910,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
goto redef_lex_error;
}
} else {
- if (fd->scope_level == 1) {
+ if (fd->scope_level == fd->body_scope) {
redef_lex_error:
/* redefining a scoped var in the same scope: error */
return js_parse_error(s, "invalid redefinition of lexical identifier");
@@ -21933,7 +21919,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
}
if (var_def_type != JS_VAR_DEF_FUNCTION_DECL &&
var_def_type != JS_VAR_DEF_NEW_FUNCTION_DECL &&
- fd->scope_level == 1 &&
+ fd->scope_level == fd->body_scope &&
find_arg(ctx, fd, name) >= 0) {
/* lexical variable redefines a parameter name */
return js_parse_error(s, "invalid redefinition of parameter name");
@@ -21944,8 +21930,8 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
}
if (fd->is_global_var) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, name);
if (hf && is_child_scope(ctx, fd, hf->scope_level,
fd->scope_level)) {
return js_parse_error(s, "invalid redefinition of global identifier");
@@ -21955,11 +21941,12 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
if (fd->is_eval &&
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == 1) {
- JSHoistedDef *hf;
- hf = add_hoisted_def(s->ctx, fd, -1, name, -1, TRUE);
+ fd->scope_level == fd->body_scope) {
+ JSGlobalVar *hf;
+ hf = add_global_var(s->ctx, fd, name);
if (!hf)
return -1;
+ hf->is_lexical = TRUE;
hf->is_const = (var_def_type == JS_VAR_DEF_CONST);
idx = GLOBAL_VAR_OFFSET;
} else {
@@ -21991,13 +21978,13 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
return js_parse_error(s, "invalid redefinition of lexical identifier");
}
if (fd->is_global_var) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, name);
if (hf && hf->is_lexical && hf->scope_level == fd->scope_level &&
fd->eval_type == JS_EVAL_TYPE_MODULE) {
goto invalid_lexical_redefinition;
}
- hf = add_hoisted_def(s->ctx, fd, -1, name, -1, FALSE);
+ hf = add_global_var(s->ctx, fd, name);
if (!hf)
return -1;
idx = GLOBAL_VAR_OFFSET;
@@ -22010,7 +21997,7 @@ static int define_var(JSParseState *s, JSFunctionDef *fd, JSAtom name,
if (idx >= 0) {
if (name == JS_ATOM_arguments && fd->has_arguments_binding)
fd->arguments_var_idx = idx;
- fd->vars[idx].func_pool_or_scope_idx = fd->scope_level;
+ fd->vars[idx].scope_next = fd->scope_level;
}
}
break;
@@ -22052,8 +22039,9 @@ static __exception int js_parse_function_decl2(JSParseState *s,
int function_line_num,
JSParseExportEnum export_flag,
JSFunctionDef **pfd);
-static __exception int js_parse_assign_expr(JSParseState *s, int in_accepted);
-static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag);
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags);
+static __exception int js_parse_assign_expr(JSParseState *s);
+static __exception int js_parse_unary(JSParseState *s, int parse_flags);
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
JSAtom label_name,
int label_break, int label_cont,
@@ -22385,8 +22373,9 @@ static BOOL is_regexp_allowed(int tok)
}
}
-#define SKIP_HAS_SEMI (1 << 0)
-#define SKIP_HAS_ELLIPSIS (1 << 1)
+#define SKIP_HAS_SEMI (1 << 0)
+#define SKIP_HAS_ELLIPSIS (1 << 1)
+#define SKIP_HAS_ASSIGNMENT (1 << 2)
/* XXX: improve speed with early bailout */
/* XXX: no longer works if regexps are present. Could use previous
@@ -22459,7 +22448,10 @@ static int js_parse_skip_parens_token(JSParseState *s, int *pbits, BOOL no_line_
bits |= SKIP_HAS_ELLIPSIS;
}
break;
-
+ case '=':
+ bits |= SKIP_HAS_ASSIGNMENT;
+ break;
+
case TOK_DIV_ASSIGN:
tok_len = 2;
goto parse_regexp;
@@ -22574,7 +22566,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_op(s, OP_null); /* dummy excludeList */
emit_op(s, OP_copy_data_properties);
@@ -22633,7 +22625,7 @@ static __exception int js_parse_object_literal(JSParseState *s)
} else {
if (js_parse_expect(s, ':'))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
if (name == JS_ATOM_NULL) {
set_object_name_computed(s);
@@ -22668,8 +22660,23 @@ static __exception int js_parse_object_literal(JSParseState *s)
return -1;
}
-static __exception int js_parse_postfix_expr(JSParseState *s,
- BOOL accept_lparen);
+/* allow the 'in' binary operator */
+#define PF_IN_ACCEPTED (1 << 0)
+/* allow function calls parsing in js_parse_postfix_expr() */
+#define PF_POSTFIX_CALL (1 << 1)
+/* allow arrow functions parsing in js_parse_postfix_expr() */
+#define PF_ARROW_FUNC (1 << 2)
+/* allow the exponentiation operator in js_parse_unary() */
+#define PF_POW_ALLOWED (1 << 3)
+/* forbid the exponentiation operator in js_parse_unary() */
+#define PF_POW_FORBIDDEN (1 << 4)
+
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags);
+
+static __exception int js_parse_left_hand_side_expr(JSParseState *s)
+{
+ return js_parse_postfix_expr(s, PF_POSTFIX_CALL);
+}
/* XXX: is there is nicer solution ? */
static __exception int js_parse_class_default_ctor(JSParseState *s,
@@ -22873,8 +22880,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
class_flags = JS_DEFINE_CLASS_HAS_HERITAGE;
if (next_token(s))
goto fail;
- /* XXX: the grammar only allows LeftHandSideExpression */
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
goto fail;
} else {
emit_op(s, OP_undefined);
@@ -23081,7 +23087,7 @@ static __exception int js_parse_class(JSParseState *s, BOOL is_class_expr,
if (s->token.val == '=') {
if (next_token(s))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
} else {
emit_op(s, OP_undefined);
@@ -23285,7 +23291,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
while (s->token.val != ']' && idx < 32) {
if (s->token.val == ',' || s->token.val == TOK_ELLIPSIS)
break;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
idx++;
/* accept trailing comma */
@@ -23306,7 +23312,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
break;
need_length = TRUE;
if (s->token.val != ',') {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_op(s, OP_define_field);
emit_u32(s, __JS_AtomFromUInt32(idx));
@@ -23341,7 +23347,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
#if 1
emit_op(s, OP_append);
@@ -23373,7 +23379,7 @@ static __exception int js_parse_array_literal(JSParseState *s)
} else {
need_length = TRUE;
if (s->token.val != ',') {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
/* a idx val */
emit_op(s, OP_define_array_el);
@@ -23781,6 +23787,8 @@ fail:
return JS_ATOM_NULL;
}
+/* Return -1 if error, 0 if no initializer, 1 if an initializer is
+ present at the top level. */
static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
int hasval, int has_ellipsis,
BOOL allow_initializer)
@@ -23789,7 +23797,8 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
int start_addr, assign_addr;
JSAtom prop_name, var_name;
int opcode, scope, tok1, skip_bits;
-
+ BOOL has_initializer;
+
if (has_ellipsis < 0) {
/* pre-parse destructuration target for spread detection */
js_parse_skip_parens_token(s, &skip_bits, FALSE);
@@ -23842,7 +23851,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
label_lvalue = -1;
depth_lvalue = 0;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name,
@@ -23898,7 +23907,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_op(s, OP_get_field2);
emit_u32(s, prop_name);
}
- if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, -1, TRUE) < 0)
return -1;
if (s->token.val == '}')
break;
@@ -23935,7 +23944,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (var_name == JS_ATOM_NULL)
goto prop_error;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
goto prop_error;
lvalue:
if (get_lvalue(s, &opcode, &scope, &var_name,
@@ -24033,7 +24042,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (next_token(s))
goto var_error;
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto var_error;
if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
set_object_name(s, var_name);
@@ -24097,7 +24106,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_u8(s, 0);
emit_op(s, OP_drop);
}
- if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, is_arg, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
var_name = JS_ATOM_NULL;
@@ -24111,7 +24120,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
opcode = OP_scope_get_var;
scope = s->cur_func->scope_level;
} else {
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name,
&label_lvalue, &enum_depth, FALSE, '[')) {
@@ -24135,7 +24144,7 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
if (next_token(s))
goto var_error;
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto var_error;
if (opcode == OP_scope_get_var || opcode == OP_get_ref_value)
set_object_name(s, var_name);
@@ -24170,10 +24179,11 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
emit_label(s, label_parse);
if (hasval)
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
emit_goto(s, OP_goto, label_assign);
emit_label(s, label_done);
+ has_initializer = TRUE;
} else {
/* normally hasval is true except if
js_parse_skip_parens_token() was wrong in the parsing */
@@ -24186,8 +24196,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg,
memset(s->cur_func->byte_code.buf + start_addr, OP_nop,
assign_addr - start_addr);
s->cur_func->label_slots[label_parse].ref_count--;
+ has_initializer = FALSE;
}
- return 0;
+ return has_initializer;
prop_error:
JS_FreeAtom(s->ctx, prop_name);
@@ -24220,10 +24231,12 @@ static void optional_chain_test(JSParseState *s, int *poptional_chaining_label,
emit_label(s, label_next);
}
-static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen)
+/* allowed parse_flags: PF_POSTFIX_CALL, PF_ARROW_FUNC */
+static __exception int js_parse_postfix_expr(JSParseState *s, int parse_flags)
{
FuncCallType call_type;
int optional_chaining_label;
+ BOOL accept_lparen = (parse_flags & PF_POSTFIX_CALL) != 0;
call_type = FUNC_CALL_NORMAL;
switch(s->token.val) {
@@ -24321,7 +24334,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
}
break;
case '(':
- if (js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
+ if ((parse_flags & PF_ARROW_FUNC) &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_NORMAL, JS_ATOM_NULL,
s->token.ptr, s->token.line_num))
@@ -24369,7 +24383,8 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
if (s->token.u.ident.is_reserved) {
return js_parse_error_reserved_identifier(s);
}
- if (peek_token(s, TRUE) == TOK_ARROW) {
+ if ((parse_flags & PF_ARROW_FUNC) &&
+ peek_token(s, TRUE) == TOK_ARROW) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_NORMAL, JS_ATOM_NULL,
s->token.ptr, s->token.line_num))
@@ -24388,10 +24403,11 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
JS_FUNC_ASYNC, JS_ATOM_NULL,
source_ptr, source_line_num))
return -1;
- } else if ((s->token.val == '(' &&
- js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
- (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
- peek_token(s, TRUE) == TOK_ARROW)) {
+ } else if ((parse_flags & PF_ARROW_FUNC) &&
+ ((s->token.val == '(' &&
+ js_parse_skip_parens_token(s, NULL, TRUE) == TOK_ARROW) ||
+ (s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved &&
+ peek_token(s, TRUE) == TOK_ARROW))) {
if (js_parse_function_decl(s, JS_PARSE_FUNC_ARROW,
JS_FUNC_ASYNC, JS_ATOM_NULL,
source_ptr, source_line_num))
@@ -24421,7 +24437,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
{
int skip_bits;
if (js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
- if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, FALSE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
if (s->token.val == '{') {
@@ -24450,7 +24466,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_atom(s, JS_ATOM_new_target);
emit_u16(s, 0);
} else {
- if (js_parse_postfix_expr(s, FALSE))
+ if (js_parse_postfix_expr(s, 0))
return -1;
accept_lparen = TRUE;
if (s->token.val != '(') {
@@ -24503,7 +24519,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
return -1;
if (!accept_lparen)
return js_parse_error(s, "invalid use of 'import()'");
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
if (js_parse_expect(s, ')'))
return -1;
@@ -24636,7 +24652,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
}
if (s->token.val == TOK_ELLIPSIS)
break;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
arg_count++;
if (s->token.val == ')')
@@ -24656,7 +24672,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
if (s->token.val == TOK_ELLIPSIS) {
if (next_token(s))
return -1;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
#if 1
/* XXX: could pass is_last indicator? */
@@ -24687,7 +24703,7 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
emit_op(s, OP_nip1);
#endif
} else {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
/* array idx val */
emit_op(s, OP_define_array_el);
@@ -24789,16 +24805,19 @@ static __exception int js_parse_postfix_expr(JSParseState *s, BOOL accept_lparen
} else if (s->token.val == '.') {
if (next_token(s))
return -1;
+ parse_property:
if (s->token.val == TOK_PRIVATE_NAME) {
/* private class field */
if (get_prev_opcode(fd) == OP_get_super) {
return js_parse_error(s, "private class field forbidden after super");
}
+ if (has_optional_chain) {
+ optional_chain_test(s, &optional_chaining_label, 1);
+ }
emit_op(s, OP_scope_get_private_field);
emit_atom(s, s->token.u.ident.atom);
emit_u16(s, s->cur_func->scope_level);
} else {
- parse_property:
if (!token_is_ident(s->token.val)) {
return js_parse_error(s, "expecting field name");
}
@@ -24857,7 +24876,7 @@ static __exception int js_parse_delete(JSParseState *s)
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
switch(opcode = get_prev_opcode(fd)) {
case OP_get_field:
@@ -24896,9 +24915,9 @@ static __exception int js_parse_delete(JSParseState *s)
case OP_scope_get_private_field:
return js_parse_error(s, "cannot delete a private class field");
case OP_get_super_value:
- emit_op(s, OP_throw_var);
+ emit_op(s, OP_throw_error);
emit_atom(s, JS_ATOM_NULL);
- emit_u8(s, JS_THROW_VAR_DELETE_SUPER);
+ emit_u8(s, JS_THROW_ERROR_DELETE_SUPER);
break;
default:
ret_true:
@@ -24909,7 +24928,8 @@ static __exception int js_parse_delete(JSParseState *s)
return 0;
}
-static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
+/* allowed parse_flags: PF_ARROW_FUNC, PF_POW_ALLOWED, PF_POW_FORBIDDEN */
+static __exception int js_parse_unary(JSParseState *s, int parse_flags)
{
int op;
@@ -24922,7 +24942,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
op = s->token.val;
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
switch(op) {
case '-':
@@ -24944,7 +24964,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
default:
abort();
}
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
case TOK_DEC:
case TOK_INC:
@@ -24954,7 +24974,6 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
op = s->token.val;
if (next_token(s))
return -1;
- /* XXX: should parse LeftHandSideExpression */
if (js_parse_unary(s, 0))
return -1;
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op))
@@ -24969,7 +24988,7 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
JSFunctionDef *fd;
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
/* reference access should not return an exception, so we
patch the get_var */
@@ -24978,13 +24997,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef;
}
emit_op(s, OP_typeof);
- exponentiation_flag = 0;
+ parse_flags = 0;
}
break;
case TOK_DELETE:
if (js_parse_delete(s))
return -1;
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
case TOK_AWAIT:
if (!(s->cur_func->func_kind & JS_FUNC_ASYNC))
@@ -24993,13 +25012,14 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
return js_parse_error(s, "await in default expression");
if (next_token(s))
return -1;
- if (js_parse_unary(s, -1))
+ if (js_parse_unary(s, PF_POW_FORBIDDEN))
return -1;
emit_op(s, OP_await);
- exponentiation_flag = 0;
+ parse_flags = 0;
break;
default:
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_postfix_expr(s, (parse_flags & PF_ARROW_FUNC) |
+ PF_POSTFIX_CALL))
return -1;
if (!s->got_lf &&
(s->token.val == TOK_DEC || s->token.val == TOK_INC)) {
@@ -25016,21 +25036,21 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
}
break;
}
- if (exponentiation_flag) {
+ if (parse_flags & (PF_POW_ALLOWED | PF_POW_FORBIDDEN)) {
#ifdef CONFIG_BIGNUM
if (s->token.val == TOK_POW || s->token.val == TOK_MATH_POW) {
/* Extended exponentiation syntax rules: we extend the ES7
grammar in order to have more intuitive semantics:
-2**2 evaluates to -4. */
if (!(s->cur_func->js_mode & JS_MODE_MATH)) {
- if (exponentiation_flag < 0) {
+ if (parse_flags & PF_POW_FORBIDDEN) {
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
}
if (next_token(s))
return -1;
- if (js_parse_unary(s, 1))
+ if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
emit_op(s, OP_pow);
}
@@ -25041,13 +25061,13 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
regarding the precedence of prefix operators and the
postifx exponential, ES7 specifies that -2**2 is a
syntax error. */
- if (exponentiation_flag < 0) {
+ if (parse_flags & PF_POW_FORBIDDEN) {
JS_ThrowSyntaxError(s->ctx, "unparenthesized unary expression can't appear on the left-hand side of '**'");
return -1;
}
if (next_token(s))
return -1;
- if (js_parse_unary(s, 1))
+ if (js_parse_unary(s, PF_POW_ALLOWED))
return -1;
emit_op(s, OP_pow);
}
@@ -25056,15 +25076,17 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag)
return 0;
}
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
static __exception int js_parse_expr_binary(JSParseState *s, int level,
- BOOL in_accepted)
+ int parse_flags)
{
int op, opcode;
if (level == 0) {
- return js_parse_unary(s, 1);
+ return js_parse_unary(s, (parse_flags & PF_ARROW_FUNC) |
+ PF_POW_ALLOWED);
}
- if (js_parse_expr_binary(s, level - 1, in_accepted))
+ if (js_parse_expr_binary(s, level - 1, parse_flags))
return -1;
for(;;) {
op = s->token.val;
@@ -25134,7 +25156,7 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
opcode = OP_instanceof;
break;
case TOK_IN:
- if (in_accepted) {
+ if (parse_flags & PF_IN_ACCEPTED) {
opcode = OP_in;
} else {
return 0;
@@ -25194,23 +25216,24 @@ static __exception int js_parse_expr_binary(JSParseState *s, int level,
}
if (next_token(s))
return -1;
- if (js_parse_expr_binary(s, level - 1, in_accepted))
+ if (js_parse_expr_binary(s, level - 1, parse_flags & ~PF_ARROW_FUNC))
return -1;
emit_op(s, opcode);
}
return 0;
}
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
static __exception int js_parse_logical_and_or(JSParseState *s, int op,
- BOOL in_accepted)
+ int parse_flags)
{
int label1;
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags))
return -1;
} else {
- if (js_parse_logical_and_or(s, TOK_LAND, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LAND, parse_flags))
return -1;
}
if (s->token.val == op) {
@@ -25224,10 +25247,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
emit_op(s, OP_drop);
if (op == TOK_LAND) {
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
return -1;
} else {
- if (js_parse_logical_and_or(s, TOK_LAND, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LAND,
+ parse_flags & ~PF_ARROW_FUNC))
return -1;
}
if (s->token.val != op) {
@@ -25242,11 +25266,11 @@ static __exception int js_parse_logical_and_or(JSParseState *s, int op,
return 0;
}
-static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
+static __exception int js_parse_coalesce_expr(JSParseState *s, int parse_flags)
{
int label1;
- if (js_parse_logical_and_or(s, TOK_LOR, in_accepted))
+ if (js_parse_logical_and_or(s, TOK_LOR, parse_flags))
return -1;
if (s->token.val == TOK_DOUBLE_QUESTION_MARK) {
label1 = new_label(s);
@@ -25259,7 +25283,7 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
emit_goto(s, OP_if_false, label1);
emit_op(s, OP_drop);
- if (js_parse_expr_binary(s, 8, in_accepted))
+ if (js_parse_expr_binary(s, 8, parse_flags & ~PF_ARROW_FUNC))
return -1;
if (s->token.val != TOK_DOUBLE_QUESTION_MARK)
break;
@@ -25269,18 +25293,19 @@ static __exception int js_parse_coalesce_expr(JSParseState *s, BOOL in_accepted)
return 0;
}
-static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
+/* allowed parse_flags: PF_ARROW_FUNC, PF_IN_ACCEPTED */
+static __exception int js_parse_cond_expr(JSParseState *s, int parse_flags)
{
int label1, label2;
- if (js_parse_coalesce_expr(s, in_accepted))
+ if (js_parse_coalesce_expr(s, parse_flags))
return -1;
if (s->token.val == '?') {
if (next_token(s))
return -1;
label1 = emit_goto(s, OP_if_false, -1);
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
if (js_parse_expect(s, ':'))
return -1;
@@ -25289,7 +25314,7 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
emit_label(s, label1);
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags & PF_IN_ACCEPTED))
return -1;
emit_label(s, label2);
@@ -25299,14 +25324,16 @@ static __exception int js_parse_cond_expr(JSParseState *s, BOOL in_accepted)
static void emit_return(JSParseState *s, BOOL hasval);
-static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_assign_expr2(JSParseState *s, int parse_flags)
{
int opcode, op, scope;
JSAtom name0 = JS_ATOM_NULL;
JSAtom name;
if (s->token.val == TOK_YIELD) {
- BOOL is_star = FALSE;
+ BOOL is_star = FALSE, is_async;
+
if (!(s->cur_func->func_kind & JS_FUNC_GENERATOR))
return js_parse_error(s, "unexpected 'yield' keyword");
if (!s->cur_func->in_function_body)
@@ -25323,109 +25350,120 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
if (next_token(s))
return -1;
}
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
return -1;
} else {
emit_op(s, OP_undefined);
}
- if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
+ is_async = (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR);
+
+ if (is_star) {
int label_loop, label_return, label_next;
int label_return1, label_yield, label_throw, label_throw1;
int label_throw2;
- if (is_star) {
- label_loop = new_label(s);
- label_yield = new_label(s);
-
- emit_op(s, OP_for_await_of_start);
+ label_loop = new_label(s);
+ label_yield = new_label(s);
- /* remove the catch offset (XXX: could avoid pushing back
- undefined) */
- emit_op(s, OP_drop);
- emit_op(s, OP_undefined);
-
- emit_op(s, OP_undefined); /* initial value */
+ emit_op(s, is_async ? OP_for_await_of_start : OP_for_of_start);
- emit_label(s, label_loop);
- emit_op(s, OP_async_iterator_next);
+ /* remove the catch offset (XXX: could avoid pushing back
+ undefined) */
+ emit_op(s, OP_drop);
+ emit_op(s, OP_undefined);
+
+ emit_op(s, OP_undefined); /* initial value */
+
+ emit_label(s, label_loop);
+ emit_op(s, OP_iterator_next);
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ label_next = emit_goto(s, OP_if_true, -1); /* end of loop */
+ emit_label(s, label_yield);
+ if (is_async) {
+ /* OP_async_yield_star takes the value as parameter */
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
emit_op(s, OP_await);
- emit_label(s, label_yield);
emit_op(s, OP_async_yield_star);
- emit_op(s, OP_dup);
- label_return = emit_goto(s, OP_if_true, -1);
- emit_op(s, OP_drop);
- emit_goto(s, OP_goto, label_loop);
-
- emit_label(s, label_return);
- emit_op(s, OP_push_i32);
- emit_u32(s, 2);
- emit_op(s, OP_strict_eq);
- label_throw = emit_goto(s, OP_if_true, -1);
-
- /* return handling */
- emit_op(s, OP_await);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 0);
- label_return1 = emit_goto(s, OP_if_true, -1);
+ } else {
+ /* OP_yield_star takes (value, done) as parameter */
+ emit_op(s, OP_yield_star);
+ }
+ emit_op(s, OP_dup);
+ label_return = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_drop);
+ emit_goto(s, OP_goto, label_loop);
+
+ emit_label(s, label_return);
+ emit_op(s, OP_push_i32);
+ emit_u32(s, 2);
+ emit_op(s, OP_strict_eq);
+ label_throw = emit_goto(s, OP_if_true, -1);
+
+ /* return handling */
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- /* XXX: the spec does not indicate that an await should be
- performed in case done = true, but the tests assume it */
- emit_goto(s, OP_if_false, label_yield);
-
- emit_label(s, label_return1);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- emit_return(s, TRUE);
-
- /* throw handling */
- emit_label(s, label_throw);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 1);
- label_throw1 = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 0);
+ label_return1 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_op(s, OP_iterator_get_value_done);
- emit_goto(s, OP_if_false, label_yield);
- /* XXX: the spec does not indicate that an await should be
- performed in case done = true, but the tests assume it */
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ emit_goto(s, OP_if_false, label_yield);
+
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
+
+ emit_label(s, label_return1);
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
+ emit_return(s, TRUE);
+
+ /* throw handling */
+ emit_label(s, label_throw);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 1);
+ label_throw1 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_goto(s, OP_goto, label_next);
- /* close the iterator and throw a type error exception */
- emit_label(s, label_throw1);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 0);
- label_throw2 = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_iterator_check_object);
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_done);
+ emit_goto(s, OP_if_false, label_yield);
+ emit_goto(s, OP_goto, label_next);
+ /* close the iterator and throw a type error exception */
+ emit_label(s, label_throw1);
+ emit_op(s, OP_iterator_call);
+ emit_u8(s, 2);
+ label_throw2 = emit_goto(s, OP_if_true, -1);
+ if (is_async)
emit_op(s, OP_await);
- emit_label(s, label_throw2);
- emit_op(s, OP_async_iterator_get);
- emit_u8(s, 2); /* throw the type error exception */
- emit_op(s, OP_drop); /* never reached */
+ emit_label(s, label_throw2);
- emit_label(s, label_next);
- emit_op(s, OP_nip); /* keep the value associated with
- done = true */
- emit_op(s, OP_nip);
- emit_op(s, OP_nip);
- } else {
- emit_op(s, OP_await);
- emit_op(s, OP_yield);
- label_next = emit_goto(s, OP_if_false, -1);
- emit_return(s, TRUE);
- emit_label(s, label_next);
- }
+ emit_op(s, OP_throw_error);
+ emit_atom(s, JS_ATOM_NULL);
+ emit_u8(s, JS_THROW_ERROR_ITERATOR_THROW);
+
+ emit_label(s, label_next);
+ emit_op(s, OP_get_field);
+ emit_atom(s, JS_ATOM_value);
+ emit_op(s, OP_nip); /* keep the value associated with
+ done = true */
+ emit_op(s, OP_nip);
+ emit_op(s, OP_nip);
} else {
int label_next;
- if (is_star) {
- emit_op(s, OP_for_of_start);
- emit_op(s, OP_drop); /* drop the catch offset */
- emit_op(s, OP_yield_star);
- } else {
- emit_op(s, OP_yield);
- }
+
+ if (is_async)
+ emit_op(s, OP_await);
+ emit_op(s, OP_yield);
label_next = emit_goto(s, OP_if_false, -1);
emit_return(s, TRUE);
emit_label(s, label_next);
@@ -25436,7 +25474,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
/* name0 is used to check for OP_set_name pattern, not duplicated */
name0 = s->token.u.ident.atom;
}
- if (js_parse_cond_expr(s, in_accepted))
+ if (js_parse_cond_expr(s, parse_flags | PF_ARROW_FUNC))
return -1;
op = s->token.val;
@@ -25447,7 +25485,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, (op != '='), op) < 0)
return -1;
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(s->ctx, name);
return -1;
}
@@ -25491,7 +25529,7 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
-1);
emit_op(s, OP_drop);
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(s->ctx, name);
return -1;
}
@@ -25533,11 +25571,17 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted)
return 0;
}
-static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted)
+static __exception int js_parse_assign_expr(JSParseState *s)
+{
+ return js_parse_assign_expr2(s, PF_IN_ACCEPTED);
+}
+
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_expr2(JSParseState *s, int parse_flags)
{
BOOL comma = FALSE;
for(;;) {
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
return -1;
if (comma) {
/* prevent get_lvalue from using the last expression
@@ -25559,7 +25603,7 @@ static __exception int js_parse_expr2(JSParseState *s, BOOL in_accepted)
static __exception int js_parse_expr(JSParseState *s)
{
- return js_parse_expr2(s, TRUE);
+ return js_parse_expr2(s, PF_IN_ACCEPTED);
}
static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
@@ -25655,12 +25699,25 @@ static void emit_return(JSParseState *s, BOOL hasval)
}
emit_op(s, OP_iterator_close_return);
if (s->cur_func->func_kind == JS_FUNC_ASYNC_GENERATOR) {
- int label_next;
- emit_op(s, OP_async_iterator_close);
+ int label_next, label_next2;
+
+ emit_op(s, OP_drop); /* catch offset */
+ emit_op(s, OP_drop); /* next */
+ emit_op(s, OP_get_field2);
+ emit_atom(s, JS_ATOM_return);
+ /* stack: iter_obj return_func */
+ emit_op(s, OP_dup);
+ emit_op(s, OP_is_undefined_or_null);
label_next = emit_goto(s, OP_if_true, -1);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
+ emit_op(s, OP_iterator_check_object);
emit_op(s, OP_await);
+ label_next2 = emit_goto(s, OP_goto, -1);
emit_label(s, label_next);
emit_op(s, OP_drop);
+ emit_label(s, label_next2);
+ emit_op(s, OP_drop);
} else {
emit_op(s, OP_iterator_close);
}
@@ -25748,7 +25805,8 @@ static __exception int js_parse_block(JSParseState *s)
return 0;
}
-static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
+/* allowed parse_flags: PF_IN_ACCEPTED */
+static __exception int js_parse_var(JSParseState *s, int parse_flags, int tok,
BOOL export_flag)
{
JSContext *ctx = s->ctx;
@@ -25788,7 +25846,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
emit_u16(s, fd->scope_level);
if (get_lvalue(s, &opcode, &scope, &name1, &label, NULL, FALSE, '=') < 0)
goto var_error;
- if (js_parse_assign_expr(s, in_accepted)) {
+ if (js_parse_assign_expr2(s, parse_flags)) {
JS_FreeAtom(ctx, name1);
goto var_error;
}
@@ -25796,7 +25854,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
put_lvalue(s, opcode, scope, name1, label,
PUT_LVALUE_NOKEEP, FALSE);
} else {
- if (js_parse_assign_expr(s, in_accepted))
+ if (js_parse_assign_expr2(s, parse_flags))
goto var_error;
set_object_name(s, name);
emit_op(s, (tok == TOK_CONST || tok == TOK_LET) ?
@@ -25823,7 +25881,7 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok,
if ((s->token.val == '[' || s->token.val == '{')
&& js_parse_skip_parens_token(s, &skip_bits, FALSE) == '=') {
emit_op(s, OP_undefined);
- if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
return js_parse_error(s, "variable name expected");
@@ -25952,7 +26010,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
- if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE))
+ if (js_parse_destructuring_element(s, tok, 0, TRUE, -1, FALSE) < 0)
return -1;
has_destructuring = TRUE;
} else {
@@ -25978,11 +26036,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
int skip_bits;
if ((s->token.val == '[' || s->token.val == '{')
&& ((tok1 = js_parse_skip_parens_token(s, &skip_bits, FALSE)) == TOK_IN || tok1 == TOK_OF)) {
- if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE))
+ if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE) < 0)
return -1;
} else {
int lvalue_label;
- if (js_parse_postfix_expr(s, TRUE))
+ if (js_parse_left_hand_side_expr(s))
return -1;
if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label,
NULL, FALSE, TOK_FOR))
@@ -26002,7 +26060,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
/* parse and evaluate initializer prior to evaluating the
object (only used with "for in" with a non lexical variable
in non strict mode */
- if (next_token(s) || js_parse_assign_expr(s, FALSE)) {
+ if (next_token(s) || js_parse_assign_expr2(s, 0)) {
JS_FreeAtom(ctx, var_name);
return -1;
}
@@ -26035,7 +26093,7 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (next_token(s))
return -1;
if (is_for_of) {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
} else {
if (js_parse_expr(s))
@@ -26088,7 +26146,11 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
if (is_for_of) {
if (is_async) {
/* call the next method */
- emit_op(s, OP_for_await_of_next);
+ /* stack: iter_obj next catch_offset */
+ emit_op(s, OP_dup3);
+ emit_op(s, OP_drop);
+ emit_op(s, OP_call_method);
+ emit_u16(s, 0);
/* get the result of the promise */
emit_op(s, OP_await);
/* unwrap the value and done values */
@@ -26646,7 +26708,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) {
if (s->token.val == '[' || s->token.val == '{') {
/* XXX: TOK_LET is not completely correct */
- if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE))
+ if (js_parse_destructuring_element(s, TOK_LET, 0, TRUE, -1, TRUE) < 0)
goto fail;
} else {
js_parse_error(s, "identifier expected");
@@ -26712,18 +26774,37 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
}
emit_label(s, label_finally);
if (s->token.val == TOK_FINALLY) {
- int saved_eval_ret_idx;
+ int saved_eval_ret_idx = 0; /* avoid warning */
+
if (next_token(s))
goto fail;
/* on the stack: ret_value gosub_ret_value */
push_break_entry(s->cur_func, &block_env, JS_ATOM_NULL,
-1, -1, 2);
- saved_eval_ret_idx = s->cur_func->eval_ret_idx;
- s->cur_func->eval_ret_idx = -1;
- /* 'finally' does not update eval_ret */
+
+ if (s->cur_func->eval_ret_idx >= 0) {
+ /* 'finally' updates eval_ret only if not a normal
+ termination */
+ saved_eval_ret_idx =
+ add_var(s->ctx, s->cur_func, JS_ATOM__ret_);
+ if (saved_eval_ret_idx < 0)
+ goto fail;
+ emit_op(s, OP_get_loc);
+ emit_u16(s, s->cur_func->eval_ret_idx);
+ emit_op(s, OP_put_loc);
+ emit_u16(s, saved_eval_ret_idx);
+ set_eval_ret_undefined(s);
+ }
+
if (js_parse_block(s))
goto fail;
- s->cur_func->eval_ret_idx = saved_eval_ret_idx;
+
+ if (s->cur_func->eval_ret_idx >= 0) {
+ emit_op(s, OP_get_loc);
+ emit_u16(s, saved_eval_ret_idx);
+ emit_op(s, OP_put_loc);
+ emit_u16(s, s->cur_func->eval_ret_idx);
+ }
pop_break_entry(s->cur_func);
}
emit_op(s, OP_ret);
@@ -27511,19 +27592,11 @@ static int exported_names_cmp(const void *p1, const void *p2, void *opaque)
static JSValue js_get_module_ns(JSContext *ctx, JSModuleDef *m);
-static int js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
- void *opaque)
+static JSValue js_module_ns_autoinit(JSContext *ctx, JSObject *p, JSAtom atom,
+ void *opaque)
{
JSModuleDef *m = opaque;
- JSValue val, this_val = JS_MKPTR(JS_TAG_OBJECT, p);
-
- val = js_get_module_ns(ctx, m);
- if (JS_IsException(val))
- return -1;
- if (JS_DefinePropertyValue(ctx, this_val, atom, val,
- JS_PROP_ENUMERABLE | JS_PROP_WRITABLE) < 0)
- return -1;
- return 0;
+ return js_get_module_ns(ctx, m);
}
static JSValue js_build_module_ns(JSContext *ctx, JSModuleDef *m)
@@ -27741,7 +27814,7 @@ static int js_create_module_bytecode_function(JSContext *ctx, JSModuleDef *m)
return -1;
}
-/* must be done before js_instantiate_module() because of cyclic references */
+/* must be done before js_link_module() because of cyclic references */
static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
{
BOOL is_c_module;
@@ -27784,7 +27857,7 @@ static int js_create_module_function(JSContext *ctx, JSModuleDef *m)
/* Prepare a module to be executed by resolving all the imported
variables. */
-static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
+static int js_link_module(JSContext *ctx, JSModuleDef *m)
{
int i;
JSImportEntry *mi;
@@ -27792,7 +27865,8 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
JSVarRef **var_refs, *var_ref;
JSObject *p;
BOOL is_c_module;
-
+ JSValue ret_val;
+
if (m->instantiated)
return 0;
m->instantiated = TRUE;
@@ -27806,7 +27880,7 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
for(i = 0; i < m->req_module_entries_count; i++) {
JSReqModuleEntry *rme = &m->req_module_entries[i];
- if (js_instantiate_module(ctx, rme->module) < 0)
+ if (js_link_module(ctx, rme->module) < 0)
goto fail;
}
@@ -27925,6 +27999,12 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m)
me->u.local.var_ref = var_ref;
}
}
+
+ /* initialize the global variables */
+ ret_val = JS_Call(ctx, m->func_obj, JS_TRUE, 0, NULL);
+ if (JS_IsException(ret_val))
+ goto fail;
+ JS_FreeValue(ctx, ret_val);
}
#ifdef DUMP_MODULE_RESOLVE
@@ -28324,7 +28404,7 @@ static __exception int js_parse_export(JSParseState *s)
s->token.ptr, s->token.line_num,
JS_PARSE_EXPORT_DEFAULT, NULL);
} else {
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
return -1;
}
/* set the name of anonymous functions */
@@ -28567,7 +28647,9 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->last_opcode_pos = -1;
fd->func_name = JS_ATOM_NULL;
fd->var_object_idx = -1;
+ fd->arg_var_object_idx = -1;
fd->arguments_var_idx = -1;
+ fd->arguments_arg_idx = -1;
fd->func_var_idx = -1;
fd->eval_ret_idx = -1;
fd->this_var_idx = -1;
@@ -28576,13 +28658,14 @@ static JSFunctionDef *js_new_function_def(JSContext *ctx,
fd->home_object_var_idx = -1;
/* XXX: should distinguish arg, var and var object and body scopes */
- fd->scope_level = 0; /* 0: var/arg scope, 1:body scope */
- fd->scope_first = -1;
fd->scopes = fd->def_scope_array;
fd->scope_size = countof(fd->def_scope_array);
fd->scope_count = 1;
fd->scopes[0].first = -1;
fd->scopes[0].parent = -1;
+ fd->scope_level = 0; /* 0: var/arg scope */
+ fd->scope_first = -1;
+ fd->body_scope = -1;
fd->filename = JS_NewAtom(ctx, filename);
fd->line_num = line_num;
@@ -28663,10 +28746,10 @@ static void js_free_function_def(JSContext *ctx, JSFunctionDef *fd)
}
js_free(ctx, fd->args);
- for(i = 0; i < fd->hoisted_def_count; i++) {
- JS_FreeAtom(ctx, fd->hoisted_def[i].var_name);
+ for(i = 0; i < fd->global_var_count; i++) {
+ JS_FreeAtom(ctx, fd->global_vars[i].var_name);
}
- js_free(ctx, fd->hoisted_def);
+ js_free(ctx, fd->global_vars);
for(i = 0; i < fd->closure_var_count; i++) {
JSClosureVar *cv = &fd->closure_var[i];
@@ -29350,19 +29433,27 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
switch(var_name) {
case JS_ATOM_home_object:
/* 'home_object' pseudo variable */
- var_idx = s->home_object_var_idx = add_var(ctx, s, var_name);
+ if (s->home_object_var_idx < 0)
+ s->home_object_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->home_object_var_idx;
break;
case JS_ATOM_this_active_func:
/* 'this.active_func' pseudo variable */
- var_idx = s->this_active_func_var_idx = add_var(ctx, s, var_name);
+ if (s->this_active_func_var_idx < 0)
+ s->this_active_func_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->this_active_func_var_idx;
break;
case JS_ATOM_new_target:
/* 'new.target' pseudo variable */
- var_idx = s->new_target_var_idx = add_var(ctx, s, var_name);
+ if (s->new_target_var_idx < 0)
+ s->new_target_var_idx = add_var(ctx, s, var_name);
+ var_idx = s->new_target_var_idx;
break;
case JS_ATOM_this:
/* 'this' pseudo variable */
- var_idx = s->this_var_idx = add_var_this(ctx, s);
+ if (s->this_var_idx < 0)
+ s->this_var_idx = add_var_this(ctx, s);
+ var_idx = s->this_var_idx;
break;
default:
var_idx = -1;
@@ -29371,18 +29462,32 @@ static int resolve_pseudo_var(JSContext *ctx, JSFunctionDef *s,
return var_idx;
}
+/* test if 'var_name' is in the variable object on the stack. If is it
+ the case, handle it and jump to 'label_done' */
+static void var_object_test(JSContext *ctx, JSFunctionDef *s,
+ JSAtom var_name, int op, DynBuf *bc,
+ int *plabel_done, BOOL is_with)
+{
+ dbuf_putc(bc, get_with_scope_opcode(op));
+ dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+ *plabel_done = new_label_fd(s, *plabel_done);
+ dbuf_put_u32(bc, *plabel_done);
+ dbuf_putc(bc, is_with);
+ update_label(s, *plabel_done, 1);
+ s->jump_size++;
+}
+
/* return the position of the next opcode */
static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
JSAtom var_name, int scope_level, int op,
DynBuf *bc, uint8_t *bc_buf,
- LabelSlot *ls, int pos_next, int arg_valid)
+ LabelSlot *ls, int pos_next)
{
int idx, var_idx, is_put;
int label_done;
- BOOL is_func_var = FALSE;
JSFunctionDef *fd;
JSVarDef *vd;
- BOOL is_pseudo_var;
+ BOOL is_pseudo_var, is_arg_scope;
label_done = -1;
@@ -29400,12 +29505,11 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (vd->var_name == var_name) {
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
if (vd->is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
- is_func_var = vd->is_func_var;
}
var_idx = idx;
break;
@@ -29413,33 +29517,16 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (vd->var_name == JS_ATOM__with_ && !is_pseudo_var) {
dbuf_putc(bc, OP_get_loc);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 1);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
}
idx = vd->scope_next;
}
+ is_arg_scope = (idx == ARG_SCOPE_END);
if (var_idx < 0) {
- /* XXX: scoping issues:
- should not resolve vars from the function body during argument parse,
- `arguments` and function-name should not be hidden by later vars.
- */
- var_idx = find_var(ctx, s, var_name);
- if (var_idx >= 0) {
- if (scope_level == 0
- && (var_idx & ARGUMENT_VAR_OFFSET)
- && (var_idx - ARGUMENT_VAR_OFFSET) >= arg_valid) {
- /* referring to an uninitialized argument */
- dbuf_putc(bc, OP_throw_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- dbuf_putc(bc, JS_THROW_VAR_UNINITIALIZED);
- }
- if (!(var_idx & ARGUMENT_VAR_OFFSET))
- is_func_var = s->vars[var_idx].is_func_var;
+ /* argument scope: variables are not visible but pseudo
+ variables are visible */
+ if (!is_arg_scope) {
+ var_idx = find_var(ctx, s, var_name);
}
if (var_idx < 0 && is_pseudo_var)
@@ -29448,21 +29535,31 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (var_idx < 0 && var_name == JS_ATOM_arguments &&
s->has_arguments_binding) {
/* 'arguments' pseudo variable */
- var_idx = add_arguments_var(ctx, s, var_name);
+ var_idx = add_arguments_var(ctx, s);
}
if (var_idx < 0 && s->is_func_expr && var_name == s->func_name) {
/* add a new variable with the function name */
var_idx = add_func_var(ctx, s, var_name);
- is_func_var = TRUE;
}
}
if (var_idx >= 0) {
+ if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
+ !(var_idx & ARGUMENT_VAR_OFFSET) &&
+ s->vars[var_idx].is_const) {
+ /* only happens when assigning a function expression name
+ in strict mode */
+ dbuf_putc(bc, OP_throw_error);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
+ dbuf_putc(bc, JS_THROW_VAR_RO);
+ goto done;
+ }
/* OP_scope_put_var_init is only used to initialize a
lexical variable, so it is never used in a with or var object. It
can be used with a closure (module global variable case). */
switch (op) {
case OP_scope_make_ref:
- if (is_func_var) {
+ if (!(var_idx & ARGUMENT_VAR_OFFSET) &&
+ s->vars[var_idx].var_kind == JS_VAR_FUNCTION_NAME) {
/* Create a dummy object reference for the func_var */
dbuf_putc(bc, OP_object);
dbuf_putc(bc, OP_get_loc);
@@ -29510,7 +29607,6 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (var_idx & ARGUMENT_VAR_OFFSET) {
dbuf_putc(bc, OP_get_arg + is_put);
dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- /* XXX: should test if argument reference needs TDZ check */
} else {
if (is_put) {
if (s->vars[var_idx].is_lexical) {
@@ -29543,41 +29639,32 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
goto done;
}
/* check eval object */
- if (s->var_object_idx >= 0 && !is_pseudo_var) {
+ if (!is_arg_scope && s->var_object_idx >= 0 && !is_pseudo_var) {
dbuf_putc(bc, OP_get_loc);
dbuf_put_u16(bc, s->var_object_idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 0);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
}
+ /* check eval object in argument scope */
+ if (s->arg_var_object_idx >= 0 && !is_pseudo_var) {
+ dbuf_putc(bc, OP_get_loc);
+ dbuf_put_u16(bc, s->arg_var_object_idx);
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+ }
+
/* check parent scopes */
for (fd = s; fd->parent;) {
scope_level = fd->parent_scope_level;
fd = fd->parent;
- if (scope_level == 0) {
- /* function is defined as part of the argument parsing: hide vars
- from the function body.
- XXX: variables created from argument destructuring might need
- to be visible, should refine this method.
- */
- var_idx = find_arg(ctx, fd, var_name);
- goto check_idx;
- }
for (idx = fd->scopes[scope_level].first; idx >= 0;) {
vd = &fd->vars[idx];
if (vd->var_name == var_name) {
if (op == OP_scope_put_var || op == OP_scope_make_ref) {
if (vd->is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
- is_func_var = vd->is_func_var;
}
var_idx = idx;
break;
@@ -29587,26 +29674,19 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
if (idx >= 0) {
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 1);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 1);
}
}
idx = vd->scope_next;
}
+ is_arg_scope = (idx == ARG_SCOPE_END);
if (var_idx >= 0)
break;
-
- var_idx = find_var(ctx, fd, var_name);
- check_idx:
- if (var_idx >= 0) {
- if (!(var_idx & ARGUMENT_VAR_OFFSET))
- is_func_var = fd->vars[var_idx].is_func_var;
- break;
+
+ if (!is_arg_scope) {
+ var_idx = find_var(ctx, fd, var_name);
+ if (var_idx >= 0)
+ break;
}
if (is_pseudo_var) {
var_idx = resolve_pseudo_var(ctx, fd, var_name);
@@ -29614,33 +29694,39 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
break;
}
if (var_name == JS_ATOM_arguments && fd->has_arguments_binding) {
- var_idx = add_arguments_var(ctx, fd, var_name);
+ var_idx = add_arguments_var(ctx, fd);
break;
}
if (fd->is_func_expr && fd->func_name == var_name) {
/* add a new variable with the function name */
var_idx = add_func_var(ctx, fd, var_name);
- is_func_var = TRUE;
break;
}
/* check eval object */
- if (fd->var_object_idx >= 0 && !is_pseudo_var) {
- fd->vars[fd->var_object_idx].is_captured = 1;
+ if (!is_arg_scope && fd->var_object_idx >= 0 && !is_pseudo_var) {
+ vd = &fd->vars[fd->var_object_idx];
+ vd->is_captured = 1;
idx = get_closure_var(ctx, s, fd, FALSE,
- fd->var_object_idx, JS_ATOM__var_,
+ fd->var_object_idx, vd->var_name,
FALSE, FALSE, JS_VAR_NORMAL);
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, 0);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
}
+ /* check eval object in argument scope */
+ if (fd->arg_var_object_idx >= 0 && !is_pseudo_var) {
+ vd = &fd->vars[fd->arg_var_object_idx];
+ vd->is_captured = 1;
+ idx = get_closure_var(ctx, s, fd, FALSE,
+ fd->arg_var_object_idx, vd->var_name,
+ FALSE, FALSE, JS_VAR_NORMAL);
+ dbuf_putc(bc, OP_get_var_ref);
+ dbuf_put_u16(bc, idx);
+ var_object_test(ctx, s, var_name, op, bc, &label_done, 0);
+ }
+
if (fd->is_eval)
break; /* it it necessarily the top level function */
}
@@ -29665,6 +29751,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
goto has_idx;
} else if ((cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_ ||
cv->var_name == JS_ATOM__with_) && !is_pseudo_var) {
int is_with = (cv->var_name == JS_ATOM__with_);
if (fd != s) {
@@ -29678,13 +29765,7 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
}
dbuf_putc(bc, OP_get_var_ref);
dbuf_put_u16(bc, idx);
- dbuf_putc(bc, get_with_scope_opcode(op));
- dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
- label_done = new_label_fd(s, label_done);
- dbuf_put_u32(bc, label_done);
- dbuf_putc(bc, is_with);
- update_label(s, label_done, 1);
- s->jump_size++;
+ var_object_test(ctx, s, var_name, op, bc, &label_done, is_with);
}
}
}
@@ -29709,14 +29790,14 @@ static int resolve_scope_var(JSContext *ctx, JSFunctionDef *s,
has_idx:
if ((op == OP_scope_put_var || op == OP_scope_make_ref) &&
s->closure_var[idx].is_const) {
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
goto done;
}
switch (op) {
case OP_scope_make_ref:
- if (is_func_var) {
+ if (s->closure_var[idx].var_kind == JS_VAR_FUNCTION_NAME) {
/* Create a dummy object reference for the func_var */
dbuf_putc(bc, OP_object);
dbuf_putc(bc, OP_get_var_ref);
@@ -29956,7 +30037,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
break;
case JS_VAR_PRIVATE_SETTER:
/* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
break;
@@ -29973,7 +30054,7 @@ static int resolve_scope_private_field(JSContext *ctx, JSFunctionDef *s,
case JS_VAR_PRIVATE_METHOD:
case JS_VAR_PRIVATE_GETTER:
/* XXX: add clearer error message */
- dbuf_putc(bc, OP_throw_var);
+ dbuf_putc(bc, OP_throw_error);
dbuf_put_u32(bc, JS_DupAtom(ctx, var_name));
dbuf_putc(bc, JS_THROW_VAR_RO);
break;
@@ -30025,17 +30106,33 @@ static void mark_eval_captured_variables(JSContext *ctx, JSFunctionDef *s,
}
}
+/* XXX: should handle the argument scope generically */
+static BOOL is_var_in_arg_scope(const JSVarDef *vd)
+{
+ return (vd->var_name == JS_ATOM_home_object ||
+ vd->var_name == JS_ATOM_this_active_func ||
+ vd->var_name == JS_ATOM_new_target ||
+ vd->var_name == JS_ATOM_this ||
+ vd->var_name == JS_ATOM__arg_var_ ||
+ vd->var_kind == JS_VAR_FUNCTION_NAME);
+}
+
static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
{
JSFunctionDef *fd;
JSVarDef *vd;
int i, scope_level, scope_idx;
- BOOL has_arguments_binding, has_this_binding;
+ BOOL has_arguments_binding, has_this_binding, is_arg_scope;
/* in non strict mode, variables are created in the caller's
environment object */
if (!s->is_eval && !(s->js_mode & JS_MODE_STRICT)) {
s->var_object_idx = add_var(ctx, s, JS_ATOM__var_);
+ if (s->has_parameter_expressions) {
+ /* an additional variable object is needed for the
+ argument scope */
+ s->arg_var_object_idx = add_var(ctx, s, JS_ATOM__arg_var_);
+ }
}
/* eval can potentially use 'arguments' so we must define it */
@@ -30051,8 +30148,14 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
s->home_object_var_idx = add_var(ctx, s, JS_ATOM_home_object);
}
has_arguments_binding = s->has_arguments_binding;
- if (has_arguments_binding)
- add_arguments_var(ctx, s, JS_ATOM_arguments);
+ if (has_arguments_binding) {
+ add_arguments_var(ctx, s);
+ /* also add an arguments binding in the argument scope to
+ raise an error if a direct eval in the argument scope tries
+ to redefine it */
+ if (s->has_parameter_expressions && !(s->js_mode & JS_MODE_STRICT))
+ add_arguments_arg(ctx, s);
+ }
if (s->is_func_expr && s->func_name != JS_ATOM_NULL)
add_func_var(ctx, s, s->func_name);
@@ -30069,7 +30172,6 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
fd = fd->parent;
if (!fd)
break;
- scope_idx = fd->scopes[scope_level].first;
/* add 'this' if it was not previously added */
if (!has_this_binding && fd->has_this_binding) {
if (fd->this_var_idx < 0)
@@ -30084,7 +30186,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
}
/* add 'arguments' if it was not previously added */
if (!has_arguments_binding && fd->has_arguments_binding) {
- add_arguments_var(ctx, fd, JS_ATOM_arguments);
+ add_arguments_var(ctx, fd);
has_arguments_binding = TRUE;
}
/* add function name */
@@ -30092,6 +30194,7 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
add_func_var(ctx, fd, fd->func_name);
/* add lexical variables */
+ scope_idx = fd->scopes[scope_level].first;
while (scope_idx >= 0) {
vd = &fd->vars[scope_idx];
vd->is_captured = 1;
@@ -30099,24 +30202,37 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
vd->var_name, vd->is_const, vd->is_lexical, vd->var_kind);
scope_idx = vd->scope_next;
}
- /* add unscoped variables */
- for(i = 0; i < fd->arg_count; i++) {
- vd = &fd->args[i];
- if (vd->var_name != JS_ATOM_NULL) {
- get_closure_var(ctx, s, fd,
- TRUE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ is_arg_scope = (scope_idx == ARG_SCOPE_END);
+ if (!is_arg_scope) {
+ /* add unscoped variables */
+ for(i = 0; i < fd->arg_count; i++) {
+ vd = &fd->args[i];
+ if (vd->var_name != JS_ATOM_NULL) {
+ get_closure_var(ctx, s, fd,
+ TRUE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
}
- }
- for(i = 0; i < fd->var_count; i++) {
- vd = &fd->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) {
- get_closure_var(ctx, s, fd,
- FALSE, i, vd->var_name, FALSE, FALSE,
- JS_VAR_NORMAL);
+ for(i = 0; i < fd->var_count; i++) {
+ vd = &fd->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) {
+ get_closure_var(ctx, s, fd,
+ FALSE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
+ }
+ } else {
+ for(i = 0; i < fd->var_count; i++) {
+ vd = &fd->vars[i];
+ /* do not close top level last result */
+ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+ get_closure_var(ctx, s, fd,
+ FALSE, i, vd->var_name, FALSE, FALSE,
+ JS_VAR_NORMAL);
+ }
}
}
if (fd->is_eval) {
@@ -30134,6 +30250,18 @@ static void add_eval_variables(JSContext *ctx, JSFunctionDef *s)
}
}
+static void set_closure_from_var(JSContext *ctx, JSClosureVar *cv,
+ JSVarDef *vd, int var_idx)
+{
+ cv->is_local = TRUE;
+ cv->is_arg = FALSE;
+ cv->is_const = vd->is_const;
+ cv->is_lexical = vd->is_lexical;
+ cv->var_kind = vd->var_kind;
+ cv->var_idx = var_idx;
+ cv->var_name = JS_DupAtom(ctx, vd->var_name);
+}
+
/* for direct eval compilation: add references to the variables of the
calling function */
static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
@@ -30141,7 +30269,8 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
{
int i, count;
JSVarDef *vd;
-
+ BOOL is_arg_scope;
+
count = b->arg_count + b->var_count + b->closure_var_count;
s->closure_var = NULL;
s->closure_var_count = 0;
@@ -30156,41 +30285,41 @@ static __exception int add_closure_variables(JSContext *ctx, JSFunctionDef *s,
vd = &b->vardefs[b->arg_count + i];
if (vd->scope_level > 0) {
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- cv->is_local = TRUE;
- cv->is_arg = FALSE;
- cv->is_const = vd->is_const;
- cv->is_lexical = vd->is_lexical;
- cv->var_kind = vd->var_kind;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
+ set_closure_from_var(ctx, cv, vd, i);
}
i = vd->scope_next;
}
- /* Add argument variables */
- for(i = 0; i < b->arg_count; i++) {
- JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
- vd = &b->vardefs[i];
- cv->is_local = TRUE;
- cv->is_arg = TRUE;
- cv->is_const = FALSE;
- cv->is_lexical = FALSE;
- cv->var_kind = JS_VAR_NORMAL;
- cv->var_idx = i;
- cv->var_name = JS_DupAtom(ctx, vd->var_name);
- }
- /* Add local non lexical variables */
- for(i = 0; i < b->var_count; i++) {
- vd = &b->vardefs[b->arg_count + i];
- if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
+ is_arg_scope = (i == ARG_SCOPE_END);
+ if (!is_arg_scope) {
+ /* Add argument variables */
+ for(i = 0; i < b->arg_count; i++) {
JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ vd = &b->vardefs[i];
cv->is_local = TRUE;
- cv->is_arg = FALSE;
+ cv->is_arg = TRUE;
cv->is_const = FALSE;
cv->is_lexical = FALSE;
cv->var_kind = JS_VAR_NORMAL;
cv->var_idx = i;
cv->var_name = JS_DupAtom(ctx, vd->var_name);
}
+ /* Add local non lexical variables */
+ for(i = 0; i < b->var_count; i++) {
+ vd = &b->vardefs[b->arg_count + i];
+ if (vd->scope_level == 0 && vd->var_name != JS_ATOM__ret_) {
+ JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ set_closure_from_var(ctx, cv, vd, i);
+ }
+ }
+ } else {
+ /* only add pseudo variables */
+ for(i = 0; i < b->var_count; i++) {
+ vd = &b->vardefs[b->arg_count + i];
+ if (vd->scope_level == 0 && is_var_in_arg_scope(vd)) {
+ JSClosureVar *cv = &s->closure_var[s->closure_var_count++];
+ set_closure_from_var(ctx, cv, vd, i);
+ }
+ }
}
for(i = 0; i < b->closure_var_count; i++) {
JSClosureVar *cv0 = &b->closure_var[i];
@@ -30348,59 +30477,93 @@ static BOOL code_match(CodeContext *s, int pos, ...)
static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, DynBuf *bc)
{
- int i, idx, var_idx;
+ int i, idx, label_next = -1;
+
+ /* add the hoisted functions in arguments and local variables */
+ for(i = 0; i < s->arg_count; i++) {
+ JSVarDef *vd = &s->args[i];
+ if (vd->func_pool_idx >= 0) {
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, vd->func_pool_idx);
+ dbuf_putc(bc, OP_put_arg);
+ dbuf_put_u16(bc, i);
+ }
+ }
+ for(i = 0; i < s->var_count; i++) {
+ JSVarDef *vd = &s->vars[i];
+ if (vd->scope_level == 0 && vd->func_pool_idx >= 0) {
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, vd->func_pool_idx);
+ dbuf_putc(bc, OP_put_loc);
+ dbuf_put_u16(bc, i);
+ }
+ }
- /* add the hoisted functions and variables */
- for(i = 0; i < s->hoisted_def_count; i++) {
- JSHoistedDef *hf = &s->hoisted_def[i];
+ /* the module global variables must be initialized before
+ evaluating the module so that the exported functions are
+ visible if there are cyclic module references */
+ if (s->module) {
+ label_next = new_label_fd(s, -1);
+
+ /* if 'this' is true, initialize the global variables and return */
+ dbuf_putc(bc, OP_push_this);
+ dbuf_putc(bc, OP_if_false);
+ dbuf_put_u32(bc, label_next);
+ update_label(s, label_next, 1);
+ s->jump_size++;
+ }
+
+ /* add the global variables (only happens if s->is_global_var is
+ true) */
+ for(i = 0; i < s->global_var_count; i++) {
+ JSGlobalVar *hf = &s->global_vars[i];
int has_closure = 0;
BOOL force_init = hf->force_init;
- if (s->is_global_var && hf->var_name != JS_ATOM_NULL) {
- /* we are in an eval, so the closure contains all the
- enclosing variables */
- /* If the outer function has a variable environment,
- create a property for the variable there */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- has_closure = 2;
- force_init = FALSE;
- break;
- }
- if (cv->var_name == JS_ATOM__var_) {
- dbuf_putc(bc, OP_get_var_ref);
- dbuf_put_u16(bc, idx);
- has_closure = 1;
- force_init = TRUE;
- break;
- }
+ /* we are in an eval, so the closure contains all the
+ enclosing variables */
+ /* If the outer function has a variable environment,
+ create a property for the variable there */
+ for(idx = 0; idx < s->closure_var_count; idx++) {
+ JSClosureVar *cv = &s->closure_var[idx];
+ if (cv->var_name == hf->var_name) {
+ has_closure = 2;
+ force_init = FALSE;
+ break;
}
- if (!has_closure) {
- int flags;
-
- flags = 0;
- if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
- flags |= JS_PROP_CONFIGURABLE;
- if (hf->cpool_idx >= 0 && !hf->is_lexical) {
- /* global function definitions need a specific handling */
- dbuf_putc(bc, OP_fclosure);
- dbuf_put_u32(bc, hf->cpool_idx);
-
- dbuf_putc(bc, OP_define_func);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
-
- goto done_hoisted_def;
- } else {
- if (hf->is_lexical) {
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (!hf->is_const)
- flags |= JS_PROP_WRITABLE;
- }
- dbuf_putc(bc, OP_define_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, flags);
+ if (cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_) {
+ dbuf_putc(bc, OP_get_var_ref);
+ dbuf_put_u16(bc, idx);
+ has_closure = 1;
+ force_init = TRUE;
+ break;
+ }
+ }
+ if (!has_closure) {
+ int flags;
+
+ flags = 0;
+ if (s->eval_type != JS_EVAL_TYPE_GLOBAL)
+ flags |= JS_PROP_CONFIGURABLE;
+ if (hf->cpool_idx >= 0 && !hf->is_lexical) {
+ /* global function definitions need a specific handling */
+ dbuf_putc(bc, OP_fclosure);
+ dbuf_put_u32(bc, hf->cpool_idx);
+
+ dbuf_putc(bc, OP_define_func);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, flags);
+
+ goto done_global_var;
+ } else {
+ if (hf->is_lexical) {
+ flags |= DEFINE_GLOBAL_LEX_VAR;
+ if (!hf->is_const)
+ flags |= JS_PROP_WRITABLE;
}
+ dbuf_putc(bc, OP_define_var);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, flags);
}
}
if (hf->cpool_idx >= 0 || force_init) {
@@ -30415,37 +30578,35 @@ static void instantiate_hoisted_definitions(JSContext *ctx, JSFunctionDef *s, Dy
} else {
dbuf_putc(bc, OP_undefined);
}
- if (s->is_global_var) {
- if (has_closure == 2) {
- dbuf_putc(bc, OP_put_var_ref);
- dbuf_put_u16(bc, idx);
- } else if (has_closure == 1) {
- dbuf_putc(bc, OP_define_field);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(bc, OP_drop);
- } else {
- /* XXX: Check if variable is writable and enumerable */
- dbuf_putc(bc, OP_put_var);
- dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
- }
+ if (has_closure == 2) {
+ dbuf_putc(bc, OP_put_var_ref);
+ dbuf_put_u16(bc, idx);
+ } else if (has_closure == 1) {
+ dbuf_putc(bc, OP_define_field);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(bc, OP_drop);
} else {
- var_idx = hf->var_idx;
- if (var_idx & ARGUMENT_VAR_OFFSET) {
- dbuf_putc(bc, OP_put_arg);
- dbuf_put_u16(bc, var_idx - ARGUMENT_VAR_OFFSET);
- } else {
- dbuf_putc(bc, OP_put_loc);
- dbuf_put_u16(bc, var_idx);
- }
+ /* XXX: Check if variable is writable and enumerable */
+ dbuf_putc(bc, OP_put_var);
+ dbuf_put_u32(bc, JS_DupAtom(ctx, hf->var_name));
}
}
- done_hoisted_def:
+ done_global_var:
JS_FreeAtom(ctx, hf->var_name);
}
- js_free(ctx, s->hoisted_def);
- s->hoisted_def = NULL;
- s->hoisted_def_count = 0;
- s->hoisted_def_size = 0;
+
+ if (s->module) {
+ dbuf_putc(bc, OP_return_undef);
+
+ dbuf_putc(bc, OP_label);
+ dbuf_put_u32(bc, label_next);
+ s->label_slots[label_next].pos2 = bc->size;
+ }
+
+ js_free(ctx, s->global_vars);
+ s->global_vars = NULL;
+ s->global_var_count = 0;
+ s->global_var_size = 0;
}
static int skip_dead_code(JSFunctionDef *s, const uint8_t *bc_buf, int bc_len,
@@ -30525,7 +30686,7 @@ static int get_label_pos(JSFunctionDef *s, int label)
variables when necessary */
static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
{
- int pos, pos_next, bc_len, op, len, i, idx, arg_valid, line_num;
+ int pos, pos_next, bc_len, op, len, i, idx, line_num;
uint8_t *bc_buf;
JSAtom var_name;
DynBuf bc_out;
@@ -30538,47 +30699,43 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
/* first pass for runtime checks (must be done before the
variables are created) */
- if (s->is_global_var) {
- for(i = 0; i < s->hoisted_def_count; i++) {
- JSHoistedDef *hf = &s->hoisted_def[i];
- int flags;
-
- if (hf->var_name != JS_ATOM_NULL) {
- /* check if global variable (XXX: simplify) */
- for(idx = 0; idx < s->closure_var_count; idx++) {
- JSClosureVar *cv = &s->closure_var[idx];
- if (cv->var_name == hf->var_name) {
- if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
- cv->is_lexical) {
- /* Check if a lexical variable is
- redefined as 'var'. XXX: Could abort
- compilation here, but for consistency
- with the other checks, we delay the
- error generation. */
- dbuf_putc(&bc_out, OP_throw_var);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
- }
- goto next;
- }
- if (cv->var_name == JS_ATOM__var_)
- goto next;
+ for(i = 0; i < s->global_var_count; i++) {
+ JSGlobalVar *hf = &s->global_vars[i];
+ int flags;
+
+ /* check if global variable (XXX: simplify) */
+ for(idx = 0; idx < s->closure_var_count; idx++) {
+ JSClosureVar *cv = &s->closure_var[idx];
+ if (cv->var_name == hf->var_name) {
+ if (s->eval_type == JS_EVAL_TYPE_DIRECT &&
+ cv->is_lexical) {
+ /* Check if a lexical variable is
+ redefined as 'var'. XXX: Could abort
+ compilation here, but for consistency
+ with the other checks, we delay the
+ error generation. */
+ dbuf_putc(&bc_out, OP_throw_error);
+ dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+ dbuf_putc(&bc_out, JS_THROW_VAR_REDECL);
}
-
- dbuf_putc(&bc_out, OP_check_define_var);
- dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
- flags = 0;
- if (hf->is_lexical)
- flags |= DEFINE_GLOBAL_LEX_VAR;
- if (hf->cpool_idx >= 0)
- flags |= DEFINE_GLOBAL_FUNC_VAR;
- dbuf_putc(&bc_out, flags);
+ goto next;
}
- next: ;
+ if (cv->var_name == JS_ATOM__var_ ||
+ cv->var_name == JS_ATOM__arg_var_)
+ goto next;
}
+
+ dbuf_putc(&bc_out, OP_check_define_var);
+ dbuf_put_u32(&bc_out, JS_DupAtom(ctx, hf->var_name));
+ flags = 0;
+ if (hf->is_lexical)
+ flags |= DEFINE_GLOBAL_LEX_VAR;
+ if (hf->cpool_idx >= 0)
+ flags |= DEFINE_GLOBAL_FUNC_VAR;
+ dbuf_putc(&bc_out, flags);
+ next: ;
}
- arg_valid = 0;
line_num = 0; /* avoid warning */
for (pos = 0; pos < bc_len; pos = pos_next) {
op = bc_buf[pos];
@@ -30590,9 +30747,6 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
s->line_number_size++;
goto no_change;
- case OP_set_arg_valid_upto:
- arg_valid = get_u16(bc_buf + pos + 1);
- break;
case OP_eval: /* convert scope index to adjusted variable index */
{
int call_argc = get_u16(bc_buf + pos + 1);
@@ -30618,7 +30772,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
var_name = get_u32(bc_buf + pos + 1);
scope = get_u16(bc_buf + pos + 5);
pos_next = resolve_scope_var(ctx, s, var_name, scope, op, &bc_out,
- NULL, NULL, pos_next, arg_valid);
+ NULL, NULL, pos_next);
JS_FreeAtom(ctx, var_name);
break;
case OP_scope_make_ref:
@@ -30631,7 +30785,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
ls = &s->label_slots[label];
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, arg_valid);
+ bc_buf, ls, pos_next);
JS_FreeAtom(ctx, var_name);
}
break;
@@ -30712,7 +30866,7 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
case OP_return:
case OP_return_undef:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_ret:
if (OPTIMIZE) {
/* remove dead code */
@@ -30746,25 +30900,27 @@ static __exception int resolve_variables(JSContext *ctx, JSFunctionDef *s)
{
int scope_idx, scope = get_u16(bc_buf + pos + 1);
- if (scope == 1) {
+ if (scope == s->body_scope) {
instantiate_hoisted_definitions(ctx, s, &bc_out);
}
for(scope_idx = s->scopes[scope].first; scope_idx >= 0;) {
JSVarDef *vd = &s->vars[scope_idx];
if (vd->scope_level == scope) {
- if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
- vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
- /* Initialize lexical variable upon entering scope */
- dbuf_putc(&bc_out, OP_fclosure);
- dbuf_put_u32(&bc_out, vd->func_pool_or_scope_idx);
- dbuf_putc(&bc_out, OP_put_loc);
- dbuf_put_u16(&bc_out, scope_idx);
- } else {
- /* XXX: should check if variable can be used
- before initialization */
- dbuf_putc(&bc_out, OP_set_loc_uninitialized);
- dbuf_put_u16(&bc_out, scope_idx);
+ if (scope_idx != s->arguments_arg_idx) {
+ if (vd->var_kind == JS_VAR_FUNCTION_DECL ||
+ vd->var_kind == JS_VAR_NEW_FUNCTION_DECL) {
+ /* Initialize lexical variable upon entering scope */
+ dbuf_putc(&bc_out, OP_fclosure);
+ dbuf_put_u32(&bc_out, vd->func_pool_idx);
+ dbuf_putc(&bc_out, OP_put_loc);
+ dbuf_put_u16(&bc_out, scope_idx);
+ } else {
+ /* XXX: should check if variable can be used
+ before initialization */
+ dbuf_putc(&bc_out, OP_set_loc_uninitialized);
+ dbuf_put_u16(&bc_out, scope_idx);
+ }
}
scope_idx = vd->scope_next;
} else {
@@ -31167,6 +31323,8 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
dbuf_putc(&bc_out, OP_special_object);
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_MAPPED_ARGUMENTS);
}
+ if (s->arguments_arg_idx >= 0)
+ put_short_code(&bc_out, OP_set_loc, s->arguments_arg_idx);
put_short_code(&bc_out, OP_put_loc, s->arguments_var_idx);
}
/* initialize a reference to the current function if needed */
@@ -31181,6 +31339,11 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
put_short_code(&bc_out, OP_put_loc, s->var_object_idx);
}
+ if (s->arg_var_object_idx >= 0) {
+ dbuf_putc(&bc_out, OP_special_object);
+ dbuf_putc(&bc_out, OP_SPECIAL_OBJECT_VAR_OBJECT);
+ put_short_code(&bc_out, OP_put_loc, s->arg_var_object_idx);
+ }
for (pos = 0; pos < bc_len; pos = pos_next) {
int val;
@@ -31248,7 +31411,7 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
pos_next = skip_dead_code(s, bc_buf, bc_len, pos_next, &line_num);
goto no_change;
@@ -31969,56 +32132,91 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s)
/* compute the maximum stack size needed by the function */
typedef struct StackSizeState {
+ int bc_len;
int stack_len_max;
uint16_t *stack_level_tab;
+ int *pc_stack;
+ int pc_stack_len;
+ int pc_stack_size;
} StackSizeState;
-static __exception int compute_stack_size_rec(JSContext *ctx,
- JSFunctionDef *fd,
- StackSizeState *s,
- int pos, int op, int stack_len)
+/* 'op' is only used for error indication */
+static __exception int ss_check(JSContext *ctx, StackSizeState *s,
+ int pos, int op, int stack_len)
{
- int bc_len, diff, n_pop, pos_next;
- const JSOpCode *oi;
- const uint8_t *bc_buf;
-
+ if ((unsigned)pos >= s->bc_len) {
+ JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
+ return -1;
+ }
if (stack_len > s->stack_len_max) {
s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX)
- goto stack_overflow;
+ if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+ JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+ return -1;
+ }
}
- bc_buf = fd->byte_code.buf;
- bc_len = fd->byte_code.size;
- for(;;) {
- if ((unsigned)pos >= bc_len)
- goto buf_overflow;
-#if 0
- printf("%5d: %d\n", pos, stack_len);
-#endif
- if (s->stack_level_tab[pos] != 0xffff) {
- /* already explored: check that the stack size is consistent */
- if (s->stack_level_tab[pos] != stack_len) {
- JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
- s->stack_level_tab[pos], stack_len, pos);
- return -1;
- } else {
- return 0;
- }
+ if (s->stack_level_tab[pos] != 0xffff) {
+ /* already explored: check that the stack size is consistent */
+ if (s->stack_level_tab[pos] != stack_len) {
+ JS_ThrowInternalError(ctx, "unconsistent stack size: %d %d (pc=%d)",
+ s->stack_level_tab[pos], stack_len, pos);
+ return -1;
} else {
- s->stack_level_tab[pos] = stack_len;
+ return 0;
}
+ }
+
+ /* mark as explored and store the stack size */
+ s->stack_level_tab[pos] = stack_len;
+
+ /* 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))
+ return -1;
+ s->pc_stack[s->pc_stack_len++] = pos;
+ return 0;
+}
+static __exception int compute_stack_size(JSContext *ctx,
+ JSFunctionDef *fd,
+ int *pstack_size)
+{
+ StackSizeState s_s, *s = &s_s;
+ int i, diff, n_pop, pos_next, stack_len, pos, op;
+ const JSOpCode *oi;
+ const uint8_t *bc_buf;
+
+ bc_buf = fd->byte_code.buf;
+ 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);
+ if (!s->stack_level_tab)
+ return -1;
+ for(i = 0; i < s->bc_len; i++)
+ s->stack_level_tab[i] = 0xffff;
+ s->stack_len_max = 0;
+ s->pc_stack = NULL;
+ s->pc_stack_len = 0;
+ s->pc_stack_size = 0;
+
+ /* breadth-first graph exploration */
+ if (ss_check(ctx, s, 0, OP_invalid, 0))
+ goto fail;
+
+ while (s->pc_stack_len > 0) {
+ pos = s->pc_stack[--s->pc_stack_len];
+ stack_len = s->stack_level_tab[pos];
op = bc_buf[pos];
if (op == 0 || op >= OP_COUNT) {
JS_ThrowInternalError(ctx, "invalid opcode (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
oi = &short_opcode_info(op);
pos_next = pos + oi->size;
- if (pos_next > bc_len) {
- buf_overflow:
+ if (pos_next > s->bc_len) {
JS_ThrowInternalError(ctx, "bytecode buffer overflow (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
n_pop = oi->n_pop;
/* call pops a variable number of arguments */
@@ -32034,13 +32232,15 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
if (stack_len < n_pop) {
JS_ThrowInternalError(ctx, "stack underflow (op=%d, pc=%d)", op, pos);
- return -1;
+ goto fail;
}
stack_len += oi->n_push - n_pop;
if (stack_len > s->stack_len_max) {
s->stack_len_max = stack_len;
- if (s->stack_len_max > JS_STACK_SIZE_MAX)
- goto stack_overflow;
+ if (s->stack_len_max > JS_STACK_SIZE_MAX) {
+ JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
+ goto fail;
+ }
}
switch(op) {
case OP_tail_call:
@@ -32049,9 +32249,9 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
case OP_return_undef:
case OP_return_async:
case OP_throw:
- case OP_throw_var:
+ case OP_throw_error:
case OP_ret:
- goto done;
+ goto done_insn;
case OP_goto:
diff = get_u32(bc_buf + pos + 1);
pos_next = pos + 1 + diff;
@@ -32068,73 +32268,57 @@ static __exception int compute_stack_size_rec(JSContext *ctx,
case OP_if_true8:
case OP_if_false8:
diff = (int8_t)bc_buf[pos + 1];
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ goto fail;
break;
#endif
case OP_if_true:
case OP_if_false:
case OP_catch:
diff = get_u32(bc_buf + pos + 1);
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len))
+ goto fail;
break;
case OP_gosub:
diff = get_u32(bc_buf + pos + 1);
- if (compute_stack_size_rec(ctx, fd, s, pos + 1 + diff, op, stack_len + 1))
- return -1;
+ if (ss_check(ctx, s, pos + 1 + diff, op, stack_len + 1))
+ goto fail;
break;
case OP_with_get_var:
case OP_with_delete_var:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 1))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 1))
+ goto fail;
break;
case OP_with_make_ref:
case OP_with_get_ref:
case OP_with_get_ref_undef:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len + 2))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len + 2))
+ goto fail;
break;
case OP_with_put_var:
diff = get_u32(bc_buf + pos + 5);
- if (compute_stack_size_rec(ctx, fd, s, pos + 5 + diff, op, stack_len - 1))
- return -1;
+ if (ss_check(ctx, s, pos + 5 + diff, op, stack_len - 1))
+ goto fail;
break;
default:
break;
}
- pos = pos_next;
+ if (ss_check(ctx, s, pos_next, op, stack_len))
+ goto fail;
+ done_insn: ;
}
- done:
- return 0;
-
- stack_overflow:
- JS_ThrowInternalError(ctx, "stack overflow (op=%d, pc=%d)", op, pos);
- return -1;
-}
-
-static __exception int compute_stack_size(JSContext *ctx,
- JSFunctionDef *fd,
- int *pstack_size)
-{
- StackSizeState s_s, *s = &s_s;
- int bc_len, i, ret;
-
- bc_len = fd->byte_code.size;
- /* bc_len > 0 */
- s->stack_level_tab = js_malloc(ctx, sizeof(s->stack_level_tab[0]) * bc_len);
- if (!s->stack_level_tab)
- return -1;
- for(i = 0; i < bc_len; i++)
- s->stack_level_tab[i] = 0xffff;
- s->stack_len_max = 0;
- ret = compute_stack_size_rec(ctx, fd, s, 0, OP_invalid, 0);
js_free(ctx, s->stack_level_tab);
+ js_free(ctx, s->pc_stack);
*pstack_size = s->stack_len_max;
- return ret;
+ return 0;
+ fail:
+ js_free(ctx, s->stack_level_tab);
+ js_free(ctx, s->pc_stack);
+ *pstack_size = 0;
+ return -1;
}
static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
@@ -32142,14 +32326,14 @@ static int add_module_variables(JSContext *ctx, JSFunctionDef *fd)
int i, idx;
JSModuleDef *m = fd->module;
JSExportEntry *me;
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
/* The imported global variables were added as closure variables
in js_parse_import(). We add here the module global
variables. */
- for(i = 0; i < fd->hoisted_def_count; i++) {
- hf = &fd->hoisted_def[i];
+ for(i = 0; i < fd->global_var_count; i++) {
+ hf = &fd->global_vars[i];
if (add_closure_var(ctx, fd, TRUE, FALSE, i, hf->var_name, hf->is_const,
hf->is_lexical, FALSE) < 0)
return -1;
@@ -32187,6 +32371,10 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
for (scope = 0; scope < fd->scope_count; scope++) {
fd->scopes[scope].first = -1;
}
+ if (fd->has_parameter_expressions) {
+ /* special end of variable list marker for the argument scope */
+ fd->scopes[ARG_SCOPE_INDEX].first = ARG_SCOPE_END;
+ }
for (idx = 0; idx < fd->var_count; idx++) {
JSVarDef *vd = &fd->vars[idx];
vd->scope_next = fd->scopes[vd->scope_level].first;
@@ -32194,12 +32382,12 @@ static JSValue js_create_function(JSContext *ctx, JSFunctionDef *fd)
}
for (scope = 2; scope < fd->scope_count; scope++) {
JSVarScope *sd = &fd->scopes[scope];
- if (sd->first == -1)
+ if (sd->first < 0)
sd->first = fd->scopes[sd->parent].first;
}
for (idx = 0; idx < fd->var_count; idx++) {
JSVarDef *vd = &fd->vars[idx];
- if (vd->scope_next == -1 && vd->scope_level > 1) {
+ if (vd->scope_next < 0 && vd->scope_level > 1) {
scope = fd->scopes[vd->scope_level].parent;
vd->scope_next = fd->scopes[scope].first;
}
@@ -32571,7 +32759,8 @@ static int js_parse_function_check_names(JSParseState *s, JSFunctionDef *fd,
/* Check if argument name duplicates a destructuring parameter */
/* XXX: should have a flag for such variables */
for (i = 0; i < fd->var_count; i++) {
- if (fd->vars[i].var_name == name)
+ if (fd->vars[i].var_name == name &&
+ fd->vars[i].scope_level == 0)
goto duplicate;
}
}
@@ -32680,8 +32869,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (fd->is_eval && fd->eval_type == JS_EVAL_TYPE_MODULE &&
(func_type == JS_PARSE_FUNC_STATEMENT || func_type == JS_PARSE_FUNC_VAR)) {
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, func_name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, func_name);
/* XXX: should check scope chain */
if (hf && hf->scope_level == fd->scope_level) {
js_parse_error(s, "invalid redefinition of global identifier in module code");
@@ -32691,21 +32880,23 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
if (func_type == JS_PARSE_FUNC_VAR) {
- /* Create lexical name here so function closure contains it */
if (!(fd->js_mode & JS_MODE_STRICT)
+ && func_kind == JS_FUNC_NORMAL
&& find_lexical_decl(ctx, fd, func_name, fd->scope_first, FALSE) < 0
&& !((func_idx = find_var(ctx, fd, func_name)) >= 0 && (func_idx & ARGUMENT_VAR_OFFSET))
&& !(func_name == JS_ATOM_arguments && fd->has_arguments_binding)) {
create_func_var = TRUE;
}
+ /* Create the lexical name here so that the function closure
+ contains it */
if (fd->is_eval &&
(fd->eval_type == JS_EVAL_TYPE_GLOBAL ||
fd->eval_type == JS_EVAL_TYPE_MODULE) &&
- fd->scope_level == 1) {
+ fd->scope_level == fd->body_scope) {
/* avoid creating a lexical variable in the global
scope. XXX: check annex B */
- JSHoistedDef *hf;
- hf = find_hoisted_def(fd, func_name);
+ JSGlobalVar *hf;
+ hf = find_global_var(fd, func_name);
/* XXX: should check scope chain */
if (hf && hf->scope_level == fd->scope_level) {
js_parse_error(s, "invalid redefinition of global identifier");
@@ -32780,6 +32971,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* parse arguments */
fd->has_simple_parameter_list = TRUE;
+ fd->has_parameter_expressions = FALSE;
has_opt_arg = FALSE;
if (func_type == JS_PARSE_FUNC_ARROW && s->token.val == TOK_IDENT) {
JSAtom name;
@@ -32792,13 +32984,30 @@ static __exception int js_parse_function_decl2(JSParseState *s,
goto fail;
fd->defined_arg_count = 1;
} else {
- if (js_parse_expect(s, '('))
- goto fail;
+ if (s->token.val == '(') {
+ int skip_bits;
+ /* if there is an '=' inside the parameter list, we
+ consider there is a parameter expression inside */
+ js_parse_skip_parens_token(s, &skip_bits, FALSE);
+ if (skip_bits & SKIP_HAS_ASSIGNMENT)
+ fd->has_parameter_expressions = TRUE;
+ if (next_token(s))
+ goto fail;
+ } else {
+ if (js_parse_expect(s, '('))
+ goto fail;
+ }
+ if (fd->has_parameter_expressions) {
+ fd->scope_level = -1; /* force no parent scope */
+ if (push_scope(s) < 0)
+ return -1;
+ }
+
while (s->token.val != ')') {
JSAtom name;
BOOL rest = FALSE;
- int idx;
+ int idx, has_initializer;
if (s->token.val == TOK_ELLIPSIS) {
fd->has_simple_parameter_list = FALSE;
@@ -32817,8 +33026,13 @@ static __exception int js_parse_function_decl2(JSParseState *s,
emit_op(s, OP_get_arg);
emit_u16(s, idx);
}
- if (js_parse_destructuring_element(s, TOK_VAR, 1, TRUE, -1, TRUE))
+ has_initializer = js_parse_destructuring_element(s, fd->has_parameter_expressions ? TOK_LET : TOK_VAR, 1, TRUE, -1, TRUE);
+ if (has_initializer < 0)
goto fail;
+ if (has_initializer)
+ has_opt_arg = TRUE;
+ if (!has_opt_arg)
+ fd->defined_arg_count++;
} else if (s->token.val == TOK_IDENT) {
if (s->token.u.ident.is_reserved) {
js_parse_error_reserved_identifier(s);
@@ -32829,6 +33043,11 @@ static __exception int js_parse_function_decl2(JSParseState *s,
js_parse_error_reserved_identifier(s);
goto fail;
}
+ if (fd->has_parameter_expressions) {
+ if (define_var(s, fd, name, JS_VAR_DEF_LET) < 0)
+ goto fail;
+ }
+ /* XXX: could avoid allocating an argument if rest is true */
idx = add_arg(ctx, fd, name);
if (idx < 0)
goto fail;
@@ -32837,70 +33056,55 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (rest) {
emit_op(s, OP_rest);
emit_u16(s, idx);
+ if (fd->has_parameter_expressions) {
+ emit_op(s, OP_dup);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
+ }
emit_op(s, OP_put_arg);
emit_u16(s, idx);
fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
} else if (s->token.val == '=') {
+ int label;
+
fd->has_simple_parameter_list = FALSE;
has_opt_arg = TRUE;
if (next_token(s))
goto fail;
- /* optimize `x = void 0` default value: no code needed */
- if (s->token.val == TOK_VOID) {
- JSParsePos pos;
- js_parse_get_pos(s, &pos);
- if (next_token(s))
- goto fail;
- if (s->token.val == TOK_NUMBER) {
- if (next_token(s))
- goto fail;
- if (s->token.val == ',') {
- if (next_token(s))
- goto fail;
- continue;
- }
- if (s->token.val == ')') {
- continue;
- }
- }
- if (js_parse_seek_token(s, &pos))
- goto fail;
+ label = new_label(s);
+ emit_op(s, OP_get_arg);
+ emit_u16(s, idx);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_undefined);
+ emit_op(s, OP_strict_eq);
+ emit_goto(s, OP_if_false, label);
+ emit_op(s, OP_drop);
+ if (js_parse_assign_expr(s))
+ goto fail;
+ set_object_name(s, name);
+ emit_op(s, OP_dup);
+ emit_op(s, OP_put_arg);
+ emit_u16(s, idx);
+ emit_label(s, label);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
+ } else {
+ if (!has_opt_arg) {
+ fd->defined_arg_count++;
}
-#if 0
- /* XXX: not correct for eval code */
- /* Check for a default value of `undefined`
- to omit default argument processing */
- if (s->token.val == TOK_IDENT &&
- s->token.u.ident.atom == JS_ATOM_undefined &&
- fd->parent == NULL &&
- ((tok = peek_token(s, FALSE)) == ',' || tok == ')')) {
- if (next_token(s)) /* ignore undefined token */
- goto fail;
- } else
-#endif
- {
- int label = new_label(s);
- if (idx > 0) {
- emit_op(s, OP_set_arg_valid_upto);
- emit_u16(s, idx);
- }
+ if (fd->has_parameter_expressions) {
+ /* copy the argument to the argument scope */
emit_op(s, OP_get_arg);
emit_u16(s, idx);
- emit_op(s, OP_undefined);
- emit_op(s, OP_strict_eq);
- emit_goto(s, OP_if_false, label);
- if (js_parse_assign_expr(s, TRUE))
- goto fail;
- set_object_name(s, name);
- emit_op(s, OP_put_arg);
- emit_u16(s, idx);
- emit_label(s, label);
+ emit_op(s, OP_scope_put_var_init);
+ emit_atom(s, name);
+ emit_u16(s, fd->scope_level);
}
- } else if (!has_opt_arg) {
- fd->defined_arg_count++;
}
} else {
js_parse_error(s, "missing formal parameter");
@@ -32922,6 +33126,41 @@ static __exception int js_parse_function_decl2(JSParseState *s,
}
}
+ if (fd->has_parameter_expressions) {
+ int idx;
+
+ /* Copy the variables in the argument scope to the variable
+ scope (see FunctionDeclarationInstantiation() in spec). The
+ normal arguments are already present, so no need to copy
+ them. */
+ idx = fd->scopes[fd->scope_level].first;
+ while (idx >= 0) {
+ JSVarDef *vd = &fd->vars[idx];
+ if (vd->scope_level != fd->scope_level)
+ break;
+ if (find_var(ctx, fd, vd->var_name) < 0) {
+ if (add_var(ctx, fd, vd->var_name) < 0)
+ goto fail;
+ vd = &fd->vars[idx]; /* fd->vars may have been reallocated */
+ emit_op(s, OP_scope_get_var);
+ emit_atom(s, vd->var_name);
+ emit_u16(s, fd->scope_level);
+ emit_op(s, OP_scope_put_var);
+ emit_atom(s, vd->var_name);
+ emit_u16(s, 0);
+ }
+ idx = vd->scope_next;
+ }
+
+ /* the argument scope has no parent, hence we don't use pop_scope(s) */
+ emit_op(s, OP_leave_scope);
+ emit_u16(s, fd->scope_level);
+
+ /* set the variable scope as the current scope */
+ fd->scope_level = 0;
+ fd->scope_first = fd->scopes[fd->scope_level].first;
+ }
+
if (next_token(s))
goto fail;
@@ -32933,7 +33172,8 @@ static __exception int js_parse_function_decl2(JSParseState *s,
/* in generators, yield expression is forbidden during the parsing
of the arguments */
fd->in_function_body = TRUE;
- push_scope(s); /* enter body scope: fd->scope_level = 1 */
+ push_scope(s); /* enter body scope */
+ fd->body_scope = fd->scope_level;
if (s->token.val == TOK_ARROW) {
if (next_token(s))
@@ -32943,7 +33183,7 @@ static __exception int js_parse_function_decl2(JSParseState *s,
if (js_parse_function_check_names(s, fd, func_name))
goto fail;
- if (js_parse_assign_expr(s, TRUE))
+ if (js_parse_assign_expr(s))
goto fail;
if (func_kind != JS_FUNC_NORMAL)
@@ -33025,10 +33265,10 @@ done:
emit_u32(s, idx);
if (create_func_var) {
if (s->cur_func->is_global_var) {
- JSHoistedDef *hf;
+ JSGlobalVar *hf;
/* the global variable must be defined at the start of the
function */
- hf = add_hoisted_def(ctx, s->cur_func, -1, func_name, -1, FALSE);
+ hf = add_global_var(ctx, s->cur_func, func_name);
if (!hf)
goto fail;
/* it is considered as defined at the top level
@@ -33058,7 +33298,7 @@ done:
}
if (lexical_func_idx >= 0) {
/* lexical variable will be initialized upon entering scope */
- s->cur_func->vars[lexical_func_idx].func_pool_or_scope_idx = idx;
+ s->cur_func->vars[lexical_func_idx].func_pool_idx = idx;
emit_op(s, OP_drop);
} else {
/* store function object into its lexical name */
@@ -33074,17 +33314,23 @@ done:
if (var_idx < 0)
goto fail;
/* the variable will be assigned at the top of the function */
- if (!add_hoisted_def(ctx, s->cur_func, idx, JS_ATOM_NULL, var_idx, FALSE))
- goto fail;
+ if (var_idx & ARGUMENT_VAR_OFFSET) {
+ s->cur_func->args[var_idx - ARGUMENT_VAR_OFFSET].func_pool_idx = idx;
+ } else {
+ s->cur_func->vars[var_idx].func_pool_idx = idx;
+ }
} else {
JSAtom func_var_name;
+ JSGlobalVar *hf;
if (func_name == JS_ATOM_NULL)
func_var_name = JS_ATOM__default_; /* export default */
else
func_var_name = func_name;
/* the variable will be assigned at the top of the function */
- if (!add_hoisted_def(ctx, s->cur_func, idx, func_var_name, -1, FALSE))
+ hf = add_global_var(ctx, s->cur_func, func_var_name);
+ if (!hf)
goto fail;
+ hf->cpool_idx = idx;
if (export_flag != JS_PARSE_EXPORT_NONE) {
if (!add_export_entry(s, s->cur_func->module, func_var_name,
export_flag == JS_PARSE_EXPORT_NAMED ? func_var_name : JS_ATOM_default, JS_EXPORT_TYPE_LOCAL))
@@ -33186,7 +33432,7 @@ static JSValue JS_EvalFunctionInternal(JSContext *ctx, JSValue fun_obj,
JS_FreeValue(ctx, fun_obj);
if (js_create_module_function(ctx, m) < 0)
goto fail;
- if (js_instantiate_module(ctx, m) < 0)
+ if (js_link_module(ctx, m) < 0)
goto fail;
ret_val = js_evaluate_module(ctx, m);
if (JS_IsException(ret_val)) {
@@ -33308,7 +33554,8 @@ static JSValue __JS_EvalInternal(JSContext *ctx, JSValueConst this_obj,
s->allow_html_comments = !s->is_module;
push_scope(s); /* body scope */
-
+ fd->body_scope = fd->scope_level;
+
err = js_parse_program(s);
if (err) {
fail:
@@ -33371,19 +33618,27 @@ static JSValue JS_EvalObject(JSContext *ctx, JSValueConst this_obj,
}
-JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
- const char *filename, int eval_flags)
+JSValue JS_EvalThis(JSContext *ctx, JSValueConst this_obj,
+ const char *input, size_t input_len,
+ const char *filename, int eval_flags)
{
int eval_type = eval_flags & JS_EVAL_TYPE_MASK;
JSValue ret;
assert(eval_type == JS_EVAL_TYPE_GLOBAL ||
eval_type == JS_EVAL_TYPE_MODULE);
- ret = JS_EvalInternal(ctx, ctx->global_obj, input, input_len, filename,
+ ret = JS_EvalInternal(ctx, this_obj, input, input_len, filename,
eval_flags, -1);
return ret;
}
+JSValue JS_Eval(JSContext *ctx, const char *input, size_t input_len,
+ const char *filename, int eval_flags)
+{
+ return JS_EvalThis(ctx, ctx->global_obj, input, input_len, filename,
+ eval_flags);
+}
+
int JS_ResolveModule(JSContext *ctx, JSValueConst obj)
{
if (JS_VALUE_GET_TAG(obj) == JS_TAG_MODULE) {
@@ -33980,7 +34235,6 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
bc_put_leb128(s, vd->scope_next + 1);
flags = idx = 0;
bc_set_flags(&flags, &idx, vd->var_kind, 4);
- bc_set_flags(&flags, &idx, vd->is_func_var, 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_captured, 1);
@@ -34971,7 +35225,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
goto fail;
idx = 0;
vd->var_kind = bc_get_flags(v8, &idx, 4);
- vd->is_func_var = 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_captured = bc_get_flags(v8, &idx, 1);
@@ -35628,16 +35881,39 @@ static JSAtom find_atom(JSContext *ctx, const char *name)
return atom;
}
-static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
- JSAtom atom, void *opaque)
+static JSValue JS_InstantiateFunctionListItem2(JSContext *ctx, JSObject *p,
+ JSAtom atom, void *opaque)
{
const JSCFunctionListEntry *e = opaque;
- JSValueConst obj = JS_MKPTR(JS_TAG_OBJECT, p);
+ JSValue val;
+
+ switch(e->def_type) {
+ case JS_DEF_CFUNC:
+ val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
+ e->name, e->u.func.length, e->u.func.cproto, e->magic);
+ break;
+ case JS_DEF_PROP_STRING:
+ val = JS_NewAtomString(ctx, e->u.str);
+ break;
+ case JS_DEF_OBJECT:
+ val = JS_NewObject(ctx);
+ JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
+ break;
+ default:
+ abort();
+ }
+ return val;
+}
+
+static int JS_InstantiateFunctionListItem(JSContext *ctx, JSValueConst obj,
+ JSAtom atom,
+ const JSCFunctionListEntry *e)
+{
JSValue val;
int prop_flags = e->prop_flags;
switch(e->def_type) {
- case JS_DEF_ALIAS:
+ case JS_DEF_ALIAS: /* using autoinit for aliases is not safe */
{
JSAtom atom1 = find_atom(ctx, e->u.alias.name);
switch (e->u.alias.base) {
@@ -35654,12 +35930,16 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
abort();
}
JS_FreeAtom(ctx, atom1);
- goto setval;
+ if (atom == JS_ATOM_Symbol_toPrimitive) {
+ /* Symbol.toPrimitive functions are not writable */
+ prop_flags = JS_PROP_CONFIGURABLE;
+ } else if (atom == JS_ATOM_Symbol_hasInstance) {
+ /* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
+ prop_flags = 0;
+ }
}
+ break;
case JS_DEF_CFUNC:
- val = JS_NewCFunction2(ctx, e->u.func.cfunc.generic,
- e->name, e->u.func.length, e->u.func.cproto, e->magic);
- setval:
if (atom == JS_ATOM_Symbol_toPrimitive) {
/* Symbol.toPrimitive functions are not writable */
prop_flags = JS_PROP_CONFIGURABLE;
@@ -35667,8 +35947,10 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
/* Function.prototype[Symbol.hasInstance] is not writable nor configurable */
prop_flags = 0;
}
- break;
- case JS_DEF_CGETSET:
+ JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
+ (void *)e, prop_flags);
+ return 0;
+ case JS_DEF_CGETSET: /* XXX: use autoinit again ? */
case JS_DEF_CGETSET_MAGIC:
{
JSValue getter, setter;
@@ -35692,9 +35974,6 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
return 0;
}
break;
- case JS_DEF_PROP_STRING:
- val = JS_NewAtomString(ctx, e->u.str);
- break;
case JS_DEF_PROP_INT32:
val = JS_NewInt32(ctx, e->u.i32);
break;
@@ -35707,10 +35986,11 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
case JS_DEF_PROP_UNDEFINED:
val = JS_UNDEFINED;
break;
+ case JS_DEF_PROP_STRING:
case JS_DEF_OBJECT:
- val = JS_NewObject(ctx);
- JS_SetPropertyFunctionList(ctx, val, e->u.prop_list.tab, e->u.prop_list.len);
- break;
+ JS_DefineAutoInitProperty(ctx, obj, atom, JS_AUTOINIT_ID_PROP,
+ (void *)e, prop_flags);
+ return 0;
default:
abort();
}
@@ -35721,36 +36001,12 @@ static int JS_InstantiateFunctionListItem(JSContext *ctx, JSObject *p,
void JS_SetPropertyFunctionList(JSContext *ctx, JSValueConst obj,
const JSCFunctionListEntry *tab, int len)
{
- int i, prop_flags;
+ int i;
for (i = 0; i < len; i++) {
const JSCFunctionListEntry *e = &tab[i];
JSAtom atom = find_atom(ctx, e->name);
-
- switch (e->def_type) {
- case JS_DEF_CFUNC:
- case JS_DEF_CGETSET:
- case JS_DEF_CGETSET_MAGIC:
- case JS_DEF_PROP_STRING:
- case JS_DEF_ALIAS:
- case JS_DEF_OBJECT:
- prop_flags = JS_PROP_WRITABLE | JS_PROP_CONFIGURABLE | (e->prop_flags & JS_PROP_ENUMERABLE);
- JS_DefineAutoInitProperty(ctx, obj, atom,
- JS_AUTOINIT_ID_PROP,
- (void *)e, prop_flags);
- break;
- case JS_DEF_PROP_INT32:
- case JS_DEF_PROP_INT64:
- case JS_DEF_PROP_DOUBLE:
- case JS_DEF_PROP_UNDEFINED:
- {
- JSObject *p = JS_VALUE_GET_OBJ(obj);
- JS_InstantiateFunctionListItem(ctx, p, atom, (void *)e);
- }
- break;
- default:
- abort();
- }
+ JS_InstantiateFunctionListItem(ctx, obj, atom, e);
JS_FreeAtom(ctx, atom);
}
}
@@ -37262,6 +37518,8 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
return tab;
}
+/* magic value: 0 = normal apply, 1 = apply for constructor, 2 =
+ Reflect.apply */
static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
@@ -37273,14 +37531,14 @@ static JSValue js_function_apply(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
this_arg = argv[0];
array_arg = argv[1];
- if (JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
- JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) {
+ if ((JS_VALUE_GET_TAG(array_arg) == JS_TAG_UNDEFINED ||
+ JS_VALUE_GET_TAG(array_arg) == JS_TAG_NULL) && magic != 2) {
return JS_Call(ctx, this_val, this_arg, 0, NULL);
}
tab = build_arg_list(ctx, &len, array_arg);
if (!tab)
return JS_EXCEPTION;
- if (magic) {
+ if (magic & 1) {
ret = JS_CallConstructor2(ctx, this_val, this_arg, len, (JSValueConst *)tab);
} else {
ret = JS_Call(ctx, this_val, this_arg, len, (JSValueConst *)tab);
@@ -37650,7 +37908,7 @@ static JSValue js_array_constructor(JSContext *ctx, JSValueConst new_target,
return obj;
if (argc == 1 && JS_IsNumber(argv[0])) {
uint32_t len;
- if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0])))
+ if (JS_ToArrayLengthFree(ctx, &len, JS_DupValue(ctx, argv[0]), TRUE))
goto fail;
if (JS_SetProperty(ctx, obj, JS_ATOM_length, JS_NewUint32(ctx, len)) < 0)
goto fail;
@@ -39659,46 +39917,6 @@ static int js_string_get_own_property(JSContext *ctx,
return FALSE;
}
-static uint32_t js_string_obj_get_length(JSContext *ctx,
- JSValueConst obj)
-{
- JSObject *p;
- JSString *p1;
- uint32_t len = 0;
-
- /* This is a class exotic method: obj class_id is JS_CLASS_STRING */
- p = JS_VALUE_GET_OBJ(obj);
- if (JS_VALUE_GET_TAG(p->u.object_data) == JS_TAG_STRING) {
- p1 = JS_VALUE_GET_STRING(p->u.object_data);
- len = p1->len;
- }
- return len;
-}
-
-static int js_string_get_own_property_names(JSContext *ctx,
- JSPropertyEnum **ptab,
- uint32_t *plen,
- JSValueConst obj)
-{
- JSPropertyEnum *tab;
- uint32_t len, i;
-
- len = js_string_obj_get_length(ctx, obj);
- tab = NULL;
- if (len > 0) {
- /* do not allocate 0 bytes */
- tab = js_malloc(ctx, sizeof(JSPropertyEnum) * len);
- if (!tab)
- return -1;
- for(i = 0; i < len; i++) {
- tab[i].atom = __JS_AtomFromUInt32(i);
- }
- }
- *ptab = tab;
- *plen = len;
- return 0;
-}
-
static int js_string_define_own_property(JSContext *ctx,
JSValueConst this_obj,
JSAtom prop, JSValueConst val,
@@ -39755,7 +39973,6 @@ static int js_string_delete_property(JSContext *ctx,
static const JSClassExoticMethods js_string_exotic_methods = {
.get_own_property = js_string_get_own_property,
- .get_own_property_names = js_string_get_own_property_names,
.define_own_property = js_string_define_own_property,
.delete_property = js_string_delete_property,
};
@@ -40359,15 +40576,17 @@ static JSValue js_string___GetSubstitution(JSContext *ctx, JSValueConst this_val
string_buffer_concat(b, sp, position + matched_len, sp->len);
} else if (c >= '0' && c <= '9') {
k = c - '0';
- c1 = string_get(rp, j);
- if (c1 >= '0' && c1 <= '9') {
- /* This behavior is specified in ES6 and refined in ECMA 2019 */
- /* ECMA 2019 does not have the extra test, but
- Test262 S15.5.4.11_A3_T1..3 require this behavior */
- k1 = k * 10 + c1 - '0';
- if (k1 >= 1 && k1 < captures_len) {
- k = k1;
- j++;
+ if (j < len) {
+ c1 = string_get(rp, j);
+ if (c1 >= '0' && c1 <= '9') {
+ /* This behavior is specified in ES6 and refined in ECMA 2019 */
+ /* ECMA 2019 does not have the extra test, but
+ Test262 S15.5.4.11_A3_T1..3 require this behavior */
+ k1 = k * 10 + c1 - '0';
+ if (k1 >= 1 && k1 < captures_len) {
+ k = k1;
+ j++;
+ }
}
}
if (k >= 1 && k < captures_len) {
@@ -42805,7 +43024,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
tab = JS_NewArray(ctx);
if (JS_IsException(tab))
goto exception;
- if (JS_SetPropertyInt64(ctx, tab, 0, JS_DupValue(ctx, matched)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, 0, JS_DupValue(ctx, matched),
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
for(n = 1; n < nCaptures; n++) {
JSValue capN;
@@ -42817,7 +43037,8 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(capN))
goto exception;
}
- if (JS_SetPropertyInt64(ctx, tab, n, capN) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n, capN,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
}
JS_FreeValue(ctx, namedCaptures);
@@ -42825,12 +43046,12 @@ static JSValue js_regexp_Symbol_replace(JSContext *ctx, JSValueConst this_val,
if (JS_IsException(namedCaptures))
goto exception;
if (functionalReplace) {
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_NewInt32(ctx, position)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_NewInt32(ctx, position), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, str)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, str), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (!JS_IsUndefined(namedCaptures)) {
- if (JS_SetPropertyInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures)) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, tab, n++, JS_DupValue(ctx, namedCaptures), JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
}
args[0] = JS_UNDEFINED;
@@ -42917,8 +43138,10 @@ static JSValue js_regexp_Symbol_search(JSContext *ctx, JSValueConst this_val,
if (js_same_value(ctx, currentLastIndex, previousLastIndex)) {
JS_FreeValue(ctx, previousLastIndex);
} else {
- if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0)
+ if (JS_SetProperty(ctx, rx, JS_ATOM_lastIndex, previousLastIndex) < 0) {
+ previousLastIndex = JS_UNDEFINED;
goto exception;
+ }
}
JS_FreeValue(ctx, str);
JS_FreeValue(ctx, currentLastIndex);
@@ -43023,7 +43246,8 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
sub = js_sub_string(ctx, strp, p, q);
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub,
+ JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (lengthA == lim)
goto done;
@@ -43034,7 +43258,7 @@ static JSValue js_regexp_Symbol_split(JSContext *ctx, JSValueConst this_val,
sub = JS_ToStringFree(ctx, JS_GetPropertyInt64(ctx, z, i));
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
if (lengthA == lim)
goto done;
@@ -43049,7 +43273,7 @@ add_tail:
sub = js_sub_string(ctx, strp, p, size);
if (JS_IsException(sub))
goto exception;
- if (JS_SetPropertyInt64(ctx, A, lengthA++, sub) < 0)
+ if (JS_DefinePropertyValueInt64(ctx, A, lengthA++, sub, JS_PROP_C_W_E | JS_PROP_THROW) < 0)
goto exception;
goto done;
exception:
@@ -43829,7 +44053,7 @@ void JS_AddIntrinsicJSON(JSContext *ctx)
static JSValue js_reflect_apply(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
- return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 0);
+ return js_function_apply(ctx, argv[0], max_int(0, argc - 1), argv + 1, 2);
}
static JSValue js_reflect_construct(JSContext *ctx, JSValueConst this_val,
@@ -46772,26 +46996,15 @@ static JSValue js_promise_then_finally_func(JSContext *ctx, JSValueConst this_va
{
JSValueConst ctor = func_data[0];
JSValueConst onFinally = func_data[1];
- JSValue res, promise, resolving_funcs[2], ret, then_func;
+ JSValue res, promise, ret, then_func;
res = JS_Call(ctx, onFinally, JS_UNDEFINED, 0, NULL);
if (JS_IsException(res))
return res;
- promise = js_new_promise_capability(ctx, resolving_funcs, ctor);
- if (JS_IsException(promise)) {
- JS_FreeValue(ctx, res);
- return JS_EXCEPTION;
- }
- ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED,
- 1, (JSValueConst*)&res);
+ promise = js_promise_resolve(ctx, ctor, 1, (JSValueConst *)&res, 0);
JS_FreeValue(ctx, res);
- JS_FreeValue(ctx, resolving_funcs[0]);
- JS_FreeValue(ctx, resolving_funcs[1]);
- if (JS_IsException(ret)) {
- JS_FreeValue(ctx, promise);
- return ret;
- }
- JS_FreeValue(ctx, ret);
+ if (JS_IsException(promise))
+ return promise;
if (magic == 0) {
then_func = JS_NewCFunctionData(ctx, js_promise_finally_value_thunk, 0,
0, 1, argv);
@@ -47503,7 +47716,7 @@ static JSValue JS_SetThisTimeValue(JSContext *ctx, JSValueConst this_val, double
JSObject *p = JS_VALUE_GET_OBJ(this_val);
if (p->class_id == JS_CLASS_DATE) {
JS_FreeValue(ctx, p->u.object_data);
- p->u.object_data = __JS_NewFloat64(ctx, v);
+ p->u.object_data = JS_NewFloat64(ctx, v);
return JS_DupValue(ctx, p->u.object_data);
}
}
@@ -47547,7 +47760,7 @@ static char const month_names[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
static char const day_names[] = "SunMonTueWedThuFriSat";
static __exception int get_date_fields(JSContext *ctx, JSValueConst obj,
- int64_t fields[9], int is_local, int force)
+ double fields[9], int is_local, int force)
{
double dval;
int64_t d, days, wd, y, i, md, h, m, s, ms, tz = 0;
@@ -47606,12 +47819,18 @@ static double time_clip(double t) {
return NAN;
}
-static double set_date_fields(int64_t fields[], int is_local) {
- int64_t days, y, m, md, h, d, i;
-
- i = fields[1];
- m = math_mod(i, 12);
- y = fields[0] + (i - m) / 12;
+/* The spec mandates the use of 'double' and it fixes the order
+ of the operations */
+static double set_date_fields(double fields[], int is_local) {
+ int64_t y;
+ double days, d, h, m1;
+ int i, m, md;
+
+ m1 = fields[1];
+ m = fmod(m1, 12);
+ if (m < 0)
+ m += 12;
+ y = (int64_t)(fields[0] + floor(m1 / 12));
days = days_from_year(y);
for(i = 0; i < m; i++) {
@@ -47621,7 +47840,8 @@ static double set_date_fields(int64_t fields[], int is_local) {
days += md;
}
days += fields[2] - 1;
- h = ((fields[3] * 60 + fields[4]) * 60 + fields[5]) * 1000 + fields[6];
+ h = fields[3] * 3600000 + fields[4] * 60000 +
+ fields[5] * 1000 + fields[6];
d = days * 86400000 + h;
if (is_local)
d += getTimezoneOffset(d) * 60000;
@@ -47632,7 +47852,7 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
// get_date_field(obj, n, is_local)
- int64_t fields[9];
+ double fields[9];
int res, n, is_local;
is_local = magic & 0x0F;
@@ -47646,14 +47866,14 @@ static JSValue get_date_field(JSContext *ctx, JSValueConst this_val,
if (magic & 0x100) { // getYear
fields[0] -= 1900;
}
- return JS_NewInt64(ctx, fields[n]);
+ return JS_NewFloat64(ctx, fields[n]);
}
static JSValue set_date_field(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv, int magic)
{
// _field(obj, first_field, end_field, args, is_local)
- int64_t fields[9];
+ double fields[9];
int res, first_field, end_field, is_local, i, n;
double d, a;
@@ -47695,7 +47915,7 @@ static JSValue get_date_string(JSContext *ctx, JSValueConst this_val,
{
// _string(obj, fmt, part)
char buf[64];
- int64_t fields[9];
+ double fields[9];
int res, fmt, part, pos;
int y, mon, d, h, m, s, ms, wd, tz;
@@ -47843,7 +48063,7 @@ static JSValue js_date_constructor(JSContext *ctx, JSValueConst new_target,
}
val = time_clip(val);
} else {
- int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 };
+ double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
if (n > 7)
n = 7;
for(i = 0; i < n; i++) {
@@ -47862,12 +48082,12 @@ has_val:
JSValueConst args[3];
args[0] = new_target;
args[1] = ctx->class_proto[JS_CLASS_DATE];
- args[2] = __JS_NewFloat64(ctx, val);
+ args[2] = JS_NewFloat64(ctx, val);
rv = js___date_create(ctx, JS_UNDEFINED, 3, args);
#else
rv = js_create_from_ctor(ctx, new_target, JS_CLASS_DATE);
if (!JS_IsException(rv))
- JS_SetObjectData(ctx, rv, __JS_NewFloat64(ctx, val));
+ JS_SetObjectData(ctx, rv, JS_NewFloat64(ctx, val));
#endif
if (!JS_IsException(rv) && JS_IsUndefined(new_target)) {
/* invoked as a function, return (new Date()).toString(); */
@@ -47883,7 +48103,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
// UTC(y, mon, d, h, m, s, ms)
- int64_t fields[] = { 0, 0, 1, 0, 0, 0, 0 };
+ double fields[] = { 0, 0, 1, 0, 0, 0, 0 };
int i, n;
double a;
@@ -47901,7 +48121,7 @@ static JSValue js_Date_UTC(JSContext *ctx, JSValueConst this_val,
if (i == 0 && fields[0] >= 0 && fields[0] < 100)
fields[0] += 1900;
}
- return __JS_NewFloat64(ctx, set_date_fields(fields, 0));
+ return JS_NewFloat64(ctx, set_date_fields(fields, 0));
}
static void string_skip_spaces(JSString *sp, int *pp) {
@@ -48011,6 +48231,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
// parse(s)
JSValue s, rv;
int64_t fields[] = { 0, 1, 1, 0, 0, 0, 0 };
+ double fields1[7];
int64_t tz, hh, mm;
double d;
int p, i, c, sgn;
@@ -48123,8 +48344,10 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
}
}
}
- d = set_date_fields(fields, is_local) - tz * 60000;
- rv = __JS_NewFloat64(ctx, d);
+ for(i = 0; i < 7; i++)
+ fields1[i] = fields[i];
+ d = set_date_fields(fields1, is_local) - tz * 60000;
+ rv = JS_NewFloat64(ctx, d);
done:
JS_FreeValue(ctx, s);
@@ -48194,7 +48417,7 @@ static JSValue js_date_getTime(JSContext *ctx, JSValueConst this_val,
if (JS_ThisTimeValue(ctx, &v, this_val))
return JS_EXCEPTION;
- return __JS_NewFloat64(ctx, v);
+ return JS_NewFloat64(ctx, v);
}
static JSValue js_date_setTime(JSContext *ctx, JSValueConst this_val,
@@ -48223,7 +48446,7 @@ static JSValue js_date_setYear(JSContext *ctx, JSValueConst this_val,
if (y >= 0 && y < 100)
y += 1900;
}
- args[0] = __JS_NewFloat64(ctx, y);
+ args[0] = JS_NewFloat64(ctx, y);
return set_date_field(ctx, this_val, 1, args, 0x011);
}
@@ -48714,9 +48937,11 @@ static JSValue JS_ToBigIntCtorFree(JSContext *ctx, JSValue val)
}
static JSValue js_bigint_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
return JS_ToBigIntCtorFree(ctx, JS_DupValue(ctx, argv[0]));
}
@@ -48962,7 +49187,7 @@ static const JSCFunctionListEntry js_bigint_proto_funcs[] = {
void JS_AddIntrinsicBigInt(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
+ JSValueConst obj1;
rt->bigint_ops.to_string = js_bigint_to_string;
rt->bigint_ops.from_string = js_string_to_bigint;
@@ -48974,9 +49199,8 @@ void JS_AddIntrinsicBigInt(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_INT],
js_bigint_proto_funcs,
countof(js_bigint_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigint_constructor, "BigInt", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigInt",
- ctx->class_proto[JS_CLASS_BIG_INT]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigInt", js_bigint_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_INT]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigint_funcs,
countof(js_bigint_funcs));
}
@@ -49194,10 +49418,12 @@ static const JSCFunctionListEntry js_bigfloat_proto_funcs[] = {
};
static JSValue js_bigfloat_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val;
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
if (argc == 0) {
bf_t *r;
val = JS_NewBigFloat(ctx);
@@ -49858,8 +50084,7 @@ static const JSCFunctionListEntry js_float_env_proto_funcs[] = {
void JS_AddIntrinsicBigFloat(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
- JSValueConst obj2;
+ JSValueConst obj1;
rt->bigfloat_ops.to_string = js_bigfloat_to_string;
rt->bigfloat_ops.from_string = js_string_to_bigfloat;
@@ -49873,9 +50098,8 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_FLOAT],
js_bigfloat_proto_funcs,
countof(js_bigfloat_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigfloat_constructor, "BigFloat", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigFloat",
- ctx->class_proto[JS_CLASS_BIG_FLOAT]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigFloat", js_bigfloat_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_FLOAT]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigfloat_funcs,
countof(js_bigfloat_funcs));
@@ -49883,10 +50107,10 @@ void JS_AddIntrinsicBigFloat(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_FLOAT_ENV],
js_float_env_proto_funcs,
countof(js_float_env_proto_funcs));
- obj2 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
+ obj1 = JS_NewGlobalCConstructorOnly(ctx, "BigFloatEnv",
js_float_env_constructor, 1,
ctx->class_proto[JS_CLASS_FLOAT_ENV]);
- JS_SetPropertyFunctionList(ctx, obj2, js_float_env_funcs,
+ JS_SetPropertyFunctionList(ctx, obj1, js_float_env_funcs,
countof(js_float_env_funcs));
}
@@ -49989,10 +50213,12 @@ static JSValue JS_ToBigDecimalFree(JSContext *ctx, JSValue val,
}
static JSValue js_bigdecimal_constructor(JSContext *ctx,
- JSValueConst this_val,
+ JSValueConst new_target,
int argc, JSValueConst *argv)
{
JSValue val;
+ if (!JS_IsUndefined(new_target))
+ return JS_ThrowTypeError(ctx, "not a constructor");
if (argc == 0) {
bfdec_t *r;
val = JS_NewBigDecimal(ctx);
@@ -50348,7 +50574,7 @@ static const JSCFunctionListEntry js_bigdecimal_funcs[] = {
void JS_AddIntrinsicBigDecimal(JSContext *ctx)
{
JSRuntime *rt = ctx->rt;
- JSValue obj1;
+ JSValueConst obj1;
rt->bigdecimal_ops.to_string = js_bigdecimal_to_string;
rt->bigdecimal_ops.from_string = js_string_to_bigdecimal;
@@ -50360,9 +50586,9 @@ void JS_AddIntrinsicBigDecimal(JSContext *ctx)
JS_SetPropertyFunctionList(ctx, ctx->class_proto[JS_CLASS_BIG_DECIMAL],
js_bigdecimal_proto_funcs,
countof(js_bigdecimal_proto_funcs));
- obj1 = JS_NewCFunction(ctx, js_bigdecimal_constructor, "BigDecimal", 1);
- JS_NewGlobalCConstructor2(ctx, obj1, "BigDecimal",
- ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
+ obj1 = JS_NewGlobalCConstructor(ctx, "BigDecimal",
+ js_bigdecimal_constructor, 1,
+ ctx->class_proto[JS_CLASS_BIG_DECIMAL]);
JS_SetPropertyFunctionList(ctx, obj1, js_bigdecimal_funcs,
countof(js_bigdecimal_funcs));
}
@@ -50818,8 +51044,7 @@ static JSValue js_array_buffer_get_byteLength(JSContext *ctx,
JSArrayBuffer *abuf = JS_GetOpaque2(ctx, this_val, class_id);
if (!abuf)
return JS_EXCEPTION;
- if (abuf->detached)
- return JS_ThrowTypeErrorDetachedArrayBuffer(ctx);
+ /* return 0 if detached */
return JS_NewUint32(ctx, abuf->byte_length);
}