summaryrefslogtreecommitdiffstats
path: root/js/src/builtin
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/builtin')
-rw-r--r--js/src/builtin/Array.js50
-rw-r--r--js/src/builtin/Classes.js2
-rw-r--r--js/src/builtin/Intl.cpp102
-rw-r--r--js/src/builtin/Map.js27
-rw-r--r--js/src/builtin/ModuleObject.cpp4
-rw-r--r--js/src/builtin/Promise.cpp53
-rw-r--r--js/src/builtin/ReflectParse.cpp6
-rw-r--r--js/src/builtin/RegExp.cpp140
-rw-r--r--js/src/builtin/RegExp.js134
-rw-r--r--js/src/builtin/RegExpLocalReplaceOpt.h.js36
-rw-r--r--js/src/builtin/Set.js29
-rw-r--r--js/src/builtin/TestingFunctions.cpp2
-rw-r--r--js/src/builtin/TypedArray.js79
-rw-r--r--js/src/builtin/TypedObject.cpp2
-rw-r--r--js/src/builtin/Utilities.js12
-rw-r--r--js/src/builtin/WeakMap.js27
-rw-r--r--js/src/builtin/WeakSet.js29
17 files changed, 366 insertions, 368 deletions
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
index 54b47b72f..45f90a7b8 100644
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -784,7 +784,7 @@ function ArrayKeys() {
return CreateArrayIterator(this, ITEM_KIND_KEY);
}
-// ES6 draft rev31 (2015/01/15) 22.1.2.1 Array.from(source[, mapfn[, thisArg]]).
+// ES 2017 draft 0f10dba4ad18de92d47d421f378233a2eae8f077 22.1.2.1
function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
// Step 1.
var C = this;
@@ -795,44 +795,40 @@ function ArrayFrom(items, mapfn=undefined, thisArg=undefined) {
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, mapfn));
var T = thisArg;
- // Steps 4-5.
+ // Step 4.
var usingIterator = GetMethod(items, std_iterator);
- // Step 6.
+ // Step 5.
if (usingIterator !== undefined) {
- // Steps 6.a-c.
+ // Steps 5.a-c.
var A = IsConstructor(C) ? new C() : [];
- // Steps 6.d-e.
- var iterator = GetIterator(items, usingIterator);
-
- // Step 6.f.
+ // Step 5.d.
var k = 0;
- // Step 6.g.
- // These steps cannot be implemented using a for-of loop.
- // See <https://bugs.ecmascript.org/show_bug.cgi?id=2883>.
- while (true) {
- // Steps 6.g.i-iii.
- var next = callContentFunction(iterator.next, iterator);
- if (!IsObject(next))
- ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
-
- // Step 6.g.iv.
- if (next.done) {
- A.length = k;
- return A;
- }
-
- // Steps 6.g.v-vi.
- var nextValue = next.value;
+ // Step 5.c, 5.e.
+ var iteratorWrapper = { [std_iterator]() { return GetIterator(items, usingIterator); } };
+ for (var nextValue of allowContentIter(iteratorWrapper)) {
+ // Step 5.e.i.
+ // Disabled for performance reason. We won't hit this case on
+ // normal array, since _DefineDataProperty will throw before it.
+ // We could hit this when |A| is a proxy and it ignores
+ // |_DefineDataProperty|, but it happens only after too long loop.
+ /*
+ if (k >= 0x1fffffffffffff)
+ ThrowTypeError(JSMSG_TOO_LONG_ARRAY);
+ */
- // Steps 6.g.vii-viii.
+ // Steps 5.e.vi-vii.
var mappedValue = mapping ? callContentFunction(mapfn, thisArg, nextValue, k) : nextValue;
- // Steps 6.g.ix-xi.
+ // Steps 5.e.ii (reordered), 5.e.viii.
_DefineDataProperty(A, k++, mappedValue);
}
+
+ // Step 5.e.iv.
+ A.length = k;
+ return A;
}
// Step 7.
diff --git a/js/src/builtin/Classes.js b/js/src/builtin/Classes.js
index d0f20b5fd..24841d605 100644
--- a/js/src/builtin/Classes.js
+++ b/js/src/builtin/Classes.js
@@ -5,7 +5,7 @@
var DefaultDerivedClassConstructor =
class extends null {
constructor(...args) {
- super(...allowContentSpread(args));
+ super(...allowContentIter(args));
}
};
MakeDefaultConstructor(DefaultDerivedClassConstructor);
diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp
index 990a4acdb..3a20c487b 100644
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -765,42 +765,53 @@ static const JSFunctionSpec collator_methods[] = {
};
/**
- * Collator constructor.
- * Spec: ECMAScript Internationalization API Specification, 10.1
+ * 10.1.2 Intl.Collator([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
Collator(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when Collator is called because of
+ // backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 10.1.2.1 step 3
+ // ES Intl 1st ed., 10.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 10.1.2.1 step 4
+ // ES Intl 1st ed., 10.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 10.1.2.1 step 5
+ // ES Intl 1st ed., 10.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 10.1.2.1 step 3.a
+ // ES Intl 1st ed., 10.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 10.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
- if (!proto)
+ // Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateCollatorPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &CollatorClass, proto);
if (!obj)
return false;
@@ -808,15 +819,13 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
}
- // 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 10.1.2.1 step 6; 10.1.3.1 step 3
+ // Step 6.
if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
return false;
- // 10.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -833,6 +842,7 @@ js::intl_Collator(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
// be used with "new", but it still has to be treated as a constructor.
return Collator(cx, args, true);
@@ -1257,42 +1267,53 @@ static const JSFunctionSpec numberFormat_methods[] = {
};
/**
- * NumberFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 11.1
+ * 11.2.1 Intl.NumberFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when NumberFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 11.1.2.1 step 3
+ // ES Intl 1st ed., 11.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 11.1.2.1 step 4
+ // ES Intl 1st ed., 11.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 11.1.2.1 step 5
+ // ES Intl 1st ed., 11.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 11.1.2.1 step 3.a
+ // ES Intl 1st ed., 11.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 11.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateNumberFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto);
if (!obj)
return false;
@@ -1300,15 +1321,13 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 11.1.2.1 step 6; 11.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
return false;
- // 11.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1325,6 +1344,7 @@ js::intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_NumberFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
@@ -1725,42 +1745,53 @@ static const JSFunctionSpec dateTimeFormat_methods[] = {
};
/**
- * DateTimeFormat constructor.
- * Spec: ECMAScript Internationalization API Specification, 12.1
+ * 12.2.1 Intl.DateTimeFormat([ locales [, options]])
+ *
+ * ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
*/
static bool
DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
{
RootedObject obj(cx);
+ // We're following ECMA-402 1st Edition when DateTimeFormat is called
+ // because of backward compatibility issues.
+ // See https://github.com/tc39/ecma402/issues/57
if (!construct) {
- // 12.1.2.1 step 3
+ // ES Intl 1st ed., 12.1.2.1 step 3
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
if (!intl)
return false;
RootedValue self(cx, args.thisv());
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
- // 12.1.2.1 step 4
+ // ES Intl 1st ed., 12.1.2.1 step 4
obj = ToObject(cx, self);
if (!obj)
return false;
- // 12.1.2.1 step 5
+ // ES Intl 1st ed., 12.1.2.1 step 5
bool extensible;
if (!IsExtensible(cx, obj, &extensible))
return false;
if (!extensible)
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
} else {
- // 12.1.2.1 step 3.a
+ // ES Intl 1st ed., 12.1.2.1 step 3.a
construct = true;
}
}
if (construct) {
- // 12.1.3.1 paragraph 2
- RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
- if (!proto)
+ // Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
+ RootedObject proto(cx);
+ if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
+
+ if (!proto) {
+ proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx);
+ if (!proto)
+ return false;
+ }
+
obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto);
if (!obj)
return false;
@@ -1768,15 +1799,13 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
obj->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
}
- // 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
- // 12.1.2.1 step 6; 12.1.3.1 step 3
+ // Step 3.
if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
return false;
- // 12.1.2.1 steps 3.a and 7
args.rval().setObject(*obj);
return true;
}
@@ -1793,6 +1822,7 @@ js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
+ MOZ_ASSERT(!args.isConstructing());
// intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
// cannot be used with "new", but it still has to be treated as a
// constructor.
diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js
index 432364614..580629a13 100644
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -14,31 +14,8 @@ function MapConstructorInit(iterable) {
if (!IsCallable(adder))
ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
- // Step 6.c.
- var iterFn = iterable[std_iterator];
- if (!IsCallable(iterFn))
- ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, iterable));
-
- var iter = callContentFunction(iterFn, iterable);
- if (!IsObject(iter))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof iter);
-
- // Step 7 (not applicable).
-
- // Step 8.
- while (true) {
- // Step 8.a.
- var next = callContentFunction(iter.next, iter);
- if (!IsObject(next))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof next);
-
- // Step 8.b.
- if (next.done)
- return;
-
- // Step 8.c.
- var nextItem = next.value;
-
+ // Steps 6.c-8.
+ for (var nextItem of allowContentIter(iterable)) {
// Step 8.d.
if (!IsObject(nextItem))
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "Map");
diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp
index 3bfc8f60b..710c7a76c 100644
--- a/js/src/builtin/ModuleObject.cpp
+++ b/js/src/builtin/ModuleObject.cpp
@@ -1159,7 +1159,7 @@ bool
ModuleBuilder::processExport(frontend::ParseNode* pn)
{
MOZ_ASSERT(pn->isKind(PNK_EXPORT) || pn->isKind(PNK_EXPORT_DEFAULT));
- MOZ_ASSERT(pn->getArity() == pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY);
+ MOZ_ASSERT(pn->getArity() == (pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY));
bool isDefault = pn->getKind() == PNK_EXPORT_DEFAULT;
ParseNode* kid = isDefault ? pn->pn_left : pn->pn_kid;
@@ -1205,7 +1205,7 @@ ModuleBuilder::processExport(frontend::ParseNode* pn)
case PNK_FUNCTION: {
RootedFunction func(cx_, kid->pn_funbox->function());
if (!func->isArrow()) {
- RootedAtom localName(cx_, func->name());
+ RootedAtom localName(cx_, func->explicitName());
RootedAtom exportName(cx_, isDefault ? cx_->names().default_ : localName.get());
MOZ_ASSERT_IF(isDefault, localName);
if (!appendExportEntry(exportName, localName))
diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp
index 59c97e529..c781a336d 100644
--- a/js/src/builtin/Promise.cpp
+++ b/js/src/builtin/Promise.cpp
@@ -1369,7 +1369,8 @@ PromiseObject::create(JSContext* cx, HandleObject executor, HandleObject proto /
static MOZ_MUST_USE bool PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator,
HandleObject C, HandleObject promiseObj,
- HandleObject resolve, HandleObject reject);
+ HandleObject resolve, HandleObject reject,
+ bool* done);
// ES2016, 25.4.4.1.
static bool
@@ -1410,12 +1411,14 @@ Promise_static_all(JSContext* cx, unsigned argc, Value* vp)
// Step 6 (implicit).
// Step 7.
- bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject);
+ bool done;
+ bool result = PerformPromiseAll(cx, iter, C, resultPromise, resolve, reject, &done);
// Step 8.
if (!result) {
// Step 8.a.
- // TODO: implement iterator closing.
+ if (!done)
+ iter.closeThrow();
// Step 8.b.
return AbruptRejectPromise(cx, args, resultPromise, reject);
@@ -1598,8 +1601,11 @@ RunResolutionFunction(JSContext *cx, HandleObject resolutionFun, HandleValue res
// ES2016, 25.4.4.1.1.
static MOZ_MUST_USE bool
PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
- HandleObject promiseObj, HandleObject resolve, HandleObject reject)
+ HandleObject promiseObj, HandleObject resolve, HandleObject reject,
+ bool* done)
{
+ *done = false;
+
RootedObject unwrappedPromiseObj(cx);
if (IsWrapper(promiseObj)) {
unwrappedPromiseObj = CheckedUnwrap(promiseObj);
@@ -1666,14 +1672,19 @@ PerformPromiseAll(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
RootedValue rejectFunVal(cx, ObjectOrNullValue(reject));
while (true) {
- bool done;
- // Steps a, b, c, e, f, g.
- if (!iterator.next(&nextValue, &done))
+ // Steps a-c, e-g.
+ if (!iterator.next(&nextValue, done)) {
+ // Steps b, f.
+ *done = true;
+
+ // Steps c, g.
return false;
+ }
// Step d.
- if (done) {
+ if (*done) {
// Step d.i (implicit).
+
// Step d.ii.
int32_t remainingCount = dataHolder->decreaseRemainingCount();
@@ -1822,7 +1833,8 @@ PromiseAllResolveElementFunction(JSContext* cx, unsigned argc, Value* vp)
static MOZ_MUST_USE bool PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator,
HandleObject C, HandleObject promiseObj,
- HandleObject resolve, HandleObject reject);
+ HandleObject resolve, HandleObject reject,
+ bool* done);
// ES2016, 25.4.4.3.
static bool
@@ -1863,12 +1875,14 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
// Step 6 (implicit).
// Step 7.
- bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject);
+ bool done;
+ bool result = PerformPromiseRace(cx, iter, C, resultPromise, resolve, reject, &done);
// Step 8.
if (!result) {
// Step 8.a.
- // TODO: implement iterator closing.
+ if (!done)
+ iter.closeThrow();
// Step 8.b.
return AbruptRejectPromise(cx, args, resultPromise, reject);
@@ -1882,25 +1896,30 @@ Promise_static_race(JSContext* cx, unsigned argc, Value* vp)
// ES2016, 25.4.4.3.1.
static MOZ_MUST_USE bool
PerformPromiseRace(JSContext *cx, JS::ForOfIterator& iterator, HandleObject C,
- HandleObject promiseObj, HandleObject resolve, HandleObject reject)
+ HandleObject promiseObj, HandleObject resolve, HandleObject reject,
+ bool* done)
{
+ *done = false;
MOZ_ASSERT(C->isConstructor());
RootedValue CVal(cx, ObjectValue(*C));
RootedValue nextValue(cx);
RootedValue resolveFunVal(cx, ObjectOrNullValue(resolve));
RootedValue rejectFunVal(cx, ObjectOrNullValue(reject));
- bool done;
while (true) {
// Steps a-c, e-g.
- if (!iterator.next(&nextValue, &done))
+ if (!iterator.next(&nextValue, done)) {
+ // Steps b, f.
+ *done = true;
+
+ // Steps c, g.
return false;
+ }
// Step d.
- if (done) {
- // Step d.i.
- // TODO: implement iterator closing.
+ if (*done) {
+ // Step d.i (implicit).
// Step d.ii.
return true;
diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
index 748ff7351..beff58e13 100644
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -2140,7 +2140,7 @@ ASTSerializer::exportDeclaration(ParseNode* pn, MutableHandleValue dst)
MOZ_ASSERT(pn->isKind(PNK_EXPORT) ||
pn->isKind(PNK_EXPORT_FROM) ||
pn->isKind(PNK_EXPORT_DEFAULT));
- MOZ_ASSERT(pn->getArity() == pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY);
+ MOZ_ASSERT(pn->getArity() == (pn->isKind(PNK_EXPORT) ? PN_UNARY : PN_BINARY));
MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_right->isKind(PNK_STRING));
RootedValue decl(cx, NullValue());
@@ -3415,7 +3415,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
#endif
RootedValue id(cx);
- RootedAtom funcAtom(cx, func->name());
+ RootedAtom funcAtom(cx, func->explicitName());
if (!optIdentifier(funcAtom, nullptr, &id))
return false;
@@ -3423,7 +3423,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
NodeVector defaults(cx);
RootedValue body(cx), rest(cx);
- if (func->hasRest())
+ if (pn->pn_funbox->hasRest())
rest.setUndefined();
else
rest.setNull();
diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp
index 80a4bb5bd..b20f41c53 100644
--- a/js/src/builtin/RegExp.cpp
+++ b/js/src/builtin/RegExp.cpp
@@ -577,14 +577,29 @@ js::regexp_clone(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-/* ES6 draft rev32 21.2.5.4. */
+MOZ_ALWAYS_INLINE bool
+IsRegExpInstanceOrPrototype(HandleValue v)
+{
+ if (!v.isObject())
+ return false;
+
+ return StandardProtoKeyOrNull(&v.toObject()) == JSProto_RegExp;
+}
+
+// ES 2017 draft 21.2.5.4.
MOZ_ALWAYS_INLINE bool
regexp_global_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
- /* Steps 4-6. */
+ // Step 3.a.
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Steps 4-6.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
args.rval().setBoolean(reObj->global());
return true;
}
@@ -592,19 +607,25 @@ regexp_global_impl(JSContext* cx, const CallArgs& args)
bool
js::regexp_global(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-3. */
+ // Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_global_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_global_impl>(cx, args);
}
-/* ES6 draft rev32 21.2.5.5. */
+// ES 2017 draft 21.2.5.5.
MOZ_ALWAYS_INLINE bool
regexp_ignoreCase_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
- /* Steps 4-6. */
+ // Step 3.a
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Steps 4-6.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
args.rval().setBoolean(reObj->ignoreCase());
return true;
}
@@ -612,19 +633,25 @@ regexp_ignoreCase_impl(JSContext* cx, const CallArgs& args)
bool
js::regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-3. */
+ // Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_ignoreCase_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_ignoreCase_impl>(cx, args);
}
-/* ES6 draft rev32 21.2.5.7. */
+// ES 2017 draft 21.2.5.7.
MOZ_ALWAYS_INLINE bool
regexp_multiline_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
- /* Steps 4-6. */
+ // Step 3.a.
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Steps 4-6.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
args.rval().setBoolean(reObj->multiline());
return true;
}
@@ -632,24 +659,30 @@ regexp_multiline_impl(JSContext* cx, const CallArgs& args)
bool
js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-3. */
+ // Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_multiline_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_multiline_impl>(cx, args);
}
-/* ES6 draft rev32 21.2.5.10. */
+// ES 2017 draft rev32 21.2.5.10.
MOZ_ALWAYS_INLINE bool
regexp_source_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+ // Step 3.a.
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setString(cx->names().emptyRegExp);
+ return true;
+ }
- /* Step 5. */
+ // Step 5.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
RootedAtom src(cx, reObj->getSource());
if (!src)
return false;
- /* Step 7. */
+ // Step 7.
RootedString str(cx, EscapeRegExpPattern(cx, src));
if (!str)
return false;
@@ -661,19 +694,25 @@ regexp_source_impl(JSContext* cx, const CallArgs& args)
static bool
regexp_source(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-4. */
+ // Steps 1-4.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_source_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_source_impl>(cx, args);
}
-/* ES6 draft rev32 21.2.5.12. */
+// ES 2017 draft 21.2.5.12.
MOZ_ALWAYS_INLINE bool
regexp_sticky_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
- /* Steps 4-6. */
+ // Step 3.a.
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Steps 4-6.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
args.rval().setBoolean(reObj->sticky());
return true;
}
@@ -681,27 +720,35 @@ regexp_sticky_impl(JSContext* cx, const CallArgs& args)
bool
js::regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-3. */
+ // Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_sticky_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_sticky_impl>(cx, args);
}
-/* ES6 21.2.5.15. */
+// ES 2017 draft 21.2.5.15.
MOZ_ALWAYS_INLINE bool
regexp_unicode_impl(JSContext* cx, const CallArgs& args)
{
- MOZ_ASSERT(IsRegExpObject(args.thisv()));
- /* Steps 4-6. */
- args.rval().setBoolean(args.thisv().toObject().as<RegExpObject>().unicode());
+ MOZ_ASSERT(IsRegExpInstanceOrPrototype(args.thisv()));
+
+ // Step 3.a.
+ if (!IsRegExpObject(args.thisv())) {
+ args.rval().setUndefined();
+ return true;
+ }
+
+ // Steps 4-6.
+ Rooted<RegExpObject*> reObj(cx, &args.thisv().toObject().as<RegExpObject>());
+ args.rval().setBoolean(reObj->unicode());
return true;
}
bool
js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp)
{
- /* Steps 1-3. */
+ // Steps 1-3.
CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsRegExpObject, regexp_unicode_impl>(cx, args);
+ return CallNonGenericMethod<IsRegExpInstanceOrPrototype, regexp_unicode_impl>(cx, args);
}
const JSPropertySpec js::regexp_properties[] = {
@@ -829,25 +876,6 @@ const JSPropertySpec js::regexp_static_props[] = {
JS_PS_END
};
-JSObject*
-js::CreateRegExpPrototype(JSContext* cx, JSProtoKey key)
-{
- MOZ_ASSERT(key == JSProto_RegExp);
-
- Rooted<RegExpObject*> proto(cx, cx->global()->createBlankPrototype<RegExpObject>(cx));
- if (!proto)
- return nullptr;
- proto->NativeObject::setPrivate(nullptr);
-
- if (!RegExpObject::assignInitialShape(cx, proto))
- return nullptr;
-
- RootedAtom source(cx, cx->names().empty);
- proto->initAndZeroLastIndex(source, RegExpFlag(0), cx);
-
- return proto;
-}
-
template <typename CharT>
static bool
IsTrailSurrogateWithLeadSurrogateImpl(JSContext* cx, HandleLinearString input, size_t index)
diff --git a/js/src/builtin/RegExp.js b/js/src/builtin/RegExp.js
index 1ffea0105..0b849292c 100644
--- a/js/src/builtin/RegExp.js
+++ b/js/src/builtin/RegExp.js
@@ -122,8 +122,7 @@ function RegExpMatch(string) {
}
// Step 5.
- var sticky = !!(flags & REGEXP_STICKY_FLAG);
- return RegExpLocalMatchOpt(rx, S, sticky);
+ return RegExpBuiltinExec(rx, S, false);
}
// Stes 4-6
@@ -220,37 +219,6 @@ function RegExpGlobalMatchOpt(rx, S, fullUnicode) {
}
}
-// ES 2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e 21.2.5.6 step 5.
-// Optimized path for @@match without global flag.
-function RegExpLocalMatchOpt(rx, S, sticky) {
- // Step 4.
- var lastIndex = ToLength(rx.lastIndex);
-
- // Step 8.
- if (!sticky) {
- lastIndex = 0;
- } else {
- if (lastIndex > S.length) {
- // Steps 12.a.i-ii, 12.c.i.1-2.
- rx.lastIndex = 0;
- return null;
- }
- }
-
- // Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
- var result = RegExpMatcher(rx, S, lastIndex);
- if (result === null) {
- // Steps 12.a.i-ii, 12.c.i.1-2.
- rx.lastIndex = 0;
- } else {
- // Step 15.
- if (sticky)
- rx.lastIndex = result.index + result[0].length;
- }
-
- return result;
-}
-
// Checks if following properties and getters are not modified, and accessing
// them not observed by content script:
// * flags
@@ -318,9 +286,10 @@ function RegExpReplace(string, replaceValue) {
if (functionalReplace) {
var elemBase = GetElemBaseForLambda(replaceValue);
- if (IsObject(elemBase))
+ if (IsObject(elemBase)) {
return RegExpGlobalReplaceOptElemBase(rx, S, lengthS, replaceValue,
fullUnicode, elemBase);
+ }
return RegExpGlobalReplaceOptFunc(rx, S, lengthS, replaceValue,
fullUnicode);
}
@@ -336,18 +305,11 @@ function RegExpReplace(string, replaceValue) {
fullUnicode);
}
- var sticky = !!(flags & REGEXP_STICKY_FLAG);
-
- if (functionalReplace) {
- return RegExpLocalReplaceOptFunc(rx, S, lengthS, replaceValue,
- sticky);
- }
- if (firstDollarIndex !== -1) {
- return RegExpLocalReplaceOptSubst(rx, S, lengthS, replaceValue,
- sticky, firstDollarIndex);
- }
- return RegExpLocalReplaceOpt(rx, S, lengthS, replaceValue,
- sticky);
+ if (functionalReplace)
+ return RegExpLocalReplaceOptFunc(rx, S, lengthS, replaceValue);
+ if (firstDollarIndex !== -1)
+ return RegExpLocalReplaceOptSubst(rx, S, lengthS, replaceValue, firstDollarIndex);
+ return RegExpLocalReplaceOpt(rx, S, lengthS, replaceValue);
}
// Steps 8-16.
@@ -647,7 +609,8 @@ function RegExpGlobalReplaceShortOpt(rx, S, lengthS, replaceValue, fullUnicode)
#undef SUBSTITUTION
#undef FUNC_NAME
-// ES 2017 draft 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e 21.2.5.9.
+// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210
+// 21.2.5.9 RegExp.prototype [ @@search ] ( string )
function RegExpSearch(string) {
// Step 1.
var rx = this;
@@ -659,41 +622,69 @@ function RegExpSearch(string) {
// Step 3.
var S = ToString(string);
+ // Step 4.
+ var previousLastIndex = rx.lastIndex;
+
+ // Step 5.
+ var lastIndexIsZero = SameValue(previousLastIndex, 0);
+ if (!lastIndexIsZero)
+ rx.lastIndex = 0;
+
if (IsRegExpMethodOptimizable(rx) && S.length < 0x7fff) {
// Step 6.
var result = RegExpSearcher(rx, S, 0);
- // Step 8.
+ // We need to consider two cases:
+ //
+ // 1. Neither global nor sticky is set:
+ // RegExpBuiltinExec doesn't modify lastIndex for local RegExps, that
+ // means |SameValue(rx.lastIndex, 0)| is true after calling exec. The
+ // comparison in steps 7-8 |SameValue(rx.lastIndex, previousLastIndex)|
+ // is therefore equal to the already computed |lastIndexIsZero| value.
+ //
+ // 2. Global or sticky flag is set.
+ // RegExpBuiltinExec will always update lastIndex and we need to
+ // restore the property to its original value.
+
+ // Steps 7-8.
+ if (!lastIndexIsZero) {
+ rx.lastIndex = previousLastIndex;
+ } else {
+ var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
+ if (flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG))
+ rx.lastIndex = previousLastIndex;
+ }
+
+ // Step 9.
if (result === -1)
return -1;
- // Step 9.
+ // Step 10.
return result & 0x7fff;
}
- return RegExpSearchSlowPath(rx, S);
+ return RegExpSearchSlowPath(rx, S, previousLastIndex);
}
-// ES 2017 draft 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e 21.2.5.9
-// steps 4-9.
-function RegExpSearchSlowPath(rx, S) {
- // Step 4.
- var previousLastIndex = rx.lastIndex;
-
- // Step 5.
- rx.lastIndex = 0;
-
+// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210
+// 21.2.5.9 RegExp.prototype [ @@search ] ( string )
+// Steps 6-10.
+function RegExpSearchSlowPath(rx, S, previousLastIndex) {
// Step 6.
var result = RegExpExec(rx, S, false);
// Step 7.
- rx.lastIndex = previousLastIndex;
+ var currentLastIndex = rx.lastIndex;
// Step 8.
+ if (!SameValue(currentLastIndex, previousLastIndex))
+ rx.lastIndex = previousLastIndex;
+
+ // Step 9.
if (result === null)
return -1;
- // Step 9.
+ // Step 10.
return result.index;
}
@@ -942,15 +933,16 @@ function RegExpExec(R, S, forTest) {
return forTest ? result !== null : result;
}
-// ES 2017 draft rev 6a13789aa9e7c6de4e96b7d3e24d9e6eba6584ad 21.2.5.2.2.
+// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210
+// 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S )
function RegExpBuiltinExec(R, S, forTest) {
- // ES6 21.2.5.2.1 step 6.
+ // 21.2.5.2.1 Runtime Semantics: RegExpExec, step 5.
// This check is here for RegExpTest. RegExp_prototype_Exec does same
// thing already.
if (!IsRegExpObject(R))
return UnwrapAndCallRegExpBuiltinExec(R, S, forTest);
- // Steps 1-2 (skipped).
+ // Steps 1-3 (skipped).
// Step 4.
var lastIndex = ToLength(R.lastIndex);
@@ -965,9 +957,11 @@ function RegExpBuiltinExec(R, S, forTest) {
if (!globalOrSticky) {
lastIndex = 0;
} else {
+ // Step 12.a.
if (lastIndex > S.length) {
- // Steps 12.a.i-ii, 12.c.i.1-2.
- R.lastIndex = 0;
+ // Steps 12.a.i-ii.
+ if (globalOrSticky)
+ R.lastIndex = 0;
return forTest ? false : null;
}
}
@@ -977,7 +971,8 @@ function RegExpBuiltinExec(R, S, forTest) {
var endIndex = RegExpTester(R, S, lastIndex);
if (endIndex == -1) {
// Steps 12.a.i-ii, 12.c.i.1-2.
- R.lastIndex = 0;
+ if (globalOrSticky)
+ R.lastIndex = 0;
return false;
}
@@ -991,8 +986,9 @@ function RegExpBuiltinExec(R, S, forTest) {
// Steps 3, 9-25, except 12.a.i-ii, 12.c.i.1-2, 15.
var result = RegExpMatcher(R, S, lastIndex);
if (result === null) {
- // Steps 12.a.i-ii, 12.c.i.1-2.
- R.lastIndex = 0;
+ // Steps 12.a.i, 12.c.i.
+ if (globalOrSticky)
+ R.lastIndex = 0;
} else {
// Step 15.
if (globalOrSticky)
diff --git a/js/src/builtin/RegExpLocalReplaceOpt.h.js b/js/src/builtin/RegExpLocalReplaceOpt.h.js
index edc2e2056..1acd6a73a 100644
--- a/js/src/builtin/RegExpLocalReplaceOpt.h.js
+++ b/js/src/builtin/RegExpLocalReplaceOpt.h.js
@@ -11,24 +11,39 @@
// * FUNCTIONAL -- replaceValue is a function
// * neither of above -- replaceValue is a string without "$"
-// ES 2017 draft 03bfda119d060aca4099d2b77cf43f6d4f11cfa2 21.2.5.8
+// ES 2017 draft 6390c2f1b34b309895d31d8c0512eac8660a0210 21.2.5.8
// steps 11.a-16.
// Optimized path for @@replace with the following conditions:
// * global flag is false
-function FUNC_NAME(rx, S, lengthS, replaceValue, sticky
+function FUNC_NAME(rx, S, lengthS, replaceValue
#ifdef SUBSTITUTION
, firstDollarIndex
#endif
)
{
- var lastIndex;
- if (sticky) {
- lastIndex = ToLength(rx.lastIndex);
+ // 21.2.5.2.2 RegExpBuiltinExec, step 4.
+ var lastIndex = ToLength(rx.lastIndex);
+
+ // 21.2.5.2.2 RegExpBuiltinExec, step 5.
+ // Side-effects in step 4 can recompile the RegExp, so we need to read the
+ // flags again and handle the case when global was enabled even though this
+ // function is optimized for non-global RegExps.
+ var flags = UnsafeGetInt32FromReservedSlot(rx, REGEXP_FLAGS_SLOT);
+
+ // 21.2.5.2.2 RegExpBuiltinExec, steps 6-7.
+ var globalOrSticky = !!(flags & (REGEXP_GLOBAL_FLAG | REGEXP_STICKY_FLAG));
+
+ if (globalOrSticky) {
+ // 21.2.5.2.2 RegExpBuiltinExec, step 12.a.
if (lastIndex > lengthS) {
- rx.lastIndex = 0;
+ if (globalOrSticky)
+ rx.lastIndex = 0;
+
+ // Steps 12-16.
return S;
}
} else {
+ // 21.2.5.2.2 RegExpBuiltinExec, step 8.
lastIndex = 0;
}
@@ -37,7 +52,11 @@ function FUNC_NAME(rx, S, lengthS, replaceValue, sticky
// Step 11.b.
if (result === null) {
- rx.lastIndex = 0;
+ // 21.2.5.2.2 RegExpBuiltinExec, steps 12.a.i, 12.c.i.
+ if (globalOrSticky)
+ rx.lastIndex = 0;
+
+ // Steps 12-16.
return S;
}
@@ -61,7 +80,8 @@ function FUNC_NAME(rx, S, lengthS, replaceValue, sticky
// To set rx.lastIndex before RegExpGetComplexReplacement.
var nextSourcePosition = position + matchLength;
- if (sticky)
+ // 21.2.5.2.2 RegExpBuiltinExec, step 15.
+ if (globalOrSticky)
rx.lastIndex = nextSourcePosition;
var replacement;
diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js
index accc70120..9af6cf8d1 100644
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -14,34 +14,9 @@ function SetConstructorInit(iterable) {
if (!IsCallable(adder))
ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
- // Step 6.c.
- var iterFn = iterable[std_iterator];
- if (!IsCallable(iterFn))
- ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, iterable));
-
- var iter = callContentFunction(iterFn, iterable);
- if (!IsObject(iter))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof iter);
-
- // Step 7 (not applicable).
-
- // Step 8.
- while (true) {
- // Step 8.a.
- var next = callContentFunction(iter.next, iter);
- if (!IsObject(next))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof next);
-
- // Step 8.b.
- if (next.done)
- return;
-
- // Step 8.c.
- var nextValue = next.value;
-
- // Steps 8.d-e.
+ // Steps 6.c-8.
+ for (var nextValue of allowContentIter(iterable))
callContentFunction(adder, set, nextValue);
- }
}
/* ES6 20121122 draft 15.16.4.6. */
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index acf449b7e..a14f9ba69 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -881,7 +881,7 @@ HasChild(JSContext* cx, unsigned argc, Value* vp)
RootedValue parent(cx, args.get(0));
RootedValue child(cx, args.get(1));
- if (!parent.isMarkable() || !child.isMarkable()) {
+ if (!parent.isGCThing() || !child.isGCThing()) {
args.rval().setBoolean(false);
return true;
}
diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
index 4d2d6488f..a2205dc92 100644
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -35,6 +35,10 @@ function IsDetachedBuffer(buffer) {
return (flags & JS_ARRAYBUFFER_DETACHED_FLAG) !== 0;
}
+function TypedArrayLengthMethod() {
+ return TypedArrayLength(this);
+}
+
function GetAttachedArrayBuffer(tarray) {
var buffer = ViewedArrayBufferIfReified(tarray);
if (IsDetachedBuffer(buffer))
@@ -42,6 +46,10 @@ function GetAttachedArrayBuffer(tarray) {
return buffer;
}
+function GetAttachedArrayBufferMethod() {
+ return GetAttachedArrayBuffer(this);
+}
+
// A function which ensures that the argument is either a typed array or a
// cross-compartment wrapper for a typed array and that the typed array involved
// has an attached array buffer. If one of those conditions doesn't hold (wrong
@@ -54,10 +62,7 @@ function IsTypedArrayEnsuringArrayBuffer(arg) {
return true;
}
- // This is a bit hacky but gets the job done: the first `arg` is used to
- // test for a wrapped typed array, the second as an argument to
- // GetAttachedArrayBuffer.
- callFunction(CallTypedArrayMethodIfWrapped, arg, arg, "GetAttachedArrayBuffer");
+ callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod");
return false;
}
@@ -98,8 +103,8 @@ function TypedArrayCreateWithLength(constructor, length) {
if (isTypedArray) {
len = TypedArrayLength(newTypedArray);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray, newTypedArray,
- "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, newTypedArray,
+ "TypedArrayLengthMethod");
}
if (len < length)
@@ -259,15 +264,14 @@ function TypedArrayEvery(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -348,15 +352,14 @@ function TypedArrayFilter(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -410,15 +413,14 @@ function TypedArrayFind(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -452,15 +454,14 @@ function TypedArrayFindIndex(predicate/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -492,15 +493,14 @@ function TypedArrayForEach(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3-4.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 5.
if (arguments.length === 0)
@@ -686,15 +686,14 @@ function TypedArrayMap(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 3.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 4.
if (arguments.length === 0)
@@ -730,15 +729,14 @@ function TypedArrayReduce(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -776,15 +774,14 @@ function TypedArrayReduceRight(callbackfn/*, initialValue*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1034,15 +1031,14 @@ function TypedArraySome(callbackfn/*, thisArg*/) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(O);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Steps 3-5.
var len;
if (isTypedArray)
len = TypedArrayLength(O);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, O, O, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, O, "TypedArrayLengthMethod");
// Step 6.
if (arguments.length === 0)
@@ -1137,7 +1133,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, "GetAttachedArrayBufferMethod");
}
// Step 3.
@@ -1145,7 +1141,7 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
len = TypedArrayLength(obj);
} else {
- len = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, obj, "TypedArrayLengthMethod");
}
if (comparefn === undefined) {
@@ -1181,8 +1177,8 @@ function TypedArraySort(comparefn) {
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
- buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj,
- "GetAttachedArrayBuffer");
+ buffer = callFunction(CallTypedArrayMethodIfWrapped, obj,
+ "GetAttachedArrayBufferMethod");
}
}
var bufferDetached;
@@ -1217,15 +1213,14 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
// We want to make sure that we have an attached buffer, per spec prose.
var isTypedArray = IsTypedArrayEnsuringArrayBuffer(array);
- // If we got here, `this` is either a typed array or a cross-compartment
- // wrapper for one.
+ // If we got here, `this` is either a typed array or a wrapper for one.
// Step 2.
var len;
if (isTypedArray)
len = TypedArrayLength(array);
else
- len = callFunction(CallTypedArrayMethodIfWrapped, array, array, "TypedArrayLength");
+ len = callFunction(CallTypedArrayMethodIfWrapped, array, "TypedArrayLengthMethod");
// Step 4.
if (len === 0)
@@ -1433,7 +1428,7 @@ function TypedArrayStaticFrom(source, mapfn = undefined, thisArg = undefined) {
// 22.2.2.1.1 IterableToList, step 4.a.
var next = callContentFunction(iterator.next, iterator);
if (!IsObject(next))
- ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
+ ThrowTypeError(JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
// 22.2.2.1.1 IterableToList, step 4.b.
if (next.done)
@@ -1560,7 +1555,7 @@ function IterableToList(items, method) {
// Step 4.a.
var next = callContentFunction(iterator.next, iterator);
if (!IsObject(next))
- ThrowTypeError(JSMSG_NEXT_RETURNED_PRIMITIVE);
+ ThrowTypeError(JSMSG_ITER_METHOD_RETURNED_PRIMITIVE, "next");
// Step 4.b.
if (next.done)
diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp
index b7297c894..ae74f01bf 100644
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -230,7 +230,7 @@ const Class js::ScalarTypeDescr::class_ = {
const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = {
JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0),
- JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, JSFUN_HAS_REST),
+ JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, 0),
JS_SELF_HOSTED_FN("equivalent", "TypeDescrEquivalent", 1, 0),
JS_FS_END
};
diff --git a/js/src/builtin/Utilities.js b/js/src/builtin/Utilities.js
index bfb1fe7f4..c73bc5e7f 100644
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -106,7 +106,17 @@ function ToLength(v) {
return std_Math_min(v, 0x1fffffffffffff);
}
-/* Spec: ECMAScript Draft, 6th edition Oct 14, 2014, 7.2.4 */
+// ES2017 draft rev aebf014403a3e641fb1622aec47c40f051943527
+// 7.2.9 SameValue ( x, y )
+function SameValue(x, y) {
+ if (x === y) {
+ return (x !== 0) || (1 / x === 1 / y);
+ }
+ return (x !== x && y !== y);
+}
+
+// ES2017 draft rev aebf014403a3e641fb1622aec47c40f051943527
+// 7.2.10 SameValueZero ( x, y )
function SameValueZero(x, y) {
return x === y || (x !== x && y !== y);
}
diff --git a/js/src/builtin/WeakMap.js b/js/src/builtin/WeakMap.js
index 066a72bfe..6755b7a7b 100644
--- a/js/src/builtin/WeakMap.js
+++ b/js/src/builtin/WeakMap.js
@@ -14,31 +14,8 @@ function WeakMapConstructorInit(iterable) {
if (!IsCallable(adder))
ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
- // Step 6.c.
- var iterFn = iterable[std_iterator];
- if (!IsCallable(iterFn))
- ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, iterable));
-
- var iter = callContentFunction(iterFn, iterable);
- if (!IsObject(iter))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof iter);
-
- // Step 7 (not applicable).
-
- // Step 8.
- while (true) {
- // Step 8.a.
- var next = callContentFunction(iter.next, iter);
- if (!IsObject(next))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof next);
-
- // Step 8.b.
- if (next.done)
- return;
-
- // Step 8.c.
- var nextItem = next.value;
-
+ // Steps 6.c-8.
+ for (var nextItem of allowContentIter(iterable)) {
// Step 8.d.
if (!IsObject(nextItem))
ThrowTypeError(JSMSG_INVALID_MAP_ITERABLE, "WeakMap");
diff --git a/js/src/builtin/WeakSet.js b/js/src/builtin/WeakSet.js
index eb7c2378f..b16b4634d 100644
--- a/js/src/builtin/WeakSet.js
+++ b/js/src/builtin/WeakSet.js
@@ -14,34 +14,9 @@ function WeakSetConstructorInit(iterable) {
if (!IsCallable(adder))
ThrowTypeError(JSMSG_NOT_FUNCTION, typeof adder);
- // Step 6.c.
- var iterFn = iterable[std_iterator];
- if (!IsCallable(iterFn))
- ThrowTypeError(JSMSG_NOT_ITERABLE, DecompileArg(0, iterable));
-
- var iter = callContentFunction(iterFn, iterable);
- if (!IsObject(iter))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof iter);
-
- // Step 7 (not applicable).
-
- // Step 8.
- while (true) {
- // Step 8.a.
- var next = callContentFunction(iter.next, iter);
- if (!IsObject(next))
- ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, typeof next);
-
- // Step 8.b.
- if (next.done)
- return;
-
- // Step 8.c.
- var nextValue = next.value;
-
- // Steps 8.d-e.
+ // Steps 6.c-8.
+ for (var nextValue of allowContentIter(iterable))
callContentFunction(adder, set, nextValue);
- }
}
// 23.4.3.1