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.cpp483
-rw-r--r--js/src/builtin/Intl.h54
-rw-r--r--js/src/builtin/IntlTimeZoneData.h2
-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
19 files changed, 802 insertions, 369 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..cd808cb10 100644
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -102,6 +102,18 @@ Char16ToUChar(char16_t* chars)
MOZ_CRASH("Char16ToUChar: Intl API disabled");
}
+inline char16_t*
+UCharToChar16(UChar* chars)
+{
+ MOZ_CRASH("UCharToChar16: Intl API disabled");
+}
+
+inline const char16_t*
+UCharToChar16(const UChar* chars)
+{
+ MOZ_CRASH("UCharToChar16: Intl API disabled");
+}
+
static int32_t
u_strlen(const UChar* s)
{
@@ -356,6 +368,27 @@ enum UCalendarDateFields {
UCAL_DAY_OF_MONTH = UCAL_DATE
};
+enum UCalendarMonths {
+ UCAL_JANUARY,
+ UCAL_FEBRUARY,
+ UCAL_MARCH,
+ UCAL_APRIL,
+ UCAL_MAY,
+ UCAL_JUNE,
+ UCAL_JULY,
+ UCAL_AUGUST,
+ UCAL_SEPTEMBER,
+ UCAL_OCTOBER,
+ UCAL_NOVEMBER,
+ UCAL_DECEMBER,
+ UCAL_UNDECIMBER
+};
+
+enum UCalendarAMPMs {
+ UCAL_AM,
+ UCAL_PM
+};
+
static UCalendar*
ucal_open(const UChar* zoneID, int32_t len, const char* locale,
UCalendarType type, UErrorCode* status)
@@ -420,6 +453,13 @@ ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* statu
MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled");
}
+enum UDateTimePatternField {
+ UDATPG_YEAR_FIELD,
+ UDATPG_MONTH_FIELD,
+ UDATPG_WEEK_OF_YEAR_FIELD,
+ UDATPG_DAY_FIELD,
+};
+
typedef void* UDateTimePatternGenerator;
static UDateTimePatternGenerator*
@@ -436,6 +476,14 @@ udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton,
MOZ_CRASH("udatpg_getBestPattern: Intl API disabled");
}
+static const UChar *
+udatpg_getAppendItemName(const UDateTimePatternGenerator *dtpg,
+ UDateTimePatternField field,
+ int32_t *pLength)
+{
+ MOZ_CRASH("udatpg_getAppendItemName: Intl API disabled");
+}
+
static void
udatpg_close(UDateTimePatternGenerator* dtpg)
{
@@ -488,10 +536,46 @@ enum UDateFormatField {
};
enum UDateFormatStyle {
+ UDAT_FULL,
+ UDAT_LONG,
+ UDAT_MEDIUM,
+ UDAT_SHORT,
+ UDAT_DEFAULT = UDAT_MEDIUM,
UDAT_PATTERN = -2,
UDAT_IGNORE = UDAT_PATTERN
};
+enum UDateFormatSymbolType {
+ UDAT_ERAS,
+ UDAT_MONTHS,
+ UDAT_SHORT_MONTHS,
+ UDAT_WEEKDAYS,
+ UDAT_SHORT_WEEKDAYS,
+ UDAT_AM_PMS,
+ UDAT_LOCALIZED_CHARS,
+ UDAT_ERA_NAMES,
+ UDAT_NARROW_MONTHS,
+ UDAT_NARROW_WEEKDAYS,
+ UDAT_STANDALONE_MONTHS,
+ UDAT_STANDALONE_SHORT_MONTHS,
+ UDAT_STANDALONE_NARROW_MONTHS,
+ UDAT_STANDALONE_WEEKDAYS,
+ UDAT_STANDALONE_SHORT_WEEKDAYS,
+ UDAT_STANDALONE_NARROW_WEEKDAYS,
+ UDAT_QUARTERS,
+ UDAT_SHORT_QUARTERS,
+ UDAT_STANDALONE_QUARTERS,
+ UDAT_STANDALONE_SHORT_QUARTERS,
+ UDAT_SHORTER_WEEKDAYS,
+ UDAT_STANDALONE_SHORTER_WEEKDAYS,
+ UDAT_CYCLIC_YEARS_WIDE,
+ UDAT_CYCLIC_YEARS_ABBREVIATED,
+ UDAT_CYCLIC_YEARS_NARROW,
+ UDAT_ZODIAC_NAMES_WIDE,
+ UDAT_ZODIAC_NAMES_ABBREVIATED,
+ UDAT_ZODIAC_NAMES_NARROW
+};
+
static int32_t
udat_countAvailable()
{
@@ -563,6 +647,13 @@ udat_close(UDateFormat* format)
MOZ_CRASH("udat_close: Intl API disabled");
}
+static int32_t
+udat_getSymbols(const UDateFormat *fmt, UDateFormatSymbolType type, int32_t symbolIndex,
+ UChar *result, int32_t resultLength, UErrorCode *status)
+{
+ MOZ_CRASH("udat_getSymbols: Intl API disabled");
+}
+
#endif
@@ -765,42 +856,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 +910,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 +933,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 +1358,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 +1412,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 +1435,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 +1836,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 +1890,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 +1913,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.
@@ -2891,6 +3012,296 @@ js::intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+template<size_t N>
+inline bool
+MatchPart(const char** pattern, const char (&part)[N])
+{
+ if (strncmp(*pattern, part, N - 1))
+ return false;
+
+ *pattern += N - 1;
+ return true;
+}
+
+bool
+js::intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 3);
+ // 1. Assert: locale is a string.
+ MOZ_ASSERT(args[0].isString());
+ // 2. Assert: style is a string.
+ MOZ_ASSERT(args[1].isString());
+ // 3. Assert: keys is an Array.
+ MOZ_ASSERT(args[2].isObject());
+
+ JSAutoByteString locale(cx, args[0].toString());
+ if (!locale)
+ return false;
+
+ JSAutoByteString style(cx, args[1].toString());
+ if (!style)
+ return false;
+
+ RootedArrayObject keys(cx, &args[2].toObject().as<ArrayObject>());
+ if (!keys)
+ return false;
+
+ // 4. Let result be ArrayCreate(0).
+ RootedArrayObject result(cx, NewDenseUnallocatedArray(cx, keys->length()));
+ if (!result)
+ return false;
+
+ UErrorCode status = U_ZERO_ERROR;
+
+ UDateFormat* fmt =
+ udat_open(UDAT_DEFAULT, UDAT_DEFAULT, icuLocale(locale.ptr()),
+ nullptr, 0, nullptr, 0, &status);
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+ ScopedICUObject<UDateFormat, udat_close> datToClose(fmt);
+
+ // UDateTimePatternGenerator will be needed for translations of date and
+ // time fields like "month", "week", "day" etc.
+ UDateTimePatternGenerator* dtpg = udatpg_open(icuLocale(locale.ptr()), &status);
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+ ScopedICUObject<UDateTimePatternGenerator, udatpg_close> datPgToClose(dtpg);
+
+ RootedValue keyValue(cx);
+ RootedString keyValStr(cx);
+ RootedValue wordVal(cx);
+ Vector<char16_t, INITIAL_CHAR_BUFFER_SIZE> chars(cx);
+ if (!chars.resize(INITIAL_CHAR_BUFFER_SIZE))
+ return false;
+
+ // 5. For each element of keys,
+ for (uint32_t i = 0; i < keys->length(); i++) {
+ /**
+ * We iterate over keys array looking for paths that we have code
+ * branches for.
+ *
+ * For any unknown path branch, the wordVal will keep NullValue and
+ * we'll throw at the end.
+ */
+
+ if (!GetElement(cx, keys, keys, i, &keyValue))
+ return false;
+
+ JSAutoByteString pattern;
+ keyValStr = keyValue.toString();
+ if (!pattern.encodeUtf8(cx, keyValStr))
+ return false;
+
+ wordVal.setNull();
+
+ // 5.a. Perform an implementation dependent algorithm to map a key to a
+ // corresponding display name.
+ const char* pat = pattern.ptr();
+
+ if (!MatchPart(&pat, "dates")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ if (MatchPart(&pat, "fields")) {
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ UDateTimePatternField fieldType;
+
+ if (MatchPart(&pat, "year")) {
+ fieldType = UDATPG_YEAR_FIELD;
+ } else if (MatchPart(&pat, "month")) {
+ fieldType = UDATPG_MONTH_FIELD;
+ } else if (MatchPart(&pat, "week")) {
+ fieldType = UDATPG_WEEK_OF_YEAR_FIELD;
+ } else if (MatchPart(&pat, "day")) {
+ fieldType = UDATPG_DAY_FIELD;
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ // This part must be the final part with no trailing data.
+ if (*pat != '\0') {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ int32_t resultSize;
+
+ const UChar* value = udatpg_getAppendItemName(dtpg, fieldType, &resultSize);
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+
+ JSString* word = NewStringCopyN<CanGC>(cx, UCharToChar16(value), resultSize);
+ if (!word)
+ return false;
+
+ wordVal.setString(word);
+ } else if (MatchPart(&pat, "gregorian")) {
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ UDateFormatSymbolType symbolType;
+ int32_t index;
+
+ if (MatchPart(&pat, "months")) {
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ if (equal(style, "narrow")) {
+ symbolType = UDAT_STANDALONE_NARROW_MONTHS;
+ } else if (equal(style, "short")) {
+ symbolType = UDAT_STANDALONE_SHORT_MONTHS;
+ } else {
+ MOZ_ASSERT(equal(style, "long"));
+ symbolType = UDAT_STANDALONE_MONTHS;
+ }
+
+ if (MatchPart(&pat, "january")) {
+ index = UCAL_JANUARY;
+ } else if (MatchPart(&pat, "february")) {
+ index = UCAL_FEBRUARY;
+ } else if (MatchPart(&pat, "march")) {
+ index = UCAL_MARCH;
+ } else if (MatchPart(&pat, "april")) {
+ index = UCAL_APRIL;
+ } else if (MatchPart(&pat, "may")) {
+ index = UCAL_MAY;
+ } else if (MatchPart(&pat, "june")) {
+ index = UCAL_JUNE;
+ } else if (MatchPart(&pat, "july")) {
+ index = UCAL_JULY;
+ } else if (MatchPart(&pat, "august")) {
+ index = UCAL_AUGUST;
+ } else if (MatchPart(&pat, "september")) {
+ index = UCAL_SEPTEMBER;
+ } else if (MatchPart(&pat, "october")) {
+ index = UCAL_OCTOBER;
+ } else if (MatchPart(&pat, "november")) {
+ index = UCAL_NOVEMBER;
+ } else if (MatchPart(&pat, "december")) {
+ index = UCAL_DECEMBER;
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+ } else if (MatchPart(&pat, "weekdays")) {
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ if (equal(style, "narrow")) {
+ symbolType = UDAT_STANDALONE_NARROW_WEEKDAYS;
+ } else if (equal(style, "short")) {
+ symbolType = UDAT_STANDALONE_SHORT_WEEKDAYS;
+ } else {
+ MOZ_ASSERT(equal(style, "long"));
+ symbolType = UDAT_STANDALONE_WEEKDAYS;
+ }
+
+ if (MatchPart(&pat, "monday")) {
+ index = UCAL_MONDAY;
+ } else if (MatchPart(&pat, "tuesday")) {
+ index = UCAL_TUESDAY;
+ } else if (MatchPart(&pat, "wednesday")) {
+ index = UCAL_WEDNESDAY;
+ } else if (MatchPart(&pat, "thursday")) {
+ index = UCAL_THURSDAY;
+ } else if (MatchPart(&pat, "friday")) {
+ index = UCAL_FRIDAY;
+ } else if (MatchPart(&pat, "saturday")) {
+ index = UCAL_SATURDAY;
+ } else if (MatchPart(&pat, "sunday")) {
+ index = UCAL_SUNDAY;
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+ } else if (MatchPart(&pat, "dayperiods")) {
+ if (!MatchPart(&pat, "/")) {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ symbolType = UDAT_AM_PMS;
+
+ if (MatchPart(&pat, "am")) {
+ index = UCAL_AM;
+ } else if (MatchPart(&pat, "pm")) {
+ index = UCAL_PM;
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ // This part must be the final part with no trailing data.
+ if (*pat != '\0') {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ int32_t resultSize =
+ udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()),
+ INITIAL_CHAR_BUFFER_SIZE, &status);
+ if (status == U_BUFFER_OVERFLOW_ERROR) {
+ if (!chars.resize(resultSize))
+ return false;
+ status = U_ZERO_ERROR;
+ udat_getSymbols(fmt, symbolType, index, Char16ToUChar(chars.begin()),
+ resultSize, &status);
+ }
+ if (U_FAILURE(status)) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_INTERNAL_INTL_ERROR);
+ return false;
+ }
+
+ JSString* word = NewStringCopyN<CanGC>(cx, chars.begin(), resultSize);
+ if (!word)
+ return false;
+
+ wordVal.setString(word);
+ } else {
+ JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, JSMSG_INVALID_KEY, pattern.ptr());
+ return false;
+ }
+
+ MOZ_ASSERT(wordVal.isString());
+
+ // 5.b. Append the result string to result.
+ if (!DefineElement(cx, result, i, wordVal))
+ return false;
+ }
+
+ // 6. Return result.
+ args.rval().setObject(*result);
+ return true;
+}
+
/******************** Intl ********************/
const Class js::IntlClass = {
diff --git a/js/src/builtin/Intl.h b/js/src/builtin/Intl.h
index 54764605b..b2197060d 100644
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -387,6 +387,48 @@ intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp);
extern MOZ_MUST_USE bool
intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp);
+/**
+ * Returns an Array with CLDR-based fields display names.
+ * The function takes three arguments:
+ *
+ * locale
+ * BCP47 compliant locale string
+ * style
+ * A string with values: long or short or narrow
+ * keys
+ * An array or path-like strings that identify keys to be returned
+ * At the moment the following types of keys are supported:
+ *
+ * 'dates/fields/{year|month|week|day}'
+ * 'dates/gregorian/months/{january|...|december}'
+ * 'dates/gregorian/weekdays/{sunday|...|saturday}'
+ * 'dates/gregorian/dayperiods/{am|pm}'
+ *
+ * Example:
+ *
+ * let info = intl_ComputeDisplayNames(
+ * 'en-US',
+ * 'long',
+ * [
+ * 'dates/fields/year',
+ * 'dates/gregorian/months/january',
+ * 'dates/gregorian/weekdays/monday',
+ * 'dates/gregorian/dayperiods/am',
+ * ]
+ * );
+ *
+ * Returned value:
+ *
+ * [
+ * 'year',
+ * 'January',
+ * 'Monday',
+ * 'AM'
+ * ]
+ */
+extern MOZ_MUST_USE bool
+intl_ComputeDisplayNames(JSContext* cx, unsigned argc, Value* vp);
+
#if ENABLE_INTL_API
/**
* Cast char16_t* strings to UChar* strings used by ICU.
@@ -402,6 +444,18 @@ Char16ToUChar(char16_t* chars)
{
return reinterpret_cast<UChar*>(chars);
}
+
+inline char16_t*
+UCharToChar16(UChar* chars)
+{
+ return reinterpret_cast<char16_t*>(chars);
+}
+
+inline const char16_t*
+UCharToChar16(const UChar* chars)
+{
+ return reinterpret_cast<const char16_t*>(chars);
+}
#endif // ENABLE_INTL_API
} // namespace js
diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h
index bb7d22109..f92c583df 100644
--- a/js/src/builtin/IntlTimeZoneData.h
+++ b/js/src/builtin/IntlTimeZoneData.h
@@ -1,5 +1,5 @@
// Generated by make_intl_data.py. DO NOT EDIT.
-// tzdata version = 2017c
+// tzdata version = 2018c
#ifndef builtin_IntlTimeZoneData_h
#define builtin_IntlTimeZoneData_h
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