diff options
Diffstat (limited to 'js')
71 files changed, 1083 insertions, 773 deletions
diff --git a/js/public/CallArgs.h b/js/public/CallArgs.h index 6e6164e55..a7774309a 100644 --- a/js/public/CallArgs.h +++ b/js/public/CallArgs.h @@ -290,7 +290,7 @@ class MOZ_STACK_CLASS CallArgs : public detail::CallArgsBase<detail::IncludeUsed args.constructing_ = constructing; #ifdef DEBUG for (unsigned i = 0; i < argc; ++i) - MOZ_ASSERT_IF(argv[i].isMarkable(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); + MOZ_ASSERT_IF(argv[i].isGCThing(), !GCThingIsMarkedGray(GCCellPtr(argv[i]))); #endif return args; } diff --git a/js/public/Date.h b/js/public/Date.h index cba0ea875..cab36a3de 100644 --- a/js/public/Date.h +++ b/js/public/Date.h @@ -134,6 +134,14 @@ NewDateObject(JSContext* cx, ClippedTime time); JS_PUBLIC_API(double) MakeDate(double year, unsigned month, unsigned day); +// Year is a year, month is 0-11, day is 1-based, and time is in milliseconds. +// The return value is a number of milliseconds since the epoch. +// +// Consistent with the MakeDate algorithm defined in ECMAScript, this value is +// *not* clipped! Use JS::TimeClip if you need a clipped date. +JS_PUBLIC_API(double) +MakeDate(double year, unsigned month, unsigned day, double time); + // Takes an integer number of milliseconds since the epoch and returns the // year. Can return NaN, and will do so if NaN is passed in. JS_PUBLIC_API(double) diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 3e95538db..5acb91b26 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -456,7 +456,7 @@ SetProxyExtra(JSObject* obj, size_t n, const Value& extra) Value* vp = &detail::GetProxyDataLayout(obj)->values->extraSlots[n]; // Trigger a barrier before writing the slot. - if (vp->isMarkable() || extra.isMarkable()) + if (vp->isGCThing() || extra.isGCThing()) SetValueInProxy(vp, extra); else *vp = extra; @@ -482,7 +482,7 @@ SetReservedOrProxyPrivateSlot(JSObject* obj, size_t slot, const Value& value) MOZ_ASSERT(slot == 0); MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj)) || IsProxy(obj)); shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); else sobj->slotRef(slot) = value; diff --git a/js/public/TraceKind.h b/js/public/TraceKind.h index 2eda9cb2c..3270966fc 100644 --- a/js/public/TraceKind.h +++ b/js/public/TraceKind.h @@ -40,9 +40,11 @@ enum class TraceKind // Note: The order here is determined by our Value packing. Other users // should sort alphabetically, for consistency. Object = 0x00, - String = 0x01, - Symbol = 0x02, - Script = 0x03, + String = 0x02, + Symbol = 0x03, + + // 0x1 is not used for any GCThing Value tag, so we use it for Script. + Script = 0x01, // Shape details are exposed through JS_TraceShapeCycleCollectorChildren. Shape = 0x04, diff --git a/js/public/Value.h b/js/public/Value.h index 00fdad586..01666ed4e 100644 --- a/js/public/Value.h +++ b/js/public/Value.h @@ -51,12 +51,12 @@ JS_ENUM_HEADER(JSValueType, uint8_t) JSVAL_TYPE_DOUBLE = 0x00, JSVAL_TYPE_INT32 = 0x01, JSVAL_TYPE_UNDEFINED = 0x02, - JSVAL_TYPE_BOOLEAN = 0x03, - JSVAL_TYPE_MAGIC = 0x04, - JSVAL_TYPE_STRING = 0x05, - JSVAL_TYPE_SYMBOL = 0x06, - JSVAL_TYPE_PRIVATE_GCTHING = 0x07, - JSVAL_TYPE_NULL = 0x08, + JSVAL_TYPE_NULL = 0x03, + JSVAL_TYPE_BOOLEAN = 0x04, + JSVAL_TYPE_MAGIC = 0x05, + JSVAL_TYPE_STRING = 0x06, + JSVAL_TYPE_SYMBOL = 0x07, + JSVAL_TYPE_PRIVATE_GCTHING = 0x08, JSVAL_TYPE_OBJECT = 0x0c, /* These never appear in a jsval; they are only provided as an out-of-band value. */ @@ -75,11 +75,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_CLEAR = 0xFFFFFF80, JSVAL_TAG_INT32 = JSVAL_TAG_CLEAR | JSVAL_TYPE_INT32, JSVAL_TAG_UNDEFINED = JSVAL_TAG_CLEAR | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, JSVAL_TAG_STRING = JSVAL_TAG_CLEAR | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_CLEAR | JSVAL_TYPE_SYMBOL, JSVAL_TAG_BOOLEAN = JSVAL_TAG_CLEAR | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_CLEAR | JSVAL_TYPE_MAGIC, - JSVAL_TAG_NULL = JSVAL_TAG_CLEAR | JSVAL_TYPE_NULL, JSVAL_TAG_OBJECT = JSVAL_TAG_CLEAR | JSVAL_TYPE_OBJECT, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_CLEAR | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); @@ -95,11 +95,11 @@ JS_ENUM_HEADER(JSValueTag, uint32_t) JSVAL_TAG_MAX_DOUBLE = 0x1FFF0, JSVAL_TAG_INT32 = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_INT32, JSVAL_TAG_UNDEFINED = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_UNDEFINED, + JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, JSVAL_TAG_STRING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_STRING, JSVAL_TAG_SYMBOL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_SYMBOL, JSVAL_TAG_BOOLEAN = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_BOOLEAN, JSVAL_TAG_MAGIC = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_MAGIC, - JSVAL_TAG_NULL = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_NULL, JSVAL_TAG_OBJECT = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_OBJECT, JSVAL_TAG_PRIVATE_GCTHING = JSVAL_TAG_MAX_DOUBLE | JSVAL_TYPE_PRIVATE_GCTHING } JS_ENUM_FOOTER(JSValueTag); @@ -112,11 +112,11 @@ JS_ENUM_HEADER(JSValueShiftedTag, uint64_t) JSVAL_SHIFTED_TAG_MAX_DOUBLE = ((((uint64_t)JSVAL_TAG_MAX_DOUBLE) << JSVAL_TAG_SHIFT) | 0xFFFFFFFF), JSVAL_SHIFTED_TAG_INT32 = (((uint64_t)JSVAL_TAG_INT32) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_UNDEFINED = (((uint64_t)JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT), + JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_STRING = (((uint64_t)JSVAL_TAG_STRING) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_SYMBOL = (((uint64_t)JSVAL_TAG_SYMBOL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_BOOLEAN = (((uint64_t)JSVAL_TAG_BOOLEAN) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_MAGIC = (((uint64_t)JSVAL_TAG_MAGIC) << JSVAL_TAG_SHIFT), - JSVAL_SHIFTED_TAG_NULL = (((uint64_t)JSVAL_TAG_NULL) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_OBJECT = (((uint64_t)JSVAL_TAG_OBJECT) << JSVAL_TAG_SHIFT), JSVAL_SHIFTED_TAG_PRIVATE_GCTHING = (((uint64_t)JSVAL_TAG_PRIVATE_GCTHING) << JSVAL_TAG_SHIFT) } JS_ENUM_FOOTER(JSValueShiftedTag); @@ -140,24 +140,25 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t), #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type))) -#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << 32) + #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING #elif defined(JS_PUNBOX64) +#define JSVAL_RAW64_UNDEFINED (uint64_t(JSVAL_TAG_UNDEFINED) << JSVAL_TAG_SHIFT) + #define JSVAL_PAYLOAD_MASK 0x00007FFFFFFFFFFFLL #define JSVAL_TAG_MASK 0xFFFF800000000000LL #define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_MAX_DOUBLE | (type))) #define JSVAL_TYPE_TO_SHIFTED_TAG(type) (((uint64_t)JSVAL_TYPE_TO_TAG(type)) << JSVAL_TAG_SHIFT) -#define JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET JSVAL_TAG_NULL #define JSVAL_UPPER_EXCL_TAG_OF_PRIMITIVE_SET JSVAL_TAG_OBJECT #define JSVAL_UPPER_INCL_TAG_OF_NUMBER_SET JSVAL_TAG_INT32 #define JSVAL_LOWER_INCL_TAG_OF_GCTHING_SET JSVAL_TAG_STRING -#define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET JSVAL_SHIFTED_TAG_NULL #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_PRIMITIVE_SET JSVAL_SHIFTED_TAG_OBJECT #define JSVAL_UPPER_EXCL_SHIFTED_TAG_OF_NUMBER_SET JSVAL_SHIFTED_TAG_UNDEFINED #define JSVAL_LOWER_INCL_SHIFTED_TAG_OF_GCTHING_SET JSVAL_SHIFTED_TAG_STRING @@ -537,12 +538,7 @@ class MOZ_NON_PARAM alignas(8) Value } bool isObjectOrNull() const { - MOZ_ASSERT(uint32_t(toTag()) <= uint32_t(JSVAL_TAG_OBJECT)); -#if defined(JS_NUNBOX32) - return uint32_t(toTag()) >= uint32_t(JSVAL_LOWER_INCL_TAG_OF_OBJ_OR_NULL_SET); -#elif defined(JS_PUNBOX64) - return data.asBits >= JSVAL_LOWER_INCL_SHIFTED_TAG_OF_OBJ_OR_NULL_SET; -#endif + return isObject() || isNull(); } bool isGCThing() const { @@ -575,12 +571,8 @@ class MOZ_NON_PARAM alignas(8) Value return isMagic(); } - bool isMarkable() const { - return isGCThing() && !isNull(); - } - JS::TraceKind traceKind() const { - MOZ_ASSERT(isMarkable()); + MOZ_ASSERT(isGCThing()); static_assert((JSVAL_TAG_STRING & 0x03) == size_t(JS::TraceKind::String), "Value type tags must correspond with JS::TraceKinds."); static_assert((JSVAL_TAG_SYMBOL & 0x03) == size_t(JS::TraceKind::Symbol), @@ -684,11 +676,6 @@ class MOZ_NON_PARAM alignas(8) Value #endif } - js::gc::Cell* toMarkablePointer() const { - MOZ_ASSERT(isMarkable()); - return toGCThing(); - } - GCCellPtr toGCCellPtr() const { return GCCellPtr(toGCThing(), traceKind()); } @@ -760,9 +747,9 @@ class MOZ_NON_PARAM alignas(8) Value * Private GC Thing API * * Non-JSObject, JSString, and JS::Symbol cells may be put into the 64-bit - * payload as private GC things. Such Values are considered isMarkable() - * and isGCThing(), and as such, automatically marked. Their traceKind() - * is gotten via their cells. + * payload as private GC things. Such Values are considered isGCThing(), and + * as such, automatically marked. Their traceKind() is gotten via their + * cells. */ void setPrivateGCThing(js::gc::Cell* cell) { @@ -834,7 +821,7 @@ class MOZ_NON_PARAM alignas(8) Value double asDouble; void* asPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -860,7 +847,7 @@ class MOZ_NON_PARAM alignas(8) Value size_t asWord; uintptr_t asUIntPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -888,7 +875,7 @@ class MOZ_NON_PARAM alignas(8) Value double asDouble; void* asPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -912,7 +899,7 @@ class MOZ_NON_PARAM alignas(8) Value size_t asWord; uintptr_t asUIntPtr; - layout() = default; + layout() : asBits(JSVAL_RAW64_UNDEFINED) {} explicit constexpr layout(uint64_t bits) : asBits(bits) {} explicit constexpr layout(double d) : asDouble(d) {} } data; @@ -965,8 +952,51 @@ class MOZ_NON_PARAM alignas(8) Value } } JS_HAZ_GC_POINTER; +/** + * This is a null-constructible structure that can convert to and from + * a Value, allowing UninitializedValue to be stored in unions. + */ +struct MOZ_NON_PARAM alignas(8) UninitializedValue +{ + private: + uint64_t bits; + + public: + UninitializedValue() = default; + UninitializedValue(const UninitializedValue&) = default; + MOZ_IMPLICIT UninitializedValue(const Value& val) : bits(val.asRawBits()) {} + + inline uint64_t asRawBits() const { + return bits; + } + + inline Value& asValueRef() { + return *reinterpret_cast<Value*>(this); + } + inline const Value& asValueRef() const { + return *reinterpret_cast<const Value*>(this); + } + + inline operator Value&() { + return asValueRef(); + } + inline operator Value const&() const { + return asValueRef(); + } + inline operator Value() const { + return asValueRef(); + } + + inline void operator=(Value const& other) { + asValueRef() = other; + } +}; + static_assert(sizeof(Value) == 8, "Value size must leave three tag bits, be a binary power, and is ubiquitously depended upon everywhere"); +static_assert(sizeof(UninitializedValue) == sizeof(Value), "Value and UninitializedValue must be the same size"); +static_assert(alignof(UninitializedValue) == alignof(Value), "Value and UninitializedValue must have same alignment"); + inline bool IsOptimizedPlaceholderMagicValue(const Value& v) { @@ -980,7 +1010,7 @@ IsOptimizedPlaceholderMagicValue(const Value& v) static MOZ_ALWAYS_INLINE void ExposeValueToActiveJS(const Value& v) { - if (v.isMarkable()) + if (v.isGCThing()) js::gc::ExposeGCThingToActiveJS(GCCellPtr(v)); } @@ -1298,7 +1328,7 @@ template <> struct BarrierMethods<JS::Value> { static gc::Cell* asGCThingOrNull(const JS::Value& v) { - return v.isMarkable() ? v.toGCThing() : nullptr; + return v.isGCThing() ? v.toGCThing() : nullptr; } static void postBarrier(JS::Value* v, const JS::Value& prev, const JS::Value& next) { JS::HeapValuePostBarrier(v, prev, next); @@ -1338,9 +1368,8 @@ class ValueOperations bool isObject() const { return value().isObject(); } bool isMagic() const { return value().isMagic(); } bool isMagic(JSWhyMagic why) const { return value().isMagic(why); } - bool isMarkable() const { return value().isMarkable(); } - bool isPrimitive() const { return value().isPrimitive(); } bool isGCThing() const { return value().isGCThing(); } + bool isPrimitive() const { return value().isPrimitive(); } bool isNullOrUndefined() const { return value().isNullOrUndefined(); } bool isObjectOrNull() const { return value().isObjectOrNull(); } @@ -1485,7 +1514,7 @@ DispatchTyped(F f, const JS::Value& val, Args&&... args) return f(val.toSymbol(), mozilla::Forward<Args>(args)...); if (MOZ_UNLIKELY(val.isPrivateGCThing())) return DispatchTyped(f, val.toGCCellPtr(), mozilla::Forward<Args>(args)...); - MOZ_ASSERT(!val.isMarkable()); + MOZ_ASSERT(!val.isGCThing()); return F::defaultValue(val); } diff --git a/js/src/Makefile.in b/js/src/Makefile.in index 3be6a6781..b007954b1 100644 --- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -147,13 +147,6 @@ ifeq ($(OS_ARCH),AIX) CFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 CXXFLAGS += -qsuppress=1540-1281 -qsuppress=1540-1608 endif -ifeq ($(OS_ARCH),HP-UX) -# Suppress warnings from aCC -# 3055: anonymous unions declaring types -# 4189: offsetof() on non-POD types -CFLAGS += +W3055,4189 -CXXFLAGS += +W3055,4189 -endif endif ifeq ($(OS_ARCH),SunOS) ifeq ($(TARGET_CPU),sparc) diff --git a/js/src/aclocal.m4 b/js/src/aclocal.m4 index 627837a41..abbbd4873 100644 --- a/js/src/aclocal.m4 +++ b/js/src/aclocal.m4 @@ -25,7 +25,6 @@ builtin(include, ../../build/autoconf/zlib.m4)dnl builtin(include, ../../build/autoconf/icu.m4)dnl builtin(include, ../../build/autoconf/clang-plugin.m4)dnl builtin(include, ../../build/autoconf/alloc.m4)dnl -builtin(include, ../../build/autoconf/jemalloc.m4)dnl builtin(include, ../../build/autoconf/sanitize.m4)dnl builtin(include, ../../build/autoconf/ios.m4)dnl diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 3a20c487b..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 @@ -2921,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/Intl.js b/js/src/builtin/Intl.js index 37c87365b..509168d7a 100644 --- a/js/src/builtin/Intl.js +++ b/js/src/builtin/Intl.js @@ -9,8 +9,7 @@ JSMSG_INVALID_OPTION_VALUE: false, JSMSG_INVALID_DIGITS_VALUE: false, JSMSG_INTL_OBJECT_REINITED: false, JSMSG_INVALID_CURRENCY_CODE: false, JSMSG_UNDEFINED_CURRENCY: false, JSMSG_INVALID_TIME_ZONE: false, - JSMSG_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false, - JSMSG_INVALID_KEY: false, + JSMSG_DATE_NOT_FINITE: false, intl_Collator_availableLocales: false, intl_availableCollations: false, intl_CompareStrings: false, @@ -21,9 +20,6 @@ intl_availableCalendars: false, intl_patternForSkeleton: false, intl_FormatDateTime: false, - intl_SelectPluralRule: false, - intl_GetPluralCategories: false, - intl_GetCalendarInfo: false, */ /* @@ -860,7 +856,6 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) { return BestAvailableLocaleHelper(availableLocales, locale, false); } -var noRelevantExtensionKeys = []; /** * Compares a BCP 47 language priority list against the set of locales in @@ -1188,10 +1183,9 @@ function GetOption(options, property, type, values, fallback) { * Spec: ECMAScript Internationalization API Specification, 9.2.10. */ function GetNumberOption(options, property, minimum, maximum, fallback) { - assert(typeof minimum === "number" && (minimum | 0) === minimum, "GetNumberOption"); - assert(typeof maximum === "number" && (maximum | 0) === maximum, "GetNumberOption"); - assert(typeof fallback === "number" && (fallback | 0) === fallback, "GetNumberOption"); - assert(minimum <= fallback && fallback <= maximum, "GetNumberOption"); + assert(typeof minimum === "number", "GetNumberOption"); + assert(typeof maximum === "number", "GetNumberOption"); + assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption"); // Step 1. var value = options[property]; @@ -1201,10 +1195,7 @@ function GetNumberOption(options, property, minimum, maximum, fallback) { value = ToNumber(value); if (Number_isNaN(value) || value < minimum || value > maximum) ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value); - - // Apply bitwise-or to convert -0 to +0 per ES2017, 5.2 and to ensure - // the result is an int32 value. - return std_Math_floor(value) | 0; + return std_Math_floor(value); } // Step 3. @@ -1278,9 +1269,7 @@ function initializeIntlObject(obj) { function setLazyData(internals, type, lazyData) { assert(internals.type === "partial", "can't set lazy data for anything but a newborn"); - assert(type === "Collator" || type === "DateTimeFormat" || - type == "NumberFormat" || type === "PluralRules", - "bad type"); + assert(type === "Collator" || type === "DateTimeFormat" || type == "NumberFormat", "bad type"); assert(IsObject(lazyData), "non-object lazy data"); // Set in reverse order so that the .type change is a barrier. @@ -1330,9 +1319,7 @@ function isInitializedIntlObject(obj) { if (IsObject(internals)) { assert(callFunction(std_Object_hasOwnProperty, internals, "type"), "missing type"); var type = internals.type; - assert(type === "partial" || type === "Collator" || - type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules", - "unexpected type"); + assert(type === "partial" || type === "Collator" || type === "DateTimeFormat" || type === "NumberFormat", "unexpected type"); assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData"); assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps"); } else { @@ -1389,8 +1376,6 @@ function getInternals(obj) internalProps = resolveCollatorInternals(lazyData) else if (type === "DateTimeFormat") internalProps = resolveDateTimeFormatInternals(lazyData) - else if (type === "PluralRules") - internalProps = resolvePluralRulesInternals(lazyData) else internalProps = resolveNumberFormatInternals(lazyData); setInternalProperties(internals, internalProps); @@ -1722,7 +1707,6 @@ function Intl_Collator_compare_get() { // Step 2. return internals.boundCompare; } -_SetCanonicalName(Intl_Collator_compare_get, "get compare"); /** @@ -1791,37 +1775,45 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { // Step 6. var opt = lazyNumberFormatData.opt; + // Compute effective locale. + // Step 9. var NumberFormat = numberFormatInternalProperties; - // Step 9. + // Step 10. var localeData = NumberFormat.localeData; - // Step 10. + // Step 11. var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat), lazyNumberFormatData.requestedLocales, lazyNumberFormatData.opt, NumberFormat.relevantExtensionKeys, localeData); - // Steps 11-12. (Step 13 is not relevant to our implementation.) + // Steps 12-13. (Step 14 is not relevant to our implementation.) internalProps.locale = r.locale; internalProps.numberingSystem = r.nu; // Compute formatting options. - // Step 15. - var style = lazyNumberFormatData.style; - internalProps.style = style; + // Step 16. + var s = lazyNumberFormatData.style; + internalProps.style = s; - // Steps 19, 21. - if (style === "currency") { + // Steps 20, 22. + if (s === "currency") { internalProps.currency = lazyNumberFormatData.currency; internalProps.currencyDisplay = lazyNumberFormatData.currencyDisplay; } + // Step 24. internalProps.minimumIntegerDigits = lazyNumberFormatData.minimumIntegerDigits; + + // Steps 27. internalProps.minimumFractionDigits = lazyNumberFormatData.minimumFractionDigits; + + // Step 30. internalProps.maximumFractionDigits = lazyNumberFormatData.maximumFractionDigits; + // Step 33. if ("minimumSignificantDigits" in lazyNumberFormatData) { // Note: Intl.NumberFormat.prototype.resolvedOptions() exposes the // actual presence (versus undefined-ness) of these properties. @@ -1830,10 +1822,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) { internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits; } - // Step 27. + // Step 35. internalProps.useGrouping = lazyNumberFormatData.useGrouping; - // Step 34. + // Step 42. internalProps.boundFormat = undefined; // The caller is responsible for associating |internalProps| with the right @@ -1861,44 +1853,6 @@ function getNumberFormatInternals(obj, methodName) { return internalProps; } -/** - * Applies digit options used for number formatting onto the intl object. - * - * Spec: ECMAScript Internationalization API Specification, 11.1.1. - */ -function SetNumberFormatDigitOptions(lazyData, options, mnfdDefault, mxfdDefault) { - // We skip Step 1 because we set the properties on a lazyData object. - - // Step 2-3. - assert(IsObject(options), "SetNumberFormatDigitOptions"); - assert(typeof mnfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(typeof mxfdDefault === "number", "SetNumberFormatDigitOptions"); - assert(mnfdDefault <= mxfdDefault, "SetNumberFormatDigitOptions"); - - // Steps 4-6. - const mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); - const mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); - const mxfdActualDefault = std_Math_max(mnfd, mxfdDefault); - const mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdActualDefault); - - // Steps 7-8. - let mnsd = options.minimumSignificantDigits; - let mxsd = options.maximumSignificantDigits; - - // Steps 9-11. - lazyData.minimumIntegerDigits = mnid; - lazyData.minimumFractionDigits = mnfd; - lazyData.maximumFractionDigits = mxfd; - - // Step 12. - if (mnsd !== undefined || mxsd !== undefined) { - mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); - mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); - lazyData.minimumSignificantDigits = mnsd; - lazyData.maximumSignificantDigits = mxsd; - } -} - /** * Initializes an object as a NumberFormat. @@ -1948,7 +1902,7 @@ function InitializeNumberFormat(numberFormat, locales, options) { // } // // Note that lazy data is only installed as a final step of initialization, - // so every NumberFormat lazy data object has *all* these properties, never a + // so every Collator lazy data object has *all* these properties, never a // subset of them. var lazyNumberFormatData = std_Object_create(null); @@ -1978,46 +1932,67 @@ function InitializeNumberFormat(numberFormat, locales, options) { opt.localeMatcher = matcher; // Compute formatting options. - // Step 14. - var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); - lazyNumberFormatData.style = style; + // Step 15. + var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal"); + lazyNumberFormatData.style = s; - // Steps 16-19. + // Steps 17-20. var c = GetOption(options, "currency", "string", undefined, undefined); if (c !== undefined && !IsWellFormedCurrencyCode(c)) ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c); var cDigits; - if (style === "currency") { + if (s === "currency") { if (c === undefined) ThrowTypeError(JSMSG_UNDEFINED_CURRENCY); - // Steps 19.a-c. + // Steps 20.a-c. c = toASCIIUpperCase(c); lazyNumberFormatData.currency = c; cDigits = CurrencyDigits(c); } - // Step 20. + // Step 21. var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol"); - if (style === "currency") + if (s === "currency") lazyNumberFormatData.currencyDisplay = cd; - // Steps 22-25. - var mnfdDefault, mxfdDefault; - if (style === "currency") { - mnfdDefault = cDigits; - mxfdDefault = cDigits; - } else { - mnfdDefault = 0; - mxfdDefault = style === "percent" ? 0 : 3; + // Step 23. + var mnid = GetNumberOption(options, "minimumIntegerDigits", 1, 21, 1); + lazyNumberFormatData.minimumIntegerDigits = mnid; + + // Steps 25-26. + var mnfdDefault = (s === "currency") ? cDigits : 0; + var mnfd = GetNumberOption(options, "minimumFractionDigits", 0, 20, mnfdDefault); + lazyNumberFormatData.minimumFractionDigits = mnfd; + + // Steps 28-29. + var mxfdDefault; + if (s === "currency") + mxfdDefault = std_Math_max(mnfd, cDigits); + else if (s === "percent") + mxfdDefault = std_Math_max(mnfd, 0); + else + mxfdDefault = std_Math_max(mnfd, 3); + var mxfd = GetNumberOption(options, "maximumFractionDigits", mnfd, 20, mxfdDefault); + lazyNumberFormatData.maximumFractionDigits = mxfd; + + // Steps 31-32. + var mnsd = options.minimumSignificantDigits; + var mxsd = options.maximumSignificantDigits; + + // Step 33. + if (mnsd !== undefined || mxsd !== undefined) { + mnsd = GetNumberOption(options, "minimumSignificantDigits", 1, 21, 1); + mxsd = GetNumberOption(options, "maximumSignificantDigits", mnsd, 21, 21); + lazyNumberFormatData.minimumSignificantDigits = mnsd; + lazyNumberFormatData.maximumSignificantDigits = mxsd; } - SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault); - // Steps 26. + // Step 34. var g = GetOption(options, "useGrouping", "boolean", undefined, true); lazyNumberFormatData.useGrouping = g; - // Steps 35-36. + // Step 43. // // We've done everything that must be done now: mark the lazy data as fully // computed and install it. @@ -2026,6 +2001,43 @@ function InitializeNumberFormat(numberFormat, locales, options) { /** + * Mapping from currency codes to the number of decimal digits used for them. + * Default is 2 digits. + * + * Spec: ISO 4217 Currency and Funds Code List. + * http://www.currency-iso.org/en/home/tables/table-a1.html + */ +var currencyDigits = { + BHD: 3, + BIF: 0, + BYR: 0, + CLF: 4, + CLP: 0, + DJF: 0, + GNF: 0, + IQD: 3, + ISK: 0, + JOD: 3, + JPY: 0, + KMF: 0, + KRW: 0, + KWD: 3, + LYD: 3, + OMR: 3, + PYG: 0, + RWF: 0, + TND: 3, + UGX: 0, + UYI: 0, + VND: 0, + VUV: 0, + XAF: 0, + XOF: 0, + XPF: 0 +}; + + +/** * Returns the number of decimal digits to be used for the given currency. * * Spec: ECMAScript Internationalization API Specification, 11.1.1. @@ -2106,7 +2118,7 @@ function numberFormatFormatToBind(value) { // Step 1.a.ii-iii. var x = ToNumber(value); - return intl_FormatNumber(this, x, /* formatToParts = */ false); + return intl_FormatNumber(this, x); } @@ -2133,22 +2145,6 @@ function Intl_NumberFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_NumberFormat_format_get, "get format"); - - -function Intl_NumberFormat_formatToParts(value) { - // Step 1. - var nf = this; - - // Steps 2-3. - getNumberFormatInternals(nf, "formatToParts"); - - // Step 4. - var x = ToNumber(value); - - // Step 5. - return intl_FormatNumber(nf, x, /* formatToParts = */ true); -} /** @@ -2290,6 +2286,26 @@ function getDateTimeFormatInternals(obj, methodName) { return internalProps; } +/** + * Components of date and time formats and their values. + * + * Spec: ECMAScript Internationalization API Specification, 12.1.1. + */ +var dateTimeComponentValues = { + weekday: ["narrow", "short", "long"], + era: ["narrow", "short", "long"], + year: ["2-digit", "numeric"], + month: ["2-digit", "numeric", "narrow", "short", "long"], + day: ["2-digit", "numeric"], + hour: ["2-digit", "numeric"], + minute: ["2-digit", "numeric"], + second: ["2-digit", "numeric"], + timeZoneName: ["short", "long"] +}; + + +var dateTimeComponents = std_Object_getOwnPropertyNames(dateTimeComponentValues); + /** * Initializes an object as a DateTimeFormat. @@ -2379,19 +2395,12 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) { lazyDateTimeFormatData.formatOpt = formatOpt; // Step 19. - // 12.1, Table 4: Components of date and time formats. - formatOpt.weekday = GetOption(options, "weekday", "string", ["narrow", "short", "long"], - undefined); - formatOpt.era = GetOption(options, "era", "string", ["narrow", "short", "long"], undefined); - formatOpt.year = GetOption(options, "year", "string", ["2-digit", "numeric"], undefined); - formatOpt.month = GetOption(options, "month", "string", - ["2-digit", "numeric", "narrow", "short", "long"], undefined); - formatOpt.day = GetOption(options, "day", "string", ["2-digit", "numeric"], undefined); - formatOpt.hour = GetOption(options, "hour", "string", ["2-digit", "numeric"], undefined); - formatOpt.minute = GetOption(options, "minute", "string", ["2-digit", "numeric"], undefined); - formatOpt.second = GetOption(options, "second", "string", ["2-digit", "numeric"], undefined); - formatOpt.timeZoneName = GetOption(options, "timeZoneName", "string", ["short", "long"], - undefined); + var i, prop; + for (i = 0; i < dateTimeComponents.length; i++) { + prop = dateTimeComponents[i]; + var value = GetOption(options, prop, "string", dateTimeComponentValues[prop], undefined); + formatOpt[prop] = value; + } // Steps 20-21 provided by ICU - see comment after this function. @@ -2659,6 +2668,7 @@ function ToDateTimeOptions(options, required, defaults) { return options; } + /** * Compares the date and time components requested by options with the available * date and time formats in formats, and selects the best match according @@ -2844,7 +2854,6 @@ function Intl_DateTimeFormat_format_get() { // Step 2. return internals.boundFormat; } -_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format"); function Intl_DateTimeFormat_formatToParts() { @@ -2980,232 +2989,6 @@ function resolveICUPattern(pattern, result) { } } -/********** Intl.PluralRules **********/ - -/** - * PluralRules internal properties. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.3. - */ -var pluralRulesInternalProperties = { - _availableLocales: null, - availableLocales: function() - { - var locales = this._availableLocales; - if (locales) - return locales; - - locales = intl_PluralRules_availableLocales(); - addSpecialMissingLanguageTags(locales); - return (this._availableLocales = locales); - } -}; - -/** - * Compute an internal properties object from |lazyPluralRulesData|. - */ -function resolvePluralRulesInternals(lazyPluralRulesData) { - assert(IsObject(lazyPluralRulesData), "lazy data not an object?"); - - var internalProps = std_Object_create(null); - - var requestedLocales = lazyPluralRulesData.requestedLocales; - - var PluralRules = pluralRulesInternalProperties; - - // Step 13. - const r = ResolveLocale(callFunction(PluralRules.availableLocales, PluralRules), - lazyPluralRulesData.requestedLocales, - lazyPluralRulesData.opt, - noRelevantExtensionKeys, undefined); - - // Step 14. - internalProps.locale = r.locale; - internalProps.type = lazyPluralRulesData.type; - - internalProps.pluralCategories = intl_GetPluralCategories( - internalProps.locale, - internalProps.type); - - internalProps.minimumIntegerDigits = lazyPluralRulesData.minimumIntegerDigits; - internalProps.minimumFractionDigits = lazyPluralRulesData.minimumFractionDigits; - internalProps.maximumFractionDigits = lazyPluralRulesData.maximumFractionDigits; - - if ("minimumSignificantDigits" in lazyPluralRulesData) { - assert("maximumSignificantDigits" in lazyPluralRulesData, "min/max sig digits mismatch"); - internalProps.minimumSignificantDigits = lazyPluralRulesData.minimumSignificantDigits; - internalProps.maximumSignificantDigits = lazyPluralRulesData.maximumSignificantDigits; - } - - return internalProps; -} - -/** - * Returns an object containing the PluralRules internal properties of |obj|, - * or throws a TypeError if |obj| isn't PluralRules-initialized. - */ -function getPluralRulesInternals(obj, methodName) { - var internals = getIntlObjectInternals(obj, "PluralRules", methodName); - assert(internals.type === "PluralRules", "bad type escaped getIntlObjectInternals"); - - var internalProps = maybeInternalProperties(internals); - if (internalProps) - return internalProps; - - internalProps = resolvePluralRulesInternals(internals.lazyData); - setInternalProperties(internals, internalProps); - return internalProps; -} - -/** - * Initializes an object as a PluralRules. - * - * This method is complicated a moderate bit by its implementing initialization - * as a *lazy* concept. Everything that must happen now, does -- but we defer - * all the work we can until the object is actually used as a PluralRules. - * This later work occurs in |resolvePluralRulesInternals|; steps not noted - * here occur there. - * - * Spec: ECMAScript 402 API, PluralRules, 1.1.1. - */ -function InitializePluralRules(pluralRules, locales, options) { - assert(IsObject(pluralRules), "InitializePluralRules"); - - // Step 1. - if (isInitializedIntlObject(pluralRules)) - ThrowTypeError(JSMSG_INTL_OBJECT_REINITED); - - let internals = initializeIntlObject(pluralRules); - - // Lazy PluralRules data has the following structure: - // - // { - // requestedLocales: List of locales, - // type: "cardinal" / "ordinal", - // - // opt: // opt object computer in InitializePluralRules - // { - // localeMatcher: "lookup" / "best fit", - // } - // - // minimumIntegerDigits: integer ∈ [1, 21], - // minimumFractionDigits: integer ∈ [0, 20], - // maximumFractionDigits: integer ∈ [0, 20], - // - // // optional - // minimumSignificantDigits: integer ∈ [1, 21], - // maximumSignificantDigits: integer ∈ [1, 21], - // } - // - // Note that lazy data is only installed as a final step of initialization, - // so every PluralRules lazy data object has *all* these properties, never a - // subset of them. - const lazyPluralRulesData = std_Object_create(null); - - // Step 3. - let requestedLocales = CanonicalizeLocaleList(locales); - lazyPluralRulesData.requestedLocales = requestedLocales; - - // Steps 4-5. - if (options === undefined) - options = {}; - else - options = ToObject(options); - - // Step 6. - const type = GetOption(options, "type", "string", ["cardinal", "ordinal"], "cardinal"); - lazyPluralRulesData.type = type; - - // Step 8. - let opt = new Record(); - lazyPluralRulesData.opt = opt; - - // Steps 9-10. - let matcher = GetOption(options, "localeMatcher", "string", ["lookup", "best fit"], "best fit"); - opt.localeMatcher = matcher; - - // Steps 11-12. - SetNumberFormatDigitOptions(lazyPluralRulesData, options, 0, 3); - - setLazyData(internals, "PluralRules", lazyPluralRulesData) -} - -/** - * Returns the subset of the given locale list for which this locale list has a - * matching (possibly fallback) locale. Locales appear in the same order in the - * returned list as in the input list. - * - * Spec: ECMAScript 402 API, PluralRules, 1.3.2. - */ -function Intl_PluralRules_supportedLocalesOf(locales /*, options*/) { - var options = arguments.length > 1 ? arguments[1] : undefined; - - // Step 1. - var availableLocales = callFunction(pluralRulesInternalProperties.availableLocales, - pluralRulesInternalProperties); - // Step 2. - let requestedLocales = CanonicalizeLocaleList(locales); - - // Step 3. - return SupportedLocales(availableLocales, requestedLocales, options); -} - -/** - * Returns a String value representing the plural category matching - * the number passed as value according to the - * effective locale and the formatting options of this PluralRules. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.3. - */ -function Intl_PluralRules_select(value) { - // Step 1. - let pluralRules = this; - // Step 2. - let internals = getPluralRulesInternals(pluralRules, "select"); - - // Steps 3-4. - let n = ToNumber(value); - - // Step 5. - return intl_SelectPluralRule(pluralRules, n); -} - -/** - * Returns the resolved options for a PluralRules object. - * - * Spec: ECMAScript 402 API, PluralRules, 1.4.4. - */ -function Intl_PluralRules_resolvedOptions() { - var internals = getPluralRulesInternals(this, "resolvedOptions"); - - var internalsPluralCategories = internals.pluralCategories; - var pluralCategories = []; - for (var i = 0; i < internalsPluralCategories.length; i++) - _DefineDataProperty(pluralCategories, i, internalsPluralCategories[i]); - - var result = { - locale: internals.locale, - type: internals.type, - pluralCategories, - minimumIntegerDigits: internals.minimumIntegerDigits, - minimumFractionDigits: internals.minimumFractionDigits, - maximumFractionDigits: internals.maximumFractionDigits, - }; - - var optionalProperties = [ - "minimumSignificantDigits", - "maximumSignificantDigits" - ]; - - for (var i = 0; i < optionalProperties.length; i++) { - var p = optionalProperties[i]; - if (callFunction(std_Object_hasOwnProperty, internals, p)) - _DefineDataProperty(result, p, internals[p]); - } - return result; -} - - function Intl_getCanonicalLocales(locales) { let codes = CanonicalizeLocaleList(locales); let result = []; @@ -3241,126 +3024,3 @@ function Intl_getCalendarInfo(locales) { return result; } - -/** - * This function is a custom method designed after Intl API, but currently - * not part of the spec or spec proposal. - * We want to use it internally to retrieve translated values from CLDR in - * order to ensure they're aligned with what Intl API returns. - * - * This API may one day be a foundation for an ECMA402 API spec proposal. - * - * The function takes two arguments - locales which is a list of locale strings - * and options which is an object with two optional properties: - * - * keys: - * an Array of string values that are paths to individual terms - * - * style: - * a String with a value "long", "short" or "narrow" - * - * It returns an object with properties: - * - * locale: - * a negotiated locale string - * - * style: - * negotiated style - * - * values: - * A key-value pair list of requested keys and corresponding - * translated values - * - */ -function Intl_getDisplayNames(locales, options) { - // 1. Let requestLocales be ? CanonicalizeLocaleList(locales). - const requestedLocales = CanonicalizeLocaleList(locales); - - // 2. If options is undefined, then - if (options === undefined) - // a. Let options be ObjectCreate(%ObjectPrototype%). - options = {}; - // 3. Else, - else - // a. Let options be ? ToObject(options). - options = ToObject(options); - - const DateTimeFormat = dateTimeFormatInternalProperties; - - // 4. Let localeData be %DateTimeFormat%.[[localeData]]. - const localeData = DateTimeFormat.localeData; - - // 5. Let opt be a new Record. - const localeOpt = new Record(); - // 6. Set localeOpt.[[localeMatcher]] to "best fit". - localeOpt.localeMatcher = "best fit"; - - // 7. Let r be ResolveLocale(%DateTimeFormat%.[[availableLocales]], requestedLocales, localeOpt, - // %DateTimeFormat%.[[relevantExtensionKeys]], localeData). - const r = ResolveLocale(callFunction(DateTimeFormat.availableLocales, DateTimeFormat), - requestedLocales, - localeOpt, - DateTimeFormat.relevantExtensionKeys, - localeData); - - // 8. Let style be ? GetOption(options, "style", "string", « "long", "short", "narrow" », "long"). - const style = GetOption(options, "style", "string", ["long", "short", "narrow"], "long"); - // 9. Let keys be ? Get(options, "keys"). - let keys = options.keys; - - // 10. If keys is undefined, - if (keys === undefined) { - // a. Let keys be ArrayCreate(0). - keys = []; - } else if (!IsObject(keys)) { - // 11. Else, - // a. If Type(keys) is not Object, throw a TypeError exception. - ThrowTypeError(JSMSG_INVALID_KEYS_TYPE); - } - - // 12. Let processedKeys be ArrayCreate(0). - // (This really should be a List, but we use an Array here in order that - // |intl_ComputeDisplayNames| may infallibly access the list's length via - // |ArrayObject::length|.) - let processedKeys = []; - // 13. Let len be ? ToLength(? Get(keys, "length")). - let len = ToLength(keys.length); - // 14. Let i be 0. - // 15. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let processedKey be ? ToString(? Get(keys, i)). - // b. Perform ? CreateDataPropertyOrThrow(processedKeys, i, processedKey). - callFunction(std_Array_push, processedKeys, ToString(keys[i])); - } - - // 16. Let names be ? ComputeDisplayNames(r.[[locale]], style, processedKeys). - const names = intl_ComputeDisplayNames(r.locale, style, processedKeys); - - // 17. Let values be ObjectCreate(%ObjectPrototype%). - const values = {}; - - // 18. Set i to 0. - // 19. Repeat, while i < len - for (let i = 0; i < len; i++) { - // a. Let key be ? Get(processedKeys, i). - const key = processedKeys[i]; - // b. Let name be ? Get(names, i). - const name = names[i]; - // c. Assert: Type(name) is string. - assert(typeof name === "string", "unexpected non-string value"); - // d. Assert: the length of name is greater than zero. - assert(name.length > 0, "empty string value"); - // e. Perform ? DefinePropertyOrThrow(values, key, name). - _DefineDataProperty(values, key, name); - } - - // 20. Let options be ObjectCreate(%ObjectPrototype%). - // 21. Perform ! DefinePropertyOrThrow(result, "locale", r.[[locale]]). - // 22. Perform ! DefinePropertyOrThrow(result, "style", style). - // 23. Perform ! DefinePropertyOrThrow(result, "values", values). - const result = { locale: r.locale, style, values }; - - // 24. Return result. - return result; -} - diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h index f92c583df..3d5c1b0d5 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 = 2018c +// tzdata version = 2018d #ifndef builtin_IntlTimeZoneData_h #define builtin_IntlTimeZoneData_h diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 40fd008b9..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; diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp index eef6fd7ec..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()); 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/frontend/Parser.cpp b/js/src/frontend/Parser.cpp index f4c02720a..623379f61 100644 --- a/js/src/frontend/Parser.cpp +++ b/js/src/frontend/Parser.cpp @@ -9617,8 +9617,9 @@ Parser<ParseHandler>::warnOnceAboutForEach() return true; if (!cx->compartment()->warnedAboutForEach) { - if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) - return false; + // Disabled warning spew. + // if (!report(ParseWarning, false, null(), JSMSG_DEPRECATED_FOR_EACH)) + // return false; cx->compartment()->warnedAboutForEach = true; } return true; diff --git a/js/src/gc/Barrier.cpp b/js/src/gc/Barrier.cpp index f19f6f046..6dab8d25b 100644 --- a/js/src/gc/Barrier.cpp +++ b/js/src/gc/Barrier.cpp @@ -56,7 +56,7 @@ HeapSlot::preconditionForWriteBarrierPost(NativeObject* obj, Kind kind, uint32_t bool isCorrectSlot = kind == Slot ? obj->getSlotAddressUnchecked(slot)->get() == target : static_cast<HeapSlot*>(obj->getDenseElements() + slot)->get() == target; - bool isBlackToGray = target.isMarkable() && + bool isBlackToGray = target.isGCThing() && IsMarkedBlack(obj) && JS::GCThingIsMarkedGray(JS::GCCellPtr(target)); return isCorrectSlot && !isBlackToGray; } diff --git a/js/src/gc/Barrier.h b/js/src/gc/Barrier.h index 950c96314..effc9233e 100644 --- a/js/src/gc/Barrier.h +++ b/js/src/gc/Barrier.h @@ -282,7 +282,7 @@ template <typename S> struct ReadBarrierFunctor : public VoidDefaultAdaptor<S> { template <> struct InternalBarrierMethods<Value> { - static bool isMarkable(const Value& v) { return v.isMarkable(); } + static bool isMarkable(const Value& v) { return v.isGCThing(); } static bool isMarkableTaggedPointer(const Value& v) { return isMarkable(v); } static void preBarrier(const Value& v) { diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index d9235f9ac..b2c105999 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -328,7 +328,7 @@ ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, Cell* cell) static bool ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, const Value& val) { - return val.isMarkable() && ShouldMarkCrossCompartment(trc, src, (Cell*)val.toGCThing()); + return val.isGCThing() && ShouldMarkCrossCompartment(trc, src, val.toGCThing()); } static void @@ -1599,7 +1599,7 @@ ObjectDenseElementsMayBeMarkable(NativeObject* nobj) if (!mayBeMarkable) { const Value* elements = nobj->getDenseElementsAllowCopyOnWrite(); for (unsigned i = 0; i < nobj->getDenseInitializedLength(); i++) - MOZ_ASSERT(!elements[i].isMarkable()); + MOZ_ASSERT(!elements[i].isGCThing()); } #endif diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index ec4c69a2f..73f63d804 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -404,7 +404,7 @@ IsAboutToBeFinalizedDuringSweep(TenuredCell& tenured); inline Cell* ToMarkable(const Value& v) { - if (v.isMarkable()) + if (v.isGCThing()) return (Cell*)v.toGCThing(); return nullptr; } diff --git a/js/src/jit/BaselineFrameInfo.h b/js/src/jit/BaselineFrameInfo.h index 13bf0358d..1691270ac 100644 --- a/js/src/jit/BaselineFrameInfo.h +++ b/js/src/jit/BaselineFrameInfo.h @@ -67,7 +67,7 @@ class StackValue union { struct { - Value v; + JS::UninitializedValue v; } constant; struct { mozilla::AlignedStorage2<ValueOperand> reg; @@ -112,7 +112,7 @@ class StackValue } Value constant() const { MOZ_ASSERT(kind_ == Constant); - return data.constant.v; + return data.constant.v.asValueRef(); } ValueOperand reg() const { MOZ_ASSERT(kind_ == Register); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index ccdc5fbfa..7b2f8214b 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8526,8 +8526,8 @@ StoreUnboxedPointer(MacroAssembler& masm, T address, MIRType type, const LAlloca masm.patchableCallPreBarrier(address, type); if (value->isConstant()) { Value v = value->toConstant()->toJSValue(); - if (v.isMarkable()) { - masm.storePtr(ImmGCPtr(v.toMarkablePointer()), address); + if (v.isGCThing()) { + masm.storePtr(ImmGCPtr(v.toGCThing()), address); } else { MOZ_ASSERT(v.isNull()); masm.storePtr(ImmWord(0), address); diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp index 966d952d3..f11f17225 100644 --- a/js/src/jit/JitFrames.cpp +++ b/js/src/jit/JitFrames.cpp @@ -2062,7 +2062,7 @@ SnapshotIterator::traceAllocation(JSTracer* trc) return; Value v = allocationValue(alloc, RM_AlwaysDefault); - if (!v.isMarkable()) + if (!v.isGCThing()) return; Value copy = v; diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp index 7f28a9020..730697163 100644 --- a/js/src/jit/Lowering.cpp +++ b/js/src/jit/Lowering.cpp @@ -2687,7 +2687,7 @@ IsNonNurseryConstant(MDefinition* def) if (!def->isConstant()) return false; Value v = def->toConstant()->toJSValue(); - return !v.isMarkable() || !IsInsideNursery(v.toMarkablePointer()); + return !v.isGCThing() || !IsInsideNursery(v.toGCThing()); } void diff --git a/js/src/jit/MacroAssembler.cpp b/js/src/jit/MacroAssembler.cpp index f633b9b7b..9dbbe7624 100644 --- a/js/src/jit/MacroAssembler.cpp +++ b/js/src/jit/MacroAssembler.cpp @@ -2214,6 +2214,12 @@ MacroAssembler::finish() } MacroAssemblerSpecific::finish(); + + MOZ_RELEASE_ASSERT(size() <= MaxCodeBytesPerProcess, + "AssemblerBuffer should ensure we don't exceed MaxCodeBytesPerProcess"); + + if (bytesNeeded() > MaxCodeBytesPerProcess) + setOOM(); } void diff --git a/js/src/jit/ProcessExecutableMemory.cpp b/js/src/jit/ProcessExecutableMemory.cpp index 71c2ab0dc..301541541 100644 --- a/js/src/jit/ProcessExecutableMemory.cpp +++ b/js/src/jit/ProcessExecutableMemory.cpp @@ -385,14 +385,6 @@ class PageBitSet #endif }; -// Limit on the number of bytes of executable memory to prevent JIT spraying -// attacks. -#if JS_BITS_PER_WORD == 32 -static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; -#else -static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; -#endif - // Per-process executable memory allocator. It reserves a block of memory of // MaxCodeBytesPerProcess bytes, then allocates/deallocates pages from that. // diff --git a/js/src/jit/ProcessExecutableMemory.h b/js/src/jit/ProcessExecutableMemory.h index 078ce7cb7..a0e2fab98 100644 --- a/js/src/jit/ProcessExecutableMemory.h +++ b/js/src/jit/ProcessExecutableMemory.h @@ -17,6 +17,14 @@ namespace jit { // alignment though. static const size_t ExecutableCodePageSize = 64 * 1024; +// Limit on the number of bytes of executable memory to prevent JIT spraying +// attacks. +#if JS_BITS_PER_WORD == 32 +static const size_t MaxCodeBytesPerProcess = 128 * 1024 * 1024; +#else +static const size_t MaxCodeBytesPerProcess = 1 * 1024 * 1024 * 1024; +#endif + enum class ProtectionSetting { Protected, // Not readable, writable, or executable. Writable, diff --git a/js/src/jit/RegisterSets.h b/js/src/jit/RegisterSets.h index 0a4045dd7..08ae53f16 100644 --- a/js/src/jit/RegisterSets.h +++ b/js/src/jit/RegisterSets.h @@ -226,13 +226,13 @@ class ConstantOrRegister // Space to hold either a Value or a TypedOrValueRegister. union U { - Value constant; + JS::UninitializedValue constant; TypedOrValueRegister reg; } data; - const Value& dataValue() const { + Value dataValue() const { MOZ_ASSERT(constant()); - return data.constant; + return data.constant.asValueRef(); } void setDataValue(const Value& value) { MOZ_ASSERT(constant()); @@ -268,7 +268,7 @@ class ConstantOrRegister return constant_; } - const Value& value() const { + Value value() const { return dataValue(); } diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index cb324220c..32fad1267 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -61,9 +61,17 @@ RematerializedFrame::New(JSContext* cx, uint8_t* top, InlineFrameIterator& iter, { unsigned numFormals = iter.isFunctionFrame() ? iter.calleeTemplate()->nargs() : 0; unsigned argSlots = Max(numFormals, iter.numActualArgs()); - size_t numBytes = sizeof(RematerializedFrame) + - (argSlots + iter.script()->nfixed()) * sizeof(Value) - - sizeof(Value); // 1 Value included in sizeof(RematerializedFrame) + unsigned extraSlots = argSlots + iter.script()->nfixed(); + + // One Value slot is included in sizeof(RematerializedFrame), so we can + // reduce the extra slot count by one. However, if there are zero slot + // allocations total, then reducing the slots by one will lead to + // the memory allocation being smaller than sizeof(RematerializedFrame). + if (extraSlots > 0) + extraSlots -= 1; + + size_t numBytes = sizeof(RematerializedFrame) + (extraSlots * sizeof(Value)); + MOZ_ASSERT(numBytes >= sizeof(RematerializedFrame)); void* buf = cx->pod_calloc<uint8_t>(numBytes); if (!buf) diff --git a/js/src/jit/arm/MacroAssembler-arm.cpp b/js/src/jit/arm/MacroAssembler-arm.cpp index c6e627db6..d40578514 100644 --- a/js/src/jit/arm/MacroAssembler-arm.cpp +++ b/js/src/jit/arm/MacroAssembler-arm.cpp @@ -3286,8 +3286,8 @@ void MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data) { ma_mov(Imm32(val.toNunboxTag()), type); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), data); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), data); else ma_mov(Imm32(val.toNunboxPayload()), data); } @@ -3484,8 +3484,8 @@ MacroAssemblerARMCompat::storePayload(const Value& val, const BaseIndex& dest) ScratchRegisterScope scratch(asMasm()); SecondScratchRegisterScope scratch2(asMasm()); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch); else ma_mov(Imm32(val.toNunboxPayload()), scratch); @@ -5314,8 +5314,8 @@ MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs, // equal, short circuit false (NotEqual). ScratchRegisterScope scratch(*this); - if (rhs.isMarkable()) - ma_cmp(lhs.payloadReg(), ImmGCPtr(rhs.toMarkablePointer()), scratch); + if (rhs.isGCThing()) + ma_cmp(lhs.payloadReg(), ImmGCPtr(rhs.toGCThing()), scratch); else ma_cmp(lhs.payloadReg(), Imm32(rhs.toNunboxPayload()), scratch); ma_cmp(lhs.typeReg(), Imm32(rhs.toNunboxTag()), scratch, Equal); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index c011af3c3..c20a6c3e5 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -915,8 +915,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM ma_mov(Imm32(val.toNunboxTag()), scratch); ma_str(scratch, ToType(dest), scratch2); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch); else ma_mov(Imm32(val.toNunboxPayload()), scratch); ma_str(scratch, ToPayload(dest), scratch2); @@ -944,15 +944,15 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM // Store the payload, marking if necessary. if (payloadoffset < 4096 && payloadoffset > -4096) { - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch2); else ma_mov(Imm32(val.toNunboxPayload()), scratch2); ma_str(scratch2, DTRAddr(scratch, DtrOffImm(payloadoffset))); } else { ma_add(Imm32(payloadoffset), scratch, scratch2); - if (val.isMarkable()) - ma_mov(ImmGCPtr(val.toMarkablePointer()), scratch2); + if (val.isGCThing()) + ma_mov(ImmGCPtr(val.toGCThing()), scratch2); else ma_mov(Imm32(val.toNunboxPayload()), scratch2); ma_str(scratch2, DTRAddr(scratch, DtrOffImm(0))); @@ -977,8 +977,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM void popValue(ValueOperand val); void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index b95831443..c21e2fd66 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -306,7 +306,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler void pushValue(const Value& val) { vixl::UseScratchRegisterScope temps(this); const Register scratch = temps.AcquireX().asUnsized(); - if (val.isMarkable()) { + if (val.isGCThing()) { BufferOffset load = movePatchablePtr(ImmPtr(val.bitsAsPunboxPointer()), scratch); writeDataRelocation(val, load); push(scratch); @@ -349,7 +349,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler } } void moveValue(const Value& val, Register dest) { - if (val.isMarkable()) { + if (val.isGCThing()) { BufferOffset load = movePatchablePtr(ImmPtr(val.bitsAsPunboxPointer()), dest); writeDataRelocation(val, load); } else { @@ -1835,8 +1835,8 @@ class MacroAssemblerCompat : public vixl::MacroAssembler dataRelocations_.writeUnsigned(load.getOffset()); } void writeDataRelocation(const Value& val, BufferOffset load) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(load.getOffset()); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.cpp b/js/src/jit/mips32/MacroAssembler-mips32.cpp index 0d3e55e21..2b2fab92d 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.cpp +++ b/js/src/jit/mips32/MacroAssembler-mips32.cpp @@ -1527,8 +1527,8 @@ MacroAssemblerMIPSCompat::getType(const Value& val) void MacroAssemblerMIPSCompat::moveData(const Value& val, Register data) { - if (val.isMarkable()) - ma_li(data, ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + ma_li(data, ImmGCPtr(val.toGCThing())); else ma_li(data, Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index 4c7618d08..adb626bb0 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -480,8 +480,8 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS void popValue(ValueOperand val); void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } diff --git a/js/src/jit/mips64/MacroAssembler-mips64.cpp b/js/src/jit/mips64/MacroAssembler-mips64.cpp index 329fa83f8..f58184bca 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.cpp +++ b/js/src/jit/mips64/MacroAssembler-mips64.cpp @@ -1885,7 +1885,7 @@ MacroAssemblerMIPS64Compat::storeValue(JSValueType type, Register reg, Address d void MacroAssemblerMIPS64Compat::storeValue(const Value& val, Address dest) { - if (val.isMarkable()) { + if (val.isGCThing()) { writeDataRelocation(val); movWithPatch(ImmWord(val.asRawBits()), SecondScratchReg); } else { diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 4cff87236..bfe452974 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -221,8 +221,8 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 } void writeDataRelocation(const Value& val) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(currentOffset()); @@ -498,7 +498,7 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 void pushValue(ValueOperand val); void popValue(ValueOperand val); void pushValue(const Value& val) { - if (val.isMarkable()) { + if (val.isGCThing()) { writeDataRelocation(val); movWithPatch(ImmWord(val.asRawBits()), ScratchRegister); push(ScratchRegister); diff --git a/js/src/jit/shared/IonAssemblerBuffer.h b/js/src/jit/shared/IonAssemblerBuffer.h index cc20e26d2..3a6552696 100644 --- a/js/src/jit/shared/IonAssemblerBuffer.h +++ b/js/src/jit/shared/IonAssemblerBuffer.h @@ -181,6 +181,10 @@ class AssemblerBuffer protected: virtual Slice* newSlice(LifoAlloc& a) { + if (size() > MaxCodeBytesPerProcess - sizeof(Slice)) { + fail_oom(); + return nullptr; + } Slice* tmp = static_cast<Slice*>(a.alloc(sizeof(Slice))); if (!tmp) { fail_oom(); diff --git a/js/src/jit/x64/MacroAssembler-x64.h b/js/src/jit/x64/MacroAssembler-x64.h index cb81bd7c1..be450767b 100644 --- a/js/src/jit/x64/MacroAssembler-x64.h +++ b/js/src/jit/x64/MacroAssembler-x64.h @@ -58,8 +58,8 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared // X64 helpers. ///////////////////////////////////////////////////////////////// void writeDataRelocation(const Value& val) { - if (val.isMarkable()) { - gc::Cell* cell = val.toMarkablePointer(); + if (val.isGCThing()) { + gc::Cell* cell = val.toGCThing(); if (cell && gc::IsInsideNursery(cell)) embedsNurseryPointers_ = true; dataRelocations_.writeUnsigned(masm.currentOffset()); @@ -132,7 +132,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared template <typename T> void storeValue(const Value& val, const T& dest) { ScratchRegisterScope scratch(asMasm()); - if (val.isMarkable()) { + if (val.isGCThing()) { movWithPatch(ImmWord(val.asRawBits()), scratch); writeDataRelocation(val); } else { @@ -171,7 +171,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared pop(val.valueReg()); } void pushValue(const Value& val) { - if (val.isMarkable()) { + if (val.isGCThing()) { ScratchRegisterScope scratch(asMasm()); movWithPatch(ImmWord(val.asRawBits()), scratch); writeDataRelocation(val); diff --git a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h index 8cb557784..fe678fc7d 100644 --- a/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h +++ b/js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h @@ -68,6 +68,33 @@ namespace js { namespace jit { + // AllocPolicy for AssemblerBuffer. OOMs when trying to allocate more than + // MaxCodeBytesPerProcess bytes. Use private inheritance to make sure we + // explicitly have to expose SystemAllocPolicy methods. + class AssemblerBufferAllocPolicy : private SystemAllocPolicy + { + public: + using SystemAllocPolicy::checkSimulatedOOM; + using SystemAllocPolicy::reportAllocOverflow; + using SystemAllocPolicy::free_; + + template <typename T> T* pod_realloc(T* p, size_t oldSize, size_t newSize) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + MOZ_ASSERT(oldSize <= MaxCodeBytesPerProcess); + if (MOZ_UNLIKELY(newSize > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_realloc<T>(p, oldSize, newSize); + } + template <typename T> T* pod_malloc(size_t numElems) { + static_assert(sizeof(T) == 1, + "AssemblerBufferAllocPolicy should only be used with byte vectors"); + if (MOZ_UNLIKELY(numElems > MaxCodeBytesPerProcess)) + return nullptr; + return SystemAllocPolicy::pod_malloc<T>(numElems); + } + }; + class AssemblerBuffer { template<size_t size, typename T> @@ -93,6 +120,9 @@ namespace jit { void ensureSpace(size_t space) { + // This should only be called with small |space| values to ensure + // we don't overflow below. + MOZ_ASSERT(space <= 16); if (MOZ_UNLIKELY(!m_buffer.reserve(m_buffer.length() + space))) oomDetected(); } @@ -168,7 +198,7 @@ namespace jit { m_buffer.clear(); } - PageProtectingVector<unsigned char, 256, SystemAllocPolicy> m_buffer; + PageProtectingVector<unsigned char, 256, AssemblerBufferAllocPolicy> m_buffer; bool m_oom; }; diff --git a/js/src/jit/x86/MacroAssembler-x86.cpp b/js/src/jit/x86/MacroAssembler-x86.cpp index 754b29c2d..dc97b5b5b 100644 --- a/js/src/jit/x86/MacroAssembler-x86.cpp +++ b/js/src/jit/x86/MacroAssembler-x86.cpp @@ -499,8 +499,8 @@ MacroAssembler::branchTestValue(Condition cond, const ValueOperand& lhs, const Value& rhs, Label* label) { MOZ_ASSERT(cond == Equal || cond == NotEqual); - if (rhs.isMarkable()) - cmpPtr(lhs.payloadReg(), ImmGCPtr(rhs.toMarkablePointer())); + if (rhs.isGCThing()) + cmpPtr(lhs.payloadReg(), ImmGCPtr(rhs.toGCThing())); else cmpPtr(lhs.payloadReg(), ImmWord(rhs.toNunboxPayload())); diff --git a/js/src/jit/x86/MacroAssembler-x86.h b/js/src/jit/x86/MacroAssembler-x86.h index 21cd63a0c..2b2507c77 100644 --- a/js/src/jit/x86/MacroAssembler-x86.h +++ b/js/src/jit/x86/MacroAssembler-x86.h @@ -94,8 +94,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } void moveValue(const Value& val, Register type, Register data) { movl(Imm32(val.toNunboxTag()), type); - if (val.isMarkable()) - movl(ImmGCPtr(val.toMarkablePointer()), data); + if (val.isGCThing()) + movl(ImmGCPtr(val.toGCThing()), data); else movl(Imm32(val.toNunboxPayload()), data); } @@ -213,8 +213,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared } void pushValue(const Value& val) { push(Imm32(val.toNunboxTag())); - if (val.isMarkable()) - push(ImmGCPtr(val.toMarkablePointer())); + if (val.isGCThing()) + push(ImmGCPtr(val.toGCThing())); else push(Imm32(val.toNunboxPayload())); } @@ -235,8 +235,8 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared pop(dest.high); } void storePayload(const Value& val, Operand dest) { - if (val.isMarkable()) - movl(ImmGCPtr(val.toMarkablePointer()), ToPayload(dest)); + if (val.isGCThing()) + movl(ImmGCPtr(val.toGCThing()), ToPayload(dest)); else movl(Imm32(val.toNunboxPayload()), ToPayload(dest)); } diff --git a/js/src/js.msg b/js/src/js.msg index 8d492f523..a276dab94 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -474,6 +474,8 @@ MSG_DEF(JSMSG_INTL_OBJECT_NOT_INITED, 3, JSEXN_TYPEERR, "Intl.{0}.prototype.{1} MSG_DEF(JSMSG_INTL_OBJECT_REINITED, 0, JSEXN_TYPEERR, "can't initialize object twice as an object of an Intl constructor") MSG_DEF(JSMSG_INVALID_CURRENCY_CODE, 1, JSEXN_RANGEERR, "invalid currency code in NumberFormat(): {0}") MSG_DEF(JSMSG_INVALID_DIGITS_VALUE, 1, JSEXN_RANGEERR, "invalid digits value: {0}") +MSG_DEF(JSMSG_INVALID_KEYS_TYPE, 0, JSEXN_TYPEERR, "calendar info keys must be an object or undefined") +MSG_DEF(JSMSG_INVALID_KEY, 1, JSEXN_RANGEERR, "invalid key: {0}") MSG_DEF(JSMSG_INVALID_LANGUAGE_TAG, 1, JSEXN_RANGEERR, "invalid language tag: {0}") MSG_DEF(JSMSG_INVALID_LOCALES_ELEMENT, 0, JSEXN_TYPEERR, "invalid element in locales argument") MSG_DEF(JSMSG_INVALID_LOCALE_MATCHER, 1, JSEXN_RANGEERR, "invalid locale matcher in supportedLocalesOf(): {0}") diff --git a/js/src/jscompartmentinlines.h b/js/src/jscompartmentinlines.h index 08d315db0..6a54bc5a6 100644 --- a/js/src/jscompartmentinlines.h +++ b/js/src/jscompartmentinlines.h @@ -61,7 +61,7 @@ inline bool JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp) { /* Only GC things have to be wrapped or copied. */ - if (!vp.isMarkable()) + if (!vp.isGCThing()) return true; /* diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index ccaeda2a3..00a8abf84 100755 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -354,10 +354,22 @@ MakeDate(double day, double time) JS_PUBLIC_API(double) JS::MakeDate(double year, unsigned month, unsigned day) { + MOZ_ASSERT(month <= 11); + MOZ_ASSERT(day >= 1 && day <= 31); + return ::MakeDate(MakeDay(year, month, day), 0); } JS_PUBLIC_API(double) +JS::MakeDate(double year, unsigned month, unsigned day, double time) +{ + MOZ_ASSERT(month <= 11); + MOZ_ASSERT(day >= 1 && day <= 31); + + return ::MakeDate(MakeDay(year, month, day), time); +} + +JS_PUBLIC_API(double) JS::YearFromTime(double time) { return ::YearFromTime(time); diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index b1c7cb0dc..722085549 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -761,7 +761,7 @@ SetReservedSlot(JSObject* obj, size_t slot, const JS::Value& value) { MOZ_ASSERT(slot < JSCLASS_RESERVED_SLOTS(GetObjectClass(obj))); shadow::Object* sobj = reinterpret_cast<shadow::Object*>(obj); - if (sobj->slotRef(slot).isMarkable() || value.isMarkable()) + if (sobj->slotRef(slot).isGCThing() || value.isGCThing()) SetReservedOrProxyPrivateSlotWithBarrier(obj, slot, value); else sobj->slotRef(slot) = value; diff --git a/js/src/jsfun.h b/js/src/jsfun.h index d45d112a5..7da831aa2 100644 --- a/js/src/jsfun.h +++ b/js/src/jsfun.h @@ -830,7 +830,7 @@ inline void JSFunction::setExtendedSlot(size_t which, const js::Value& val) { MOZ_ASSERT(which < mozilla::ArrayLength(toExtended()->extendedSlots)); - MOZ_ASSERT_IF(js::IsMarkedBlack(this) && val.isMarkable(), + MOZ_ASSERT_IF(js::IsMarkedBlack(this) && val.isGCThing(), !JS::GCThingIsMarkedGray(JS::GCCellPtr(val))); toExtended()->extendedSlots[which] = val; } diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index e86ceab3d..9f914943e 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -3309,7 +3309,7 @@ js::detail::CopyScript(JSContext* cx, HandleScript src, HandleScript dst, GCPtrValue* vector = Rebase<GCPtrValue>(dst, src, src->consts()->vector); dst->consts()->vector = vector; for (unsigned i = 0; i < nconsts; ++i) - MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom()); + MOZ_ASSERT_IF(vector[i].isGCThing(), vector[i].toString()->isAtom()); } if (nobjects != 0) { GCPtrObject* vector = Rebase<GCPtrObject>(dst, src, src->objects()->vector); diff --git a/js/src/jsstr.h b/js/src/jsstr.h index 3b92aa21b..7e9621d4a 100644 --- a/js/src/jsstr.h +++ b/js/src/jsstr.h @@ -9,6 +9,7 @@ #include "mozilla/HashFunctions.h" #include "mozilla/PodOperations.h" +#include "mozilla/TextUtils.h" #include <stdio.h> @@ -95,7 +96,7 @@ struct JSSubString { #define JS7_UNOCT(c) (JS7_UNDEC(c)) #define JS7_ISHEX(c) ((c) < 128 && isxdigit(c)) #define JS7_UNHEX(c) (unsigned)(JS7_ISDEC(c) ? (c) - '0' : 10 + tolower(c) - 'a') -#define JS7_ISLET(c) ((c) < 128 && isalpha(c)) +#define JS7_ISLET(c) (mozilla::IsAsciiAlpha(c)) extern size_t js_strlen(const char16_t* s); diff --git a/js/src/jstypes.h b/js/src/jstypes.h index 6593d2067..75774e5b8 100644 --- a/js/src/jstypes.h +++ b/js/src/jstypes.h @@ -160,10 +160,6 @@ # if defined(__64BIT__) # define JS_64BIT # endif -#elif defined(__HP_cc) || defined(__HP_aCC) /* HP-UX cc/aCC */ -# if defined(__LP64__) -# define JS_64BIT -# endif #else # error "Implement me" #endif diff --git a/js/src/make-source-package.sh b/js/src/make-source-package.sh index 6e44dd977..e6d3f6df5 100755 --- a/js/src/make-source-package.sh +++ b/js/src/make-source-package.sh @@ -151,7 +151,6 @@ case $cmd in ${TOPSRCDIR}/memory/moz.build \ ${TOPSRCDIR}/memory/build \ ${TOPSRCDIR}/memory/fallible \ - ${TOPSRCDIR}/memory/jemalloc \ ${TOPSRCDIR}/memory/mozalloc \ ${TOPSRCDIR}/memory/mozjemalloc \ ${tgtpath}/memory diff --git a/js/src/moz.build b/js/src/moz.build index a18170a75..2d4e83db3 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -708,7 +708,7 @@ if CONFIG['_MSC_VER']: CXXFLAGS += ['-wd4577'] CXXFLAGS += ['-wd4312'] -if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'): +if CONFIG['OS_ARCH'] not in ('WINNT'): OS_LIBS += [ 'm', ] diff --git a/js/src/old-configure.in b/js/src/old-configure.in index 5da81ce3e..162a071d7 100644 --- a/js/src/old-configure.in +++ b/js/src/old-configure.in @@ -1534,6 +1534,14 @@ MOZ_ARG_ENABLE_STRING(ui-locale, AC_SUBST(MOZ_UI_LOCALE) dnl ======================================================== +dnl Build the tests? +dnl ======================================================== +MOZ_ARG_ENABLE_BOOL(tests, +[ --enable-tests Build test libraries & programs], + ENABLE_TESTS=1, + ENABLE_TESTS= ) + +dnl ======================================================== dnl = dnl = Module specific options dnl = @@ -2091,6 +2099,8 @@ AC_SUBST(MOZ_DEBUG_LDFLAGS) AC_SUBST(WARNINGS_AS_ERRORS) AC_SUBST(LIBICONV) +AC_SUBST(ENABLE_TESTS) + AC_SUBST(ENABLE_STRIP) AC_SUBST(PKG_SKIP_STRIP) AC_SUBST(INCREMENTAL_LINKER) @@ -2106,6 +2116,7 @@ AC_SUBST(MOZ_APP_VERSION) AC_SUBST(MOZ_PKG_SPECIAL) AC_SUBST(MOZILLA_OFFICIAL) +AC_SUBST(MC_OFFICIAL) dnl ======================================================== dnl ECMAScript Internationalization API Support (uses ICU) @@ -2243,8 +2254,6 @@ AC_SUBST(JS_LIBRARY_NAME) AC_SUBST(JS_CONFIG_MOZ_JS_LIBS) AC_SUBST(JS_CONFIG_LIBS) -MOZ_SUBCONFIGURE_JEMALLOC() - # Avoid using obsolete NSPR features AC_DEFINE(NO_NSPR_10_SUPPORT) diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index cc68c90d5..8d69ca942 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -906,6 +906,7 @@ AddIntlExtras(JSContext* cx, unsigned argc, Value* vp) static const JSFunctionSpec funcs[] = { JS_SELF_HOSTED_FN("getCalendarInfo", "Intl_getCalendarInfo", 1, 0), + JS_SELF_HOSTED_FN("getDisplayNames", "Intl_getDisplayNames", 2, 0), JS_FS_END }; diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js index 890b1c1d5..7b3a46a60 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js index 19fd871eb..ed63df921 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js index 34425acec..215808765 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js index 8b2dedec2..48242dfbd 100644 --- a/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js +++ b/js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js @@ -1,7 +1,7 @@ // |reftest| skip-if(!this.hasOwnProperty("Intl")) // Generated by make_intl_data.py. DO NOT EDIT. -// tzdata version = 2018c +// tzdata version = 2018d const tzMapper = [ x => x, diff --git a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js b/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js deleted file mode 100644 index f5f5b62a8..000000000 --- a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js +++ /dev/null @@ -1,27 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")||!this.hasOwnProperty("addIntlExtras")) - -// Tests the PluralRules.resolvedOptions function for overriden Array[Symbol.species]. - -addIntlExtras(Intl); - -var pl = new Intl.PluralRules("de"); - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var pluralCategories = pl.resolvedOptions().pluralCategories; - -assertEqArray(pluralCategories, ["one", "other"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js b/js/src/tests/Intl/getCanonicalLocales-overridden-species.js deleted file mode 100644 index 858735b58..000000000 --- a/js/src/tests/Intl/getCanonicalLocales-overridden-species.js +++ /dev/null @@ -1,23 +0,0 @@ -// |reftest| skip-if(!this.hasOwnProperty("Intl")) - -// Tests the getCanonicalLocales function for overriden Array[Symbol.species]. - -Object.defineProperty(Array, Symbol.species, { - value: function() { - return new Proxy(["?"], { - get(t, pk, r) { - return Reflect.get(t, pk, r); - }, - defineProperty(t, pk) { - return true; - } - }); - } -}); - -var arr = Intl.getCanonicalLocales("de-x-private"); - -assertEqArray(arr, ["de-x-private"]); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/Intl/getDisplayNames.js b/js/src/tests/Intl/getDisplayNames.js new file mode 100644 index 000000000..ad2dbc940 --- /dev/null +++ b/js/src/tests/Intl/getDisplayNames.js @@ -0,0 +1,238 @@ +// |reftest| skip-if(!this.hasOwnProperty('Intl')||!this.hasOwnProperty('addIntlExtras')) +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +// Tests the getCalendarInfo function with a diverse set of arguments. + +/* + * Test if getDisplayNames return value matches expected values. + */ +function checkDisplayNames(names, expected) +{ + assertEq(Object.getPrototypeOf(names), Object.prototype); + + assertEq(names.locale, expected.locale); + assertEq(names.style, expected.style); + + const nameValues = names.values; + const expectedValues = expected.values; + + const nameValuesKeys = Object.getOwnPropertyNames(nameValues).sort(); + const expectedValuesKeys = Object.getOwnPropertyNames(expectedValues).sort(); + + assertEqArray(nameValuesKeys, expectedValuesKeys); + + for (let key of expectedValuesKeys) + assertEq(nameValues[key], expectedValues[key]); +} + +addIntlExtras(Intl); + +let gDN = Intl.getDisplayNames; + +assertEq(gDN.length, 2); + +checkDisplayNames(gDN('en-US', { +}), { + locale: 'en-US', + style: 'long', + values: {} +}); + +checkDisplayNames(gDN('en-US', { + keys: [ + 'dates/gregorian/weekdays/wednesday' + ], + style: 'narrow' +}), { + locale: 'en-US', + style: 'narrow', + values: { + 'dates/gregorian/weekdays/wednesday': 'W' + } +}); + +checkDisplayNames(gDN('en-US', { + keys: [ + 'dates/fields/year', + 'dates/fields/month', + 'dates/fields/week', + 'dates/fields/day', + 'dates/gregorian/months/january', + 'dates/gregorian/months/february', + 'dates/gregorian/months/march', + 'dates/gregorian/weekdays/tuesday' + ] +}), { + locale: 'en-US', + style: 'long', + values: { + 'dates/fields/year': 'year', + 'dates/fields/month': 'month', + 'dates/fields/week': 'week', + 'dates/fields/day': 'day', + 'dates/gregorian/months/january': 'January', + 'dates/gregorian/months/february': 'February', + 'dates/gregorian/months/march': 'March', + 'dates/gregorian/weekdays/tuesday': 'Tuesday', + } +}); + +checkDisplayNames(gDN('fr', { + keys: [ + 'dates/fields/year', + 'dates/fields/day', + 'dates/gregorian/months/october', + 'dates/gregorian/weekdays/saturday', + 'dates/gregorian/dayperiods/pm' + ] +}), { + locale: 'fr', + style: 'long', + values: { + 'dates/fields/year': 'année', + 'dates/fields/day': 'jour', + 'dates/gregorian/months/october': 'octobre', + 'dates/gregorian/weekdays/saturday': 'samedi', + 'dates/gregorian/dayperiods/pm': 'PM' + } +}); + +checkDisplayNames(gDN('it', { + style: 'short', + keys: [ + 'dates/gregorian/weekdays/thursday', + 'dates/gregorian/months/august', + 'dates/gregorian/dayperiods/am', + 'dates/fields/month', + ] +}), { + locale: 'it', + style: 'short', + values: { + 'dates/gregorian/weekdays/thursday': 'gio', + 'dates/gregorian/months/august': 'ago', + 'dates/gregorian/dayperiods/am': 'AM', + 'dates/fields/month': 'mese' + } +}); + +checkDisplayNames(gDN('ar', { + style: 'long', + keys: [ + 'dates/gregorian/weekdays/thursday', + 'dates/gregorian/months/august', + 'dates/gregorian/dayperiods/am', + 'dates/fields/month', + ] +}), { + locale: 'ar', + style: 'long', + values: { + 'dates/gregorian/weekdays/thursday': 'الخميس', + 'dates/gregorian/months/august': 'أغسطس', + 'dates/gregorian/dayperiods/am': 'ص', + 'dates/fields/month': 'الشهر' + } +}); + +/* Invalid input */ + +assertThrowsInstanceOf(() => { + gDN('en-US', { + style: '', + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +assertThrowsInstanceOf(() => { + gDN('en-US', { + style: 'bogus', + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +assertThrowsInstanceOf(() => { + gDN('foo-X', { + keys: [ + 'dates/gregorian/weekdays/thursday', + ] + }); +}, RangeError); + +const typeErrorKeys = [ + null, + 'string', + Symbol.iterator, + 15, + 1, + 3.7, + NaN, + Infinity +]; + +for (let keys of typeErrorKeys) { + assertThrowsInstanceOf(() => { + gDN('en-US', { + keys + }); + }, TypeError); +} + +const rangeErrorKeys = [ + [''], + ['foo'], + ['dates/foo'], + ['/dates/foo'], + ['dates/foo/foo'], + ['dates/fields'], + ['dates/fields/'], + ['dates/fields/foo'], + ['dates/fields/foo/month'], + ['/dates/foo/faa/bar/baz'], + ['dates///bar/baz'], + ['dates/gregorian'], + ['dates/gregorian/'], + ['dates/gregorian/foo'], + ['dates/gregorian/months'], + ['dates/gregorian/months/foo'], + ['dates/gregorian/weekdays'], + ['dates/gregorian/weekdays/foo'], + ['dates/gregorian/dayperiods'], + ['dates/gregorian/dayperiods/foo'], + ['dates/gregorian/months/الشهر'], + [3], + [null], + ['d', 'a', 't', 'e', 's'], + ['datesEXTRA'], + ['dates/fieldsEXTRA'], + ['dates/gregorianEXTRA'], + ['dates/gregorian/monthsEXTRA'], + ['dates/gregorian/weekdaysEXTRA'], + ['dates/fields/dayperiods/amEXTRA'], + ['dates/gregori\u1161n/months/january'], + ["dates/fields/year/"], + ["dates/fields/month/"], + ["dates/fields/week/"], + ["dates/fields/day/"], + ["dates/gregorian/months/january/"], + ["dates/gregorian/weekdays/saturday/"], + ["dates/gregorian/dayperiods/am/"], + ["dates/fields/months/january/"], +]; + +for (let keys of rangeErrorKeys) { + assertThrowsInstanceOf(() => { + gDN('en-US', { + keys + }); + }, RangeError); +} + +if (typeof reportCompare === 'function') + reportCompare(0, 0); diff --git a/js/src/threading/windows/ConditionVariable.cpp b/js/src/threading/windows/ConditionVariable.cpp index 3c75a0f27..92e0249b7 100644 --- a/js/src/threading/windows/ConditionVariable.cpp +++ b/js/src/threading/windows/ConditionVariable.cpp @@ -54,8 +54,8 @@ js::ConditionVariable::notify_all() void js::ConditionVariable::wait(UniqueLock<Mutex>& lock) { - CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; - bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE); + SRWLOCK* srwlock = &lock.lock.platformData()->lock; + bool r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, INFINITE, 0); MOZ_RELEASE_ASSERT(r); } @@ -70,7 +70,7 @@ js::CVStatus js::ConditionVariable::wait_for(UniqueLock<Mutex>& lock, const mozilla::TimeDuration& rel_time) { - CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection; + SRWLOCK* srwlock = &lock.lock.platformData()->lock; // Note that DWORD is unsigned, so we have to be careful to clamp at 0. // If rel_time is Forever, then ToMilliseconds is +inf, which evaluates as @@ -82,7 +82,7 @@ js::ConditionVariable::wait_for(UniqueLock<Mutex>& lock, ? INFINITE : static_cast<DWORD>(msecd); - BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec); + BOOL r = SleepConditionVariableSRW(&platformData()->cv_, srwlock, msec, 0); if (r) return CVStatus::NoTimeout; MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT); diff --git a/js/src/threading/windows/MutexImpl.cpp b/js/src/threading/windows/MutexImpl.cpp index 385d1c8de..e838459b5 100644 --- a/js/src/threading/windows/MutexImpl.cpp +++ b/js/src/threading/windows/MutexImpl.cpp @@ -13,35 +13,6 @@ #include "threading/Mutex.h" #include "threading/windows/MutexPlatformData.h" -namespace { - -// We build with a toolkit that supports WinXP, so we have to probe -// for modern features at runtime. This is necessary because Vista and -// later automatically allocate and subsequently leak a debug info -// object for each critical section that we allocate unless we tell it -// not to. In order to tell it not to, we need the extra flags field -// provided by the Ex version of InitializeCriticalSection. -struct MutexNativeImports -{ - using InitializeCriticalSectionExT = BOOL (WINAPI*)(CRITICAL_SECTION*, DWORD, DWORD); - InitializeCriticalSectionExT InitializeCriticalSectionEx; - - MutexNativeImports() { - HMODULE kernel32_dll = GetModuleHandle("kernel32.dll"); - MOZ_RELEASE_ASSERT(kernel32_dll != NULL); - InitializeCriticalSectionEx = reinterpret_cast<InitializeCriticalSectionExT>( - GetProcAddress(kernel32_dll, "InitializeCriticalSectionEx")); - } - - bool hasInitializeCriticalSectionEx() const { - return InitializeCriticalSectionEx; - } -}; - -static MutexNativeImports NativeImports; - -} // (anonymous namespace) - js::detail::MutexImpl::MutexImpl() { AutoEnterOOMUnsafeRegion oom; @@ -49,18 +20,7 @@ js::detail::MutexImpl::MutexImpl() if (!platformData_) oom.crash("js::Mutex::Mutex"); - // This number was adopted from NSPR. - const static DWORD LockSpinCount = 1500; - BOOL r; - if (NativeImports.hasInitializeCriticalSectionEx()) { - r = NativeImports.InitializeCriticalSectionEx(&platformData()->criticalSection, - LockSpinCount, - CRITICAL_SECTION_NO_DEBUG_INFO); - } else { - r = InitializeCriticalSectionAndSpinCount(&platformData()->criticalSection, - LockSpinCount); - } - MOZ_RELEASE_ASSERT(r); + InitializeSRWLock(&platformData()->lock); } js::detail::MutexImpl::~MutexImpl() @@ -68,18 +28,17 @@ js::detail::MutexImpl::~MutexImpl() if (!platformData_) return; - DeleteCriticalSection(&platformData()->criticalSection); js_delete(platformData()); } void js::detail::MutexImpl::lock() { - EnterCriticalSection(&platformData()->criticalSection); + AcquireSRWLockExclusive(&platformData()->lock); } void js::detail::MutexImpl::unlock() { - LeaveCriticalSection(&platformData()->criticalSection); + ReleaseSRWLockExclusive(&platformData()->lock); } diff --git a/js/src/threading/windows/MutexPlatformData.h b/js/src/threading/windows/MutexPlatformData.h index fbe7fc80d..1d741c5d0 100644 --- a/js/src/threading/windows/MutexPlatformData.h +++ b/js/src/threading/windows/MutexPlatformData.h @@ -13,7 +13,7 @@ struct js::detail::MutexImpl::PlatformData { - CRITICAL_SECTION criticalSection; + SRWLOCK lock; }; #endif // platform_win_MutexPlatformData_h diff --git a/js/src/vm/ProxyObject.cpp b/js/src/vm/ProxyObject.cpp index 49ed5a624..69b4cd952 100644 --- a/js/src/vm/ProxyObject.cpp +++ b/js/src/vm/ProxyObject.cpp @@ -45,7 +45,7 @@ ProxyObject::New(JSContext* cx, const BaseProxyHandler* handler, HandleValue pri // wrappee. Prefer to allocate in the nursery, when possible. NewObjectKind newKind = NurseryAllocatedProxy; if (options.singleton()) { - MOZ_ASSERT(priv.isGCThing() && priv.toGCThing()->isTenured()); + MOZ_ASSERT(priv.isNull() || (priv.isGCThing() && priv.toGCThing()->isTenured())); newKind = SingletonObject; } else if ((priv.isGCThing() && priv.toGCThing()->isTenured()) || !handler->canNurseryAllocate() || diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index bf49f2268..9a8ec7679 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2477,6 +2477,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2,0), JS_FN("intl_FormatNumber", intl_FormatNumber, 2,0), JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1,0), + JS_FN("intl_ComputeDisplayNames", intl_ComputeDisplayNames, 3,0), JS_FN("intl_IsValidTimeZoneName", intl_IsValidTimeZoneName, 1,0), JS_FN("intl_NumberFormat", intl_NumberFormat, 2,0), JS_FN("intl_NumberFormat_availableLocales", intl_NumberFormat_availableLocales, 0,0), diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index b4f41c3d5..7fade24fb 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -857,7 +857,7 @@ class NumLit private: Which which_; union { - Value scalar_; + JS::UninitializedValue scalar_; SimdConstant simd_; } u; @@ -880,7 +880,7 @@ class NumLit int32_t toInt32() const { MOZ_ASSERT(which_ == Fixnum || which_ == NegativeInt || which_ == BigUnsigned); - return u.scalar_.toInt32(); + return u.scalar_.asValueRef().toInt32(); } uint32_t toUint32() const { @@ -889,17 +889,17 @@ class NumLit RawF64 toDouble() const { MOZ_ASSERT(which_ == Double); - return RawF64(u.scalar_.toDouble()); + return RawF64(u.scalar_.asValueRef().toDouble()); } RawF32 toFloat() const { MOZ_ASSERT(which_ == Float); - return RawF32(float(u.scalar_.toDouble())); + return RawF32(float(u.scalar_.asValueRef().toDouble())); } Value scalarValue() const { MOZ_ASSERT(which_ != OutOfRangeInt); - return u.scalar_; + return u.scalar_.asValueRef(); } bool isSimd() const diff --git a/js/xpconnect/src/ExportHelpers.cpp b/js/xpconnect/src/ExportHelpers.cpp index 3dbf83e3b..e574e708c 100644 --- a/js/xpconnect/src/ExportHelpers.cpp +++ b/js/xpconnect/src/ExportHelpers.cpp @@ -329,11 +329,20 @@ NewFunctionForwarder(JSContext* cx, HandleId idArg, HandleObject callable, if (id == JSID_VOIDHANDLE) id = GetJSIDByIndex(cx, XPCJSContext::IDX_EMPTYSTRING); + // If our callable is a (possibly wrapped) function, we can give + // the exported thing the right number of args. + unsigned nargs = 0; + RootedObject unwrapped(cx, js::UncheckedUnwrap(callable)); + if (unwrapped) { + if (JSFunction* fun = JS_GetObjectFunction(unwrapped)) + nargs = JS_GetFunctionArity(fun); + } + // We have no way of knowing whether the underlying function wants to be a // constructor or not, so we just mark all forwarders as constructors, and // let the underlying function throw for construct calls if it wants. JSFunction* fun = js::NewFunctionByIdWithReserved(cx, FunctionForwarder, - 0, JSFUN_CONSTRUCTOR, id); + nargs, JSFUN_CONSTRUCTOR, id); if (!fun) return false; diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index bedb7c650..8862bca32 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -59,14 +59,6 @@ #include "nsIXULRuntime.h" #include "nsJSPrincipals.h" -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#endif - -#if defined(MOZ_JEMALLOC4) -#include "mozmemory.h" -#endif - #ifdef XP_WIN #include <windows.h> #endif @@ -151,18 +143,6 @@ public: mActive = false; } } else { -#if defined(MOZ_JEMALLOC4) - if (mPurge) { - /* Jemalloc purges dirty pages regularly during free() when the - * ratio of dirty pages compared to active pages is higher than - * 1 << lg_dirty_mult. A high ratio can have an impact on - * performance, so we use the default ratio of 8, but force a - * regular purge of all remaining dirty pages, after cycle - * collection. */ - Telemetry::AutoTimer<Telemetry::MEMORY_FREE_PURGED_PAGES_MS> timer; - jemalloc_free_dirty_pages(); - } -#endif mActive = false; } return NS_OK; @@ -709,11 +689,6 @@ XPCJSContext::GCSliceCallback(JSContext* cx, if (!self) return; -#ifdef MOZ_CRASHREPORTER - CrashReporter::SetGarbageCollecting(progress == JS::GC_CYCLE_BEGIN || - progress == JS::GC_SLICE_BEGIN); -#endif - if (self->mPrevGCSliceCallback) (*self->mPrevGCSliceCallback)(cx, progress, desc); } diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index d9629bfed..45d00d390 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -59,11 +59,6 @@ #include <unistd.h> /* for isatty() */ #endif -#ifdef MOZ_CRASHREPORTER -#include "nsExceptionHandler.h" -#include "nsICrashReporter.h" -#endif - using namespace mozilla; using namespace JS; using mozilla::dom::AutoJSAPI; @@ -1372,18 +1367,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp, argv += 2; } -#ifdef MOZ_CRASHREPORTER - const char* val = getenv("MOZ_CRASHREPORTER"); - if (val && *val) { - rv = CrashReporter::SetExceptionHandler(greDir, true); - if (NS_FAILED(rv)) { - printf("CrashReporter::SetExceptionHandler failed!\n"); - return 1; - } - MOZ_ASSERT(CrashReporter::GetEnabled()); - } -#endif - { if (argc > 1 && !strcmp(argv[1], "--greomni")) { nsCOMPtr<nsIFile> greOmni; @@ -1603,12 +1586,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp, dirprovider.ClearPluginDir(); dirprovider.ClearAppFile(); -#ifdef MOZ_CRASHREPORTER - // Shut down the crashreporter service to prevent leaking some strings it holds. - if (CrashReporter::GetEnabled()) - CrashReporter::UnsetExceptionHandler(); -#endif - NS_LogTerm(); return result; diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp index a3d2b88c5..4c1230172 100644 --- a/js/xpconnect/src/XPCVariant.cpp +++ b/js/xpconnect/src/XPCVariant.cpp @@ -55,7 +55,7 @@ XPCTraceableVariant::~XPCTraceableVariant() { Value val = GetJSValPreserveColor(); - MOZ_ASSERT(val.isGCThing(), "Must be traceable or unlinked"); + MOZ_ASSERT(val.isGCThing() || val.isNull(), "Must be traceable or unlinked"); mData.Cleanup(); @@ -65,7 +65,7 @@ XPCTraceableVariant::~XPCTraceableVariant() void XPCTraceableVariant::TraceJS(JSTracer* trc) { - MOZ_ASSERT(GetJSValPreserveColor().isMarkable()); + MOZ_ASSERT(GetJSValPreserveColor().isGCThing()); JS::TraceEdge(trc, &mJSVal, "XPCTraceableVariant::mJSVal"); } @@ -86,7 +86,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) tmp->mData.Cleanup(); - if (val.isMarkable()) { + if (val.isGCThing()) { XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(tmp); v->RemoveFromRootSet(); } @@ -99,7 +99,7 @@ XPCVariant::newVariant(JSContext* cx, const Value& aJSVal) { RefPtr<XPCVariant> variant; - if (!aJSVal.isMarkable()) + if (!aJSVal.isGCThing()) variant = new XPCVariant(cx, aJSVal); else variant = new XPCTraceableVariant(cx, aJSVal); diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index acf92f3c3..a12e36baa 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -1785,9 +1785,12 @@ CallMethodHelper::ConvertIndependentParam(uint8_t i) // indirectly, regardless of in/out-ness. if (type_tag == nsXPTType::T_JSVAL) { // Root the value. - dp->val.j.setUndefined(); - if (!js::AddRawValueRoot(mCallContext, &dp->val.j, "XPCWrappedNative::CallMethod param")) + dp->val.j.asValueRef().setUndefined(); + if (!js::AddRawValueRoot(mCallContext, &dp->val.j.asValueRef(), + "XPCWrappedNative::CallMethod param")) + { return false; + } } // Flag cleanup for anything that isn't self-contained. diff --git a/js/xpconnect/tests/unit/test_exportFunction.js b/js/xpconnect/tests/unit/test_exportFunction.js index 830816342..9e1bf2082 100644 --- a/js/xpconnect/tests/unit/test_exportFunction.js +++ b/js/xpconnect/tests/unit/test_exportFunction.js @@ -10,12 +10,14 @@ function run_test() { epsb.do_check_true = do_check_true; epsb.do_check_eq = do_check_eq; subsb.do_check_true = do_check_true; + subsb.do_check_eq = do_check_eq; // Exporting should work if prinicipal of the source sandbox // subsumes the principal of the target sandbox. Cu.evalInSandbox("(" + function() { var wasCalled = false; this.funToExport = function(expectedThis, a, obj, native, mixed, callback) { + do_check_eq(arguments.callee.length, 6); do_check_eq(a, 42); do_check_eq(obj, subsb.tobecloned); do_check_eq(obj.cloned, "cloned"); @@ -53,6 +55,7 @@ function run_test() { invokedCallback = false; callback = function() { invokedCallback = true; }; imported(this, 42, tobecloned, native, mixed, callback); + do_check_eq(imported.length, 6); do_check_true(invokedCallback); }.toSource() + ")()", subsb); |