diff options
Diffstat (limited to 'js/src/builtin')
-rw-r--r-- | js/src/builtin/Array.js | 50 | ||||
-rw-r--r-- | js/src/builtin/Classes.js | 2 | ||||
-rw-r--r-- | js/src/builtin/Intl.cpp | 102 | ||||
-rw-r--r-- | js/src/builtin/Map.js | 27 | ||||
-rw-r--r-- | js/src/builtin/ModuleObject.cpp | 4 | ||||
-rw-r--r-- | js/src/builtin/Promise.cpp | 53 | ||||
-rw-r--r-- | js/src/builtin/ReflectParse.cpp | 6 | ||||
-rw-r--r-- | js/src/builtin/RegExp.cpp | 140 | ||||
-rw-r--r-- | js/src/builtin/RegExp.js | 134 | ||||
-rw-r--r-- | js/src/builtin/RegExpLocalReplaceOpt.h.js | 36 | ||||
-rw-r--r-- | js/src/builtin/Set.js | 29 | ||||
-rw-r--r-- | js/src/builtin/TestingFunctions.cpp | 2 | ||||
-rw-r--r-- | js/src/builtin/TypedArray.js | 79 | ||||
-rw-r--r-- | js/src/builtin/TypedObject.cpp | 2 | ||||
-rw-r--r-- | js/src/builtin/Utilities.js | 12 | ||||
-rw-r--r-- | js/src/builtin/WeakMap.js | 27 | ||||
-rw-r--r-- | js/src/builtin/WeakSet.js | 29 |
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 |