summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
Diffstat (limited to 'js')
-rw-r--r--js/moz.configure24
-rw-r--r--js/src/builtin/Intl.js626
-rw-r--r--js/src/gc/Nursery.cpp14
-rw-r--r--js/src/jit-test/tests/debug/bug1353356.js65
-rw-r--r--js/src/jit/Ion.cpp3
-rw-r--r--js/src/jit/MoveResolver.cpp99
-rw-r--r--js/src/jit/MoveResolver.h11
-rw-r--r--js/src/jsapi-tests/testJitMoveEmitterCycles.cpp94
-rw-r--r--js/src/jsapi.h3
-rw-r--r--js/src/jsfun.cpp4
-rw-r--r--js/src/jsscript.cpp50
-rw-r--r--js/src/jsutil.cpp2
-rw-r--r--js/src/old-configure.in10
-rw-r--r--js/src/shell/js.cpp4
-rw-r--r--js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js27
-rw-r--r--js/src/tests/Intl/getCanonicalLocales-overridden-species.js23
-rw-r--r--js/src/threading/windows/ConditionVariable.cpp329
-rw-r--r--js/src/vm/SharedArrayObject.cpp34
-rw-r--r--js/src/vm/Stack.cpp14
-rw-r--r--js/src/vm/Stopwatch.h6
-rw-r--r--js/src/vm/TypeInference.cpp12
-rw-r--r--js/src/vm/TypeInference.h4
-rw-r--r--js/src/vm/Xdr.h20
-rw-r--r--js/src/wasm/AsmJS.cpp3
-rw-r--r--js/src/wasm/WasmJS.cpp18
-rw-r--r--js/src/wasm/WasmModule.cpp8
-rw-r--r--js/xpconnect/shell/xpcshell.exe.manifest1
-rw-r--r--js/xpconnect/src/XPCJSID.cpp29
-rw-r--r--js/xpconnect/wrappers/AccessCheck.cpp14
29 files changed, 986 insertions, 565 deletions
diff --git a/js/moz.configure b/js/moz.configure
index 0eeb2fc52..eadd0e9ab 100644
--- a/js/moz.configure
+++ b/js/moz.configure
@@ -236,3 +236,27 @@ def ctypes_and_compile_environment(ctypes, compile_environment, _):
return ctypes and compile_environment
include('ffi.configure', when=ctypes_and_compile_environment)
+
+# Support various fuzzing options
+# ==============================================================
+with only_when('--enable-compile-environment'):
+ option('--enable-fuzzing', help='Enable fuzzing support')
+
+ @depends('--enable-fuzzing')
+ def enable_fuzzing(value):
+ if value:
+ return True
+
+ @depends(enable_fuzzing,
+ try_compile(body='__AFL_COMPILER;',
+ check_msg='for AFL compiler',
+ when='--enable-fuzzing'))
+ def enable_libfuzzer(fuzzing, afl):
+ if fuzzing and not afl:
+ return True
+
+ set_config('FUZZING', enable_fuzzing)
+ set_define('FUZZING', enable_fuzzing)
+
+ set_config('LIBFUZZER', enable_libfuzzer)
+ set_define('LIBFUZZER', enable_libfuzzer)
diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js
index 493062c1c..37c87365b 100644
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -9,7 +9,8 @@
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_DATE_NOT_FINITE: false, JSMSG_INVALID_KEYS_TYPE: false,
+ JSMSG_INVALID_KEY: false,
intl_Collator_availableLocales: false,
intl_availableCollations: false,
intl_CompareStrings: false,
@@ -20,6 +21,9 @@
intl_availableCalendars: false,
intl_patternForSkeleton: false,
intl_FormatDateTime: false,
+ intl_SelectPluralRule: false,
+ intl_GetPluralCategories: false,
+ intl_GetCalendarInfo: false,
*/
/*
@@ -432,7 +436,7 @@ function CanonicalizeLanguageTag(locale) {
subtags[i] = subtag;
i++;
}
- var normal = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, 0, i), "-");
+ var normal = ArrayJoinRange(subtags, "-", 0, i);
// Extension sequences are sorted by their singleton characters.
// "u-ca-chinese-t-zh-latn" -> "t-zh-latn-u-ca-chinese"
@@ -442,7 +446,7 @@ function CanonicalizeLanguageTag(locale) {
i++;
while (i < subtags.length && subtags[i].length > 1)
i++;
- var extension = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, extensionStart, i), "-");
+ var extension = ArrayJoinRange(subtags, "-", extensionStart, i);
callFunction(std_Array_push, extensions, extension);
}
callFunction(std_Array_sort, extensions);
@@ -450,7 +454,7 @@ function CanonicalizeLanguageTag(locale) {
// Private use sequences are left as is. "x-private"
var privateUse = "";
if (i < subtags.length)
- privateUse = callFunction(std_Array_join, callFunction(std_Array_slice, subtags, i), "-");
+ privateUse = ArrayJoinRange(subtags, "-", i);
// Put everything back together.
var canonical = normal;
@@ -467,6 +471,24 @@ function CanonicalizeLanguageTag(locale) {
return canonical;
}
+/**
+ * Joins the array elements in the given range with the supplied separator.
+ */
+function ArrayJoinRange(array, separator, from, to = array.length) {
+ assert(typeof separator === "string", "|separator| is a string value");
+ assert(typeof from === "number", "|from| is a number value");
+ assert(typeof to === "number", "|to| is a number value");
+ assert(0 <= from && from <= to && to <= array.length, "|from| and |to| form a valid range");
+
+ if (from === to)
+ return "";
+
+ var result = array[from];
+ for (var i = from + 1; i < to; i++) {
+ result += separator + array[i];
+ }
+ return result;
+}
function localeContainsNoUnicodeExtensions(locale) {
// No "-u-", no possible Unicode extension.
@@ -838,6 +860,7 @@ function BestAvailableLocaleIgnoringDefault(availableLocales, locale) {
return BestAvailableLocaleHelper(availableLocales, locale, false);
}
+var noRelevantExtensionKeys = [];
/**
* Compares a BCP 47 language priority list against the set of locales in
@@ -1165,9 +1188,10 @@ 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", "GetNumberOption");
- assert(typeof maximum === "number", "GetNumberOption");
- assert(fallback === undefined || (fallback >= minimum && fallback <= maximum), "GetNumberOption");
+ 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");
// Step 1.
var value = options[property];
@@ -1177,7 +1201,10 @@ function GetNumberOption(options, property, minimum, maximum, fallback) {
value = ToNumber(value);
if (Number_isNaN(value) || value < minimum || value > maximum)
ThrowRangeError(JSMSG_INVALID_DIGITS_VALUE, value);
- return std_Math_floor(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;
}
// Step 3.
@@ -1251,7 +1278,9 @@ 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", "bad type");
+ assert(type === "Collator" || type === "DateTimeFormat" ||
+ type == "NumberFormat" || type === "PluralRules",
+ "bad type");
assert(IsObject(lazyData), "non-object lazy data");
// Set in reverse order so that the .type change is a barrier.
@@ -1301,7 +1330,9 @@ 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", "unexpected type");
+ assert(type === "partial" || type === "Collator" ||
+ type === "DateTimeFormat" || type === "NumberFormat" || type === "PluralRules",
+ "unexpected type");
assert(callFunction(std_Object_hasOwnProperty, internals, "lazyData"), "missing lazyData");
assert(callFunction(std_Object_hasOwnProperty, internals, "internalProps"), "missing internalProps");
} else {
@@ -1358,6 +1389,8 @@ 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);
@@ -1689,6 +1722,7 @@ function Intl_Collator_compare_get() {
// Step 2.
return internals.boundCompare;
}
+_SetCanonicalName(Intl_Collator_compare_get, "get compare");
/**
@@ -1757,45 +1791,37 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
// Step 6.
var opt = lazyNumberFormatData.opt;
- // Compute effective locale.
- // Step 9.
var NumberFormat = numberFormatInternalProperties;
- // Step 10.
+ // Step 9.
var localeData = NumberFormat.localeData;
- // Step 11.
+ // Step 10.
var r = ResolveLocale(callFunction(NumberFormat.availableLocales, NumberFormat),
lazyNumberFormatData.requestedLocales,
lazyNumberFormatData.opt,
NumberFormat.relevantExtensionKeys,
localeData);
- // Steps 12-13. (Step 14 is not relevant to our implementation.)
+ // Steps 11-12. (Step 13 is not relevant to our implementation.)
internalProps.locale = r.locale;
internalProps.numberingSystem = r.nu;
// Compute formatting options.
- // Step 16.
- var s = lazyNumberFormatData.style;
- internalProps.style = s;
+ // Step 15.
+ var style = lazyNumberFormatData.style;
+ internalProps.style = style;
- // Steps 20, 22.
- if (s === "currency") {
+ // Steps 19, 21.
+ if (style === "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.
@@ -1804,10 +1830,10 @@ function resolveNumberFormatInternals(lazyNumberFormatData) {
internalProps.maximumSignificantDigits = lazyNumberFormatData.maximumSignificantDigits;
}
- // Step 35.
+ // Step 27.
internalProps.useGrouping = lazyNumberFormatData.useGrouping;
- // Step 42.
+ // Step 34.
internalProps.boundFormat = undefined;
// The caller is responsible for associating |internalProps| with the right
@@ -1835,6 +1861,44 @@ 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.
@@ -1884,7 +1948,7 @@ function InitializeNumberFormat(numberFormat, locales, options) {
// }
//
// Note that lazy data is only installed as a final step of initialization,
- // so every Collator lazy data object has *all* these properties, never a
+ // so every NumberFormat lazy data object has *all* these properties, never a
// subset of them.
var lazyNumberFormatData = std_Object_create(null);
@@ -1914,67 +1978,46 @@ function InitializeNumberFormat(numberFormat, locales, options) {
opt.localeMatcher = matcher;
// Compute formatting options.
- // Step 15.
- var s = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
- lazyNumberFormatData.style = s;
+ // Step 14.
+ var style = GetOption(options, "style", "string", ["decimal", "percent", "currency"], "decimal");
+ lazyNumberFormatData.style = style;
- // Steps 17-20.
+ // Steps 16-19.
var c = GetOption(options, "currency", "string", undefined, undefined);
if (c !== undefined && !IsWellFormedCurrencyCode(c))
ThrowRangeError(JSMSG_INVALID_CURRENCY_CODE, c);
var cDigits;
- if (s === "currency") {
+ if (style === "currency") {
if (c === undefined)
ThrowTypeError(JSMSG_UNDEFINED_CURRENCY);
- // Steps 20.a-c.
+ // Steps 19.a-c.
c = toASCIIUpperCase(c);
lazyNumberFormatData.currency = c;
cDigits = CurrencyDigits(c);
}
- // Step 21.
+ // Step 20.
var cd = GetOption(options, "currencyDisplay", "string", ["code", "symbol", "name"], "symbol");
- if (s === "currency")
+ if (style === "currency")
lazyNumberFormatData.currencyDisplay = cd;
- // 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;
+ // Steps 22-25.
+ var mnfdDefault, mxfdDefault;
+ if (style === "currency") {
+ mnfdDefault = cDigits;
+ mxfdDefault = cDigits;
+ } else {
+ mnfdDefault = 0;
+ mxfdDefault = style === "percent" ? 0 : 3;
}
+ SetNumberFormatDigitOptions(lazyNumberFormatData, options, mnfdDefault, mxfdDefault);
- // Step 34.
+ // Steps 26.
var g = GetOption(options, "useGrouping", "boolean", undefined, true);
lazyNumberFormatData.useGrouping = g;
- // Step 43.
+ // Steps 35-36.
//
// We've done everything that must be done now: mark the lazy data as fully
// computed and install it.
@@ -1983,43 +2026,6 @@ 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.
@@ -2100,7 +2106,7 @@ function numberFormatFormatToBind(value) {
// Step 1.a.ii-iii.
var x = ToNumber(value);
- return intl_FormatNumber(this, x);
+ return intl_FormatNumber(this, x, /* formatToParts = */ false);
}
@@ -2127,6 +2133,22 @@ 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);
+}
/**
@@ -2268,26 +2290,6 @@ 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.
@@ -2377,12 +2379,19 @@ function InitializeDateTimeFormat(dateTimeFormat, locales, options) {
lazyDateTimeFormatData.formatOpt = formatOpt;
// Step 19.
- 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;
- }
+ // 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);
// Steps 20-21 provided by ICU - see comment after this function.
@@ -2650,7 +2659,6 @@ 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
@@ -2836,6 +2844,7 @@ function Intl_DateTimeFormat_format_get() {
// Step 2.
return internals.boundFormat;
}
+_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format");
function Intl_DateTimeFormat_formatToParts() {
@@ -2971,6 +2980,232 @@ 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 = [];
@@ -3006,3 +3241,126 @@ 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/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
index bce2b74aa..aa50bf29e 100644
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -121,6 +121,13 @@ js::Nursery::Nursery(JSRuntime* rt)
bool
js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGC& lock)
{
+ if (!mallocedBuffers.init())
+ return false;
+
+ freeMallocedBuffersTask = js_new<FreeMallocedBuffersTask>(runtime()->defaultFreeOp());
+ if (!freeMallocedBuffersTask || !freeMallocedBuffersTask->init())
+ return false;
+
/* maxNurseryBytes parameter is rounded down to a multiple of chunk size. */
maxNurseryChunks_ = maxNurseryBytes >> ChunkShift;
@@ -128,16 +135,9 @@ js::Nursery::init(uint32_t maxNurseryBytes, AutoLockGC& lock)
if (maxNurseryChunks_ == 0)
return true;
- if (!mallocedBuffers.init())
- return false;
-
if (!cellsWithUid_.init())
return false;
- freeMallocedBuffersTask = js_new<FreeMallocedBuffersTask>(runtime()->defaultFreeOp());
- if (!freeMallocedBuffersTask || !freeMallocedBuffersTask->init())
- return false;
-
AutoMaybeStartBackgroundAllocation maybeBgAlloc;
updateNumChunksLocked(1, maybeBgAlloc, lock);
if (numChunks() == 0)
diff --git a/js/src/jit-test/tests/debug/bug1353356.js b/js/src/jit-test/tests/debug/bug1353356.js
new file mode 100644
index 000000000..389bb7860
--- /dev/null
+++ b/js/src/jit-test/tests/debug/bug1353356.js
@@ -0,0 +1,65 @@
+// |jit-test| allow-oom; --fuzzing-safe
+
+var lfLogBuffer = `
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+ setJitCompilerOption("ion.warmup.trigger", 4);
+ var g = newGlobal();
+ g.debuggeeGlobal = this;
+ g.eval("(" + function () {
+ dbg = new Debugger(debuggeeGlobal);
+ dbg.onExceptionUnwind = function (frame, exc) {
+ var s = '!';
+ for (var f = frame; f; f = f.older)
+ debuggeeGlobal.log += s;
+ };
+ } + ")();");
+ j('Number.prototype.toSource.call([])');
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-selectmode 4
+//corefuzz-dcd-endofdata
+}
+//corefuzz-dcd-endofdata
+//corefuzz-dcd-selectmode 5
+//corefuzz-dcd-endofdata
+oomTest(() => i({
+ new : (true ),
+ thisprops: true
+}));
+`;
+lfLogBuffer = lfLogBuffer.split('\n');
+var lfRunTypeId = -1;
+var lfCodeBuffer = "";
+while (true) {
+ var line = lfLogBuffer.shift();
+ if (line == null) {
+ break;
+ } else if (line == "//corefuzz-dcd-endofdata") {
+ loadFile(lfCodeBuffer);
+ lfCodeBuffer = "";
+ loadFile(line);
+ } else {
+ lfCodeBuffer += line + "\n";
+ }
+}
+if (lfCodeBuffer) loadFile(lfCodeBuffer);
+function loadFile(lfVarx) {
+ try {
+ if (lfVarx.indexOf("//corefuzz-dcd-selectmode ") === 0) {
+ lfRunTypeId = parseInt(lfVarx.split(" ")[1]) % 6;
+ } else {
+ switch (lfRunTypeId) {
+ case 4:
+ oomTest(function() {
+ let m = parseModule(lfVarx);
+ });
+ break;
+ default:
+ evaluate(lfVarx);
+ }
+ }
+ } catch (lfVare) {}
+}
diff --git a/js/src/jit/Ion.cpp b/js/src/jit/Ion.cpp
index 2a158ed7e..c61b414e0 100644
--- a/js/src/jit/Ion.cpp
+++ b/js/src/jit/Ion.cpp
@@ -568,9 +568,6 @@ jit::LinkIonScript(JSContext* cx, HandleScript calleeScript)
// doesn't has code to handle it after linking happened. So it's
// not OK to throw a catchable exception from there.
cx->clearPendingException();
-
- // Reset the TypeZone's compiler output for this script, if any.
- InvalidateCompilerOutputsForScript(cx, calleeScript);
}
}
diff --git a/js/src/jit/MoveResolver.cpp b/js/src/jit/MoveResolver.cpp
index 5fd6c7bd5..383b45073 100644
--- a/js/src/jit/MoveResolver.cpp
+++ b/js/src/jit/MoveResolver.cpp
@@ -106,12 +106,111 @@ MoveResolver::findCycledMove(PendingMoveIterator* iter, PendingMoveIterator end,
return nullptr;
}
+#ifdef JS_CODEGEN_ARM
+static inline bool
+MoveIsDouble(const MoveOperand& move)
+{
+ if (!move.isFloatReg())
+ return false;
+ return move.floatReg().isDouble();
+}
+#endif
+
+#ifdef JS_CODEGEN_ARM
+static inline bool
+MoveIsSingle(const MoveOperand& move)
+{
+ if (!move.isFloatReg())
+ return false;
+ return move.floatReg().isSingle();
+}
+#endif
+
+#ifdef JS_CODEGEN_ARM
+bool
+MoveResolver::isDoubleAliasedAsSingle(const MoveOperand& move)
+{
+ if (!MoveIsDouble(move))
+ return false;
+
+ for (auto iter = pending_.begin(); iter != pending_.end(); ++iter) {
+ PendingMove* other = *iter;
+ if (other->from().aliases(move) && MoveIsSingle(other->from()))
+ return true;
+ if (other->to().aliases(move) && MoveIsSingle(other->to()))
+ return true;
+ }
+ return false;
+}
+#endif
+
+#ifdef JS_CODEGEN_ARM
+static MoveOperand
+SplitIntoLowerHalf(const MoveOperand& move)
+{
+ if (MoveIsDouble(move)) {
+ FloatRegister lowerSingle = move.floatReg().asSingle();
+ return MoveOperand(lowerSingle);
+ }
+
+ MOZ_ASSERT(move.isMemoryOrEffectiveAddress());
+ return move;
+}
+#endif
+
+#ifdef JS_CODEGEN_ARM
+static MoveOperand
+SplitIntoUpperHalf(const MoveOperand& move)
+{
+ if (MoveIsDouble(move)) {
+ FloatRegister lowerSingle = move.floatReg().asSingle();
+ FloatRegister upperSingle = VFPRegister(lowerSingle.code() + 1, VFPRegister::Single);
+ return MoveOperand(upperSingle);
+ }
+
+ MOZ_ASSERT(move.isMemoryOrEffectiveAddress());
+ return MoveOperand(move.base(), move.disp() + sizeof(float));
+}
+#endif
+
bool
MoveResolver::resolve()
{
resetState();
orderedMoves_.clear();
+#ifdef JS_CODEGEN_ARM
+ // Some of ARM's double registers alias two of its single registers,
+ // but the algorithm below assumes that every register can participate
+ // in at most one cycle. To satisfy the algorithm, any double registers
+ // that may conflict are split into their single-register halves.
+ //
+ // This logic is only applicable because ARM only uses registers d0-d15,
+ // all of which alias s0-s31. Double registers d16-d31 are unused.
+ // Therefore there is never a double move that cannot be split.
+ // If this changes in the future, the algorithm will have to be fixed.
+ for (auto iter = pending_.begin(); iter != pending_.end(); ++iter) {
+ PendingMove* pm = *iter;
+
+ if (isDoubleAliasedAsSingle(pm->from()) || isDoubleAliasedAsSingle(pm->to())) {
+ PendingMove* lower = movePool_.allocate();
+ if (!lower)
+ return false;
+
+ // Insert the new node before the current position to not affect iteration.
+ MoveOperand fromLower = SplitIntoLowerHalf(pm->from());
+ MoveOperand toLower = SplitIntoLowerHalf(pm->to());
+ new (lower) PendingMove(fromLower, toLower, MoveOp::FLOAT32);
+ pending_.insertBefore(pm, lower);
+
+ // Overwrite pm in place for the upper move. Iteration proceeds as normal.
+ MoveOperand fromUpper = SplitIntoUpperHalf(pm->from());
+ MoveOperand toUpper = SplitIntoUpperHalf(pm->to());
+ pm->overwrite(fromUpper, toUpper, MoveOp::FLOAT32);
+ }
+ }
+#endif
+
InlineList<PendingMove> stack;
// This is a depth-first-search without recursion, which tries to find
diff --git a/js/src/jit/MoveResolver.h b/js/src/jit/MoveResolver.h
index fad2ba9e3..db045cfcf 100644
--- a/js/src/jit/MoveResolver.h
+++ b/js/src/jit/MoveResolver.h
@@ -252,6 +252,13 @@ class MoveOp
bool aliases(const MoveOp& other) const {
return aliases(other.from()) || aliases(other.to());
}
+#ifdef JS_CODEGEN_ARM
+ void overwrite(MoveOperand& from, MoveOperand& to, Type type) {
+ from_ = from;
+ to_ = to;
+ type_ = type;
+ }
+#endif
};
class MoveResolver
@@ -299,6 +306,10 @@ class MoveResolver
// Internal reset function. Does not clear lists.
void resetState();
+#ifdef JS_CODEGEN_ARM
+ bool isDoubleAliasedAsSingle(const MoveOperand& move);
+#endif
+
public:
MoveResolver();
diff --git a/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp b/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
index 416587293..c1c2baddd 100644
--- a/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
+++ b/js/src/jsapi-tests/testJitMoveEmitterCycles.cpp
@@ -6,6 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#if defined(JS_SIMULATOR_ARM)
+
#include "jit/arm/Assembler-arm.h"
#include "jit/arm/MoveEmitter-arm.h"
#include "jit/arm/Simulator-arm.h"
@@ -528,5 +529,96 @@ BEGIN_TEST(testJitMoveEmitterCycles_autogen3)
return true;
}
END_TEST(testJitMoveEmitterCycles_autogen3)
+BEGIN_TEST(testJitMoveEmitterCycles_bug1299147_1)
+{
+ using namespace js;
+ using namespace js::jit;
+ LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
+ TempAllocator alloc(&lifo);
+ JitContext jc(cx, &alloc);
+ cx->runtime()->getJitRuntime(cx);
+ MacroAssembler masm;
+ MoveEmitter mover(masm);
+ MoveResolver mr;
+ mr.setAllocator(alloc);
+ Simulator* sim = Simulator::Current();
+ // S2 -> S0
+ // S2 -> S6
+ // S3 -> S1
+ // S3 -> S7
+ // D0 -> D1
+ // D0 -> D2
+ TRY(mr.addMove(MoveOperand(s2), MoveOperand(s0), MoveOp::FLOAT32));
+ TRY(mr.addMove(MoveOperand(s2), MoveOperand(s6), MoveOp::FLOAT32));
+ sim->set_s_register_from_float(2, 2);
+ TRY(mr.addMove(MoveOperand(s3), MoveOperand(s1), MoveOp::FLOAT32));
+ TRY(mr.addMove(MoveOperand(s3), MoveOperand(s7), MoveOp::FLOAT32));
+ sim->set_s_register_from_float(3, 4);
+ TRY(mr.addMove(MoveOperand(d0), MoveOperand(d1), MoveOp::FLOAT32));
+ TRY(mr.addMove(MoveOperand(d0), MoveOperand(d2), MoveOp::FLOAT32));
+ sim->set_d_register_from_double(0, 1);
+ // don't explode!
+ TRY(mr.resolve());
+ mover.emit(mr);
+ mover.finish();
+ masm.abiret();
+ JitCode* code = linkAndAllocate(cx, &masm);
+ sim->call(code->raw(), 1, 1);
+ float f;
+ double d;
+ sim->get_double_from_d_register(1, &d);
+ CHECK(d == 1);
+ sim->get_double_from_d_register(2, &d);
+ CHECK(d == 1);
+ sim->get_float_from_s_register(0, &f);
+ CHECK(int(f) == 2);
+ sim->get_float_from_s_register(6, &f);
+ CHECK(int(f) == 2);
+ sim->get_float_from_s_register(1, &f);
+ CHECK(int(f) == 4);
+ sim->get_float_from_s_register(7, &f);
+ CHECK(int(f) == 4);
+ return true;
+}
+END_TEST(testJitMoveEmitterCycles_bug1299147_1)
+BEGIN_TEST(testJitMoveEmitterCycles_bug1299147)
+{
+ using namespace js;
+ using namespace js::jit;
+ LifoAlloc lifo(LIFO_ALLOC_PRIMARY_CHUNK_SIZE);
+ TempAllocator alloc(&lifo);
+ JitContext jc(cx, &alloc);
+ cx->runtime()->getJitRuntime(cx);
+ MacroAssembler masm;
+ MoveEmitter mover(masm);
+ MoveResolver mr;
+ mr.setAllocator(alloc);
+ Simulator* sim = Simulator::Current();
+ // S2 -> S5
+ // S2 -> S6
+ // D0 -> D1
+ TRY(mr.addMove(MoveOperand(s2), MoveOperand(s5), MoveOp::FLOAT32));
+ TRY(mr.addMove(MoveOperand(s2), MoveOperand(s6), MoveOp::FLOAT32));
+ sim->set_s_register_from_float(2, 2);
+ TRY(mr.addMove(MoveOperand(d0), MoveOperand(d1), MoveOp::FLOAT32));
+ sim->set_d_register_from_double(0, 1);
+ // don't explode!
+ TRY(mr.resolve());
+ mover.emit(mr);
+ mover.finish();
+ masm.abiret();
+ JitCode* code = linkAndAllocate(cx, &masm);
+ sim->call(code->raw(), 1, 1);
+ float f;
+ double d;
+ sim->get_double_from_d_register(1, &d);
+ CHECK(d == 1);
+ sim->get_float_from_s_register(5, &f);
+ CHECK(int(f) == 2);
+ sim->get_float_from_s_register(6, &f);
+ CHECK(int(f) == 2);
+ return true;
+}
+END_TEST(testJitMoveEmitterCycles_bug1299147)
-#endif
+#endif // JS_SIMULATOR_ARM
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 9ad3e757f..2d6ff462c 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5927,7 +5927,7 @@ enum TranscodeResult
TranscodeResult_Failure_BadBuildId = TranscodeResult_Failure | 0x1,
TranscodeResult_Failure_RunOnceNotSupported = TranscodeResult_Failure | 0x2,
TranscodeResult_Failure_AsmJSNotSupported = TranscodeResult_Failure | 0x3,
- TranscodeResult_Failure_UnknownClassKind = TranscodeResult_Failure | 0x4,
+ TranscodeResult_Failure_BadDecode = TranscodeResult_Failure | 0x4,
// A error, the JSContext has a pending exception.
TranscodeResult_Throw = 0x200
@@ -5999,7 +5999,6 @@ enum AsmJSCacheResult
AsmJSCache_Disabled_JitInspector,
AsmJSCache_InternalError,
AsmJSCache_Disabled_PrivateBrowsing,
- AsmJSCache_ESR52,
AsmJSCache_LIMIT
};
diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp
index 9fffce448..c952441ad 100644
--- a/js/src/jsfun.cpp
+++ b/js/src/jsfun.cpp
@@ -641,6 +641,10 @@ js::XDRInterpretedFunction(XDRState<mode>* xdr, HandleScope enclosingScope,
objp.set(fun);
}
+ // Verify marker at end of function to detect buffer truncation.
+ if (!xdr->codeMarker(0xA0129CD1))
+ return false;
+
return true;
}
diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp
index 2e02aa63d..10821f26a 100644
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -75,24 +75,19 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
{
JSContext* cx = xdr->cx();
- /*
- * A script constant can be an arbitrary primitive value as they are used
- * to implement JSOP_LOOKUPSWITCH. But they cannot be objects, see
- * bug 407186.
- */
enum ConstTag {
- SCRIPT_INT = 0,
- SCRIPT_DOUBLE = 1,
- SCRIPT_ATOM = 2,
- SCRIPT_TRUE = 3,
- SCRIPT_FALSE = 4,
- SCRIPT_NULL = 5,
- SCRIPT_OBJECT = 6,
- SCRIPT_VOID = 7,
- SCRIPT_HOLE = 8
+ SCRIPT_INT,
+ SCRIPT_DOUBLE,
+ SCRIPT_ATOM,
+ SCRIPT_TRUE,
+ SCRIPT_FALSE,
+ SCRIPT_NULL,
+ SCRIPT_OBJECT,
+ SCRIPT_VOID,
+ SCRIPT_HOLE
};
- uint32_t tag;
+ ConstTag tag;
if (mode == XDR_ENCODE) {
if (vp.isInt32()) {
tag = SCRIPT_INT;
@@ -116,7 +111,7 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
}
}
- if (!xdr->codeUint32(&tag))
+ if (!xdr->codeEnum32(&tag))
return false;
switch (tag) {
@@ -182,6 +177,10 @@ js::XDRScriptConst(XDRState<mode>* xdr, MutableHandleValue vp)
if (mode == XDR_DECODE)
vp.setMagic(JS_ELEMENTS_HOLE);
break;
+ default:
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR value kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
return true;
}
@@ -742,11 +741,20 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
case ScopeKind::Module:
MOZ_CRASH("NYI");
break;
+ default:
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR scope kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
if (mode == XDR_DECODE)
vector[i].init(scope);
}
+
+ // Verify marker to detect data corruption after decoding scope data. A
+ // mismatch here indicates we will almost certainly crash in release.
+ if (!xdr->codeMarker(0xF81F7F5A))
+ return false;
}
/*
@@ -832,12 +840,18 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope, HandleScrip
}
default: {
- MOZ_ASSERT(false, "Unknown class kind.");
- return xdr->fail(JS::TranscodeResult_Failure_UnknownClassKind);
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR class kind");
+ return xdr->fail(JS::TranscodeResult_Failure_BadDecode);
}
}
}
+ // Verify marker to detect data corruption after decoding object data. A
+ // mismatch here indicates we will almost certainly crash in release.
+ if (!xdr->codeMarker(0x223DB179))
+ return false;
+
if (ntrynotes != 0) {
JSTryNote* tnfirst = script->trynotes()->vector;
MOZ_ASSERT(script->trynotes()->length == ntrynotes);
diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp
index bb9f33df9..705d21975 100644
--- a/js/src/jsutil.cpp
+++ b/js/src/jsutil.cpp
@@ -39,7 +39,7 @@ mozilla::Atomic<AutoEnterOOMUnsafeRegion*> AutoEnterOOMUnsafeRegion::owner_;
namespace oom {
JS_PUBLIC_DATA(uint32_t) targetThread = 0;
-JS_PUBLIC_DATA(MOZ_THREAD_LOCAL(uint32_t)) threadType;
+MOZ_THREAD_LOCAL(uint32_t) threadType;
JS_PUBLIC_DATA(uint64_t) maxAllocations = UINT64_MAX;
JS_PUBLIC_DATA(uint64_t) counter = 0;
JS_PUBLIC_DATA(bool) failAlways = true;
diff --git a/js/src/old-configure.in b/js/src/old-configure.in
index e4589b951..5da81ce3e 100644
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -143,8 +143,7 @@ MOZ_TOOL_VARIABLES
dnl Special win32 checks
dnl ========================================================
-# Target the Windows 8.1 SDK by default
-WINVER=502
+WINVER=601
case "$target" in
*-mingw*)
@@ -722,12 +721,7 @@ case "$target" in
IMPORT_LIB_SUFFIX=lib
MKSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
MKCSHLIB='$(LD) -NOLOGO -DLL -OUT:$@ -PDB:$(LINK_PDBFILE) $(DSO_LDOPTS)'
- dnl Set subsystem version 5 for Windows XP.
- if test "$CPU_ARCH" = "x86"; then
- WIN32_SUBSYSTEM_VERSION=5.01
- else
- WIN32_SUBSYSTEM_VERSION=6.01
- fi
+ WIN32_SUBSYSTEM_VERSION=6.01
WIN32_CONSOLE_EXE_LDFLAGS=-SUBSYSTEM:CONSOLE,$WIN32_SUBSYSTEM_VERSION
WIN32_GUI_EXE_LDFLAGS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
DSO_LDOPTS=-SUBSYSTEM:WINDOWS,$WIN32_SUBSYSTEM_VERSION
diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp
index 88d482a23..3f56981cd 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -1546,9 +1546,9 @@ ConvertTranscodeResultToJSException(JSContext* cx, JS::TranscodeResult rv)
MOZ_ASSERT(!cx->isExceptionPending());
JS_ReportErrorASCII(cx, "Asm.js is not supported by XDR");
return false;
- case JS::TranscodeResult_Failure_UnknownClassKind:
+ case JS::TranscodeResult_Failure_BadDecode:
MOZ_ASSERT(!cx->isExceptionPending());
- JS_ReportErrorASCII(cx, "Unknown class kind, go fix it.");
+ JS_ReportErrorASCII(cx, "XDR data corruption");
return false;
case JS::TranscodeResult_Throw:
diff --git a/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js b/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js
new file mode 100644
index 000000000..f5f5b62a8
--- /dev/null
+++ b/js/src/tests/Intl/PluralRules/resolvedOptions-overridden-species.js
@@ -0,0 +1,27 @@
+// |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
new file mode 100644
index 000000000..858735b58
--- /dev/null
+++ b/js/src/tests/Intl/getCanonicalLocales-overridden-species.js
@@ -0,0 +1,23 @@
+// |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/threading/windows/ConditionVariable.cpp b/js/src/threading/windows/ConditionVariable.cpp
index 868c35141..3c75a0f27 100644
--- a/js/src/threading/windows/ConditionVariable.cpp
+++ b/js/src/threading/windows/ConditionVariable.cpp
@@ -28,342 +28,34 @@
_InterlockedIncrement((volatile long*)(addend))
#endif
-// Windows XP and Server 2003 don't support condition variables natively. The
-// NativeImports class is responsible for detecting native support and
-// retrieving the appropriate function pointers. It gets instantiated once,
-// using a static initializer.
-class ConditionVariableNativeImports
-{
-public:
- ConditionVariableNativeImports() {
- HMODULE kernel32_dll = GetModuleHandle("kernel32.dll");
- MOZ_RELEASE_ASSERT(kernel32_dll != NULL);
-
-#define LOAD_SYMBOL(symbol) loadSymbol(kernel32_dll, #symbol, symbol)
- supported_ = LOAD_SYMBOL(InitializeConditionVariable) &&
- LOAD_SYMBOL(WakeConditionVariable) &&
- LOAD_SYMBOL(WakeAllConditionVariable) &&
- LOAD_SYMBOL(SleepConditionVariableCS);
-#undef LOAD_SYMBOL
- }
-
- inline bool supported() const {
- return supported_;
- }
-
- void(WINAPI* InitializeConditionVariable)(CONDITION_VARIABLE* ConditionVariable);
- void(WINAPI* WakeAllConditionVariable)(PCONDITION_VARIABLE ConditionVariable);
- void(WINAPI* WakeConditionVariable)(CONDITION_VARIABLE* ConditionVariable);
- BOOL(WINAPI* SleepConditionVariableCS)(CONDITION_VARIABLE* ConditionVariable,
- CRITICAL_SECTION* CriticalSection,
- DWORD dwMilliseconds);
-
-private:
- template <typename T>
- inline bool loadSymbol(HMODULE module, const char* name, T& fn) {
- FARPROC ptr = GetProcAddress(module, name);
- if (!ptr)
- return false;
-
- fn = reinterpret_cast<T>(ptr);
- return true;
- }
-
- bool supported_;
-};
-
-static ConditionVariableNativeImports sNativeImports;
-
// Wrapper for native condition variable APIs.
-struct ConditionVariableNative
-{
- inline void initialize() {
- sNativeImports.InitializeConditionVariable(&cv_);
- }
-
- inline void destroy() {
- // Native condition variables don't require cleanup.
- }
-
- inline void notify_one() { sNativeImports.WakeConditionVariable(&cv_); }
-
- inline void notify_all() { sNativeImports.WakeAllConditionVariable(&cv_); }
-
- inline bool wait(CRITICAL_SECTION* cs, DWORD msec) {
- return sNativeImports.SleepConditionVariableCS(&cv_, cs, msec);
- }
-
-private:
- CONDITION_VARIABLE cv_;
-};
-
-// Fallback condition variable support for Windows XP and Server 2003. Given the
-// difficulty of testing on these antiquated platforms and their rapidly
-// diminishing market share, this implementation trades performance for
-// predictable behavior.
-struct ConditionVariableFallback
-{
- static const uint32_t WAKEUP_MODE_NONE = 0;
- static const uint32_t WAKEUP_MODE_ONE = 0x40000000;
- static const uint32_t WAKEUP_MODE_ALL = 0x80000000;
-
- static const uint32_t WAKEUP_MODE_MASK = WAKEUP_MODE_ONE | WAKEUP_MODE_ALL;
- static const uint32_t SLEEPERS_COUNT_MASK = ~WAKEUP_MODE_MASK;
-
- void initialize()
- {
- // Initialize the state variable to 0 sleepers, no wakeup.
- sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE;
-
- // Create a semaphore that prevents threads from entering sleep,
- // or waking other threads while a wakeup is ongoing.
- sleepWakeupSemaphore_ = CreateSemaphoreW(NULL, 1, 1, NULL);
- MOZ_RELEASE_ASSERT(sleepWakeupSemaphore_);
-
- // Use an auto-reset event for waking up a single sleeper.
- wakeOneEvent_ = CreateEventW(NULL, FALSE, FALSE, NULL);
- MOZ_RELEASE_ASSERT(wakeOneEvent_);
-
- // Use a manual-reset event for waking up all sleepers.
- wakeAllEvent_ = CreateEventW(NULL, TRUE, FALSE, NULL);
- MOZ_RELEASE_ASSERT(wakeAllEvent_);
- }
-
- void destroy()
- {
- BOOL r;
-
- MOZ_RELEASE_ASSERT(sleepersCountAndWakeupMode_ == (0 | WAKEUP_MODE_NONE));
-
- r = CloseHandle(sleepWakeupSemaphore_);
- MOZ_RELEASE_ASSERT(r);
-
- r = CloseHandle(wakeOneEvent_);
- MOZ_RELEASE_ASSERT(r);
-
- r = CloseHandle(wakeAllEvent_);
- MOZ_RELEASE_ASSERT(r);
- }
-
-private:
- void wakeup(uint32_t wakeupMode, HANDLE wakeEvent)
- {
- // Ensure that only one thread at a time can wake up others.
- BOOL result = WaitForSingleObject(sleepWakeupSemaphore_, INFINITE);
- MOZ_RELEASE_ASSERT(result == WAIT_OBJECT_0);
-
- // Atomically set the wakeup mode and retrieve the number of sleepers.
- uint32_t wcwm = InterlockedExchangeAdd(&sleepersCountAndWakeupMode_,
- wakeupMode);
- uint32_t sleepersCount = wcwm & SLEEPERS_COUNT_MASK;
- MOZ_RELEASE_ASSERT((wcwm & WAKEUP_MODE_MASK) == WAKEUP_MODE_NONE);
-
- if (sleepersCount > 0) {
- // If there are any sleepers, set the wake event. The (last) woken
- // up thread is responsible for releasing the semaphore.
- BOOL success = SetEvent(wakeEvent);
- MOZ_RELEASE_ASSERT(success);
-
- } else {
- // If there are no sleepers, set the wakeup mode back to 'none'
- // and release the semaphore ourselves.
- sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE;
-
- BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL);
- MOZ_RELEASE_ASSERT(success);
- }
- }
-
-public:
- void notify_one() { wakeup(WAKEUP_MODE_ONE, wakeOneEvent_); }
-
- void notify_all() { wakeup(WAKEUP_MODE_ALL, wakeAllEvent_); }
-
- bool wait(CRITICAL_SECTION* userLock, DWORD msec)
- {
- // Make sure that we can't enter sleep when there are other threads
- // that still need to wake up on either of the wake events being set.
- DWORD result = WaitForSingleObject(sleepWakeupSemaphore_, INFINITE);
- MOZ_RELEASE_ASSERT(result == WAIT_OBJECT_0);
-
- // Register ourselves as a sleeper. Use an atomic operation, because
- // if another thread times out at the same time, it will decrement the
- // sleepers count without acquiring the semaphore.
- uint32_t wcwm = InterlockedIncrement(&sleepersCountAndWakeupMode_);
- MOZ_RELEASE_ASSERT((wcwm & WAKEUP_MODE_MASK) == WAKEUP_MODE_NONE);
-
- // Now that that this thread has been enlisted as a sleeper, it is safe
- // again for other threads to do a wakeup.
- BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL);
- MOZ_RELEASE_ASSERT(success);
-
- // Release the caller's mutex.
- LeaveCriticalSection(userLock);
-
- // Wait for either event to become signaled, which happens when
- // notify_one() or notify_all() is called, or for a timeout.
- HANDLE handles[2] = { wakeOneEvent_, wakeAllEvent_ };
- DWORD waitResult = WaitForMultipleObjects(2, handles, FALSE, msec);
- MOZ_RELEASE_ASSERT(waitResult == WAIT_OBJECT_0 ||
- waitResult == WAIT_OBJECT_0 + 1 ||
- (waitResult == WAIT_TIMEOUT && msec != INFINITE));
-
- // Atomically decrease the sleepers count and retrieve the wakeup mode
- // and new sleepers count.
- // If the wait returned because wakeOneEvent_ was set, we are certain
- // that the wakeup mode will be WAKEUP_MODE_ONE. In that case,
- // atomically reset the wakeup mode to 'none', because if another
- // thread's sleep times out at same time and it finds that it was the
- // last sleeper, it decides whether or not to reset the wakeOneEvent_
- // based on the current wakeup mode.
- uint32_t sub;
- if (waitResult == WAIT_OBJECT_0)
- sub = 1 | WAKEUP_MODE_ONE;
- else
- sub = 1;
- // Note that InterlockedExchangeAdd returns the old value, but it's
- // easier to work with the new value.
- wcwm = InterlockedExchangeAdd(&sleepersCountAndWakeupMode_, -sub) - sub;
-
- uint32_t wakeupMode = wcwm & WAKEUP_MODE_MASK;
- uint32_t sleepersCount = wcwm & SLEEPERS_COUNT_MASK;
-
- bool releaseSleepWakeupSemaphore = false;
-
- if (waitResult == WAIT_OBJECT_0) {
- // The wake-one event is an auto-reset event so if we're woken by
- // it, it should already have been reset. We also already removed
- // the WAKEUP_MODE_ONE bit so the wakeup mode should now be 'none'
- // again.
- MOZ_RELEASE_ASSERT(wakeupMode == WAKEUP_MODE_NONE);
-
- // The signaling thread has acquired the enter-wakeup semaphore and
- // expects the woken (this) thread to release it again.
- releaseSleepWakeupSemaphore = true;
-
- } else if (waitResult == WAIT_TIMEOUT && wakeupMode == WAKEUP_MODE_ONE &&
- sleepersCount == 0) {
- // In theory a race condition is possible where the last sleeper
- // times out right at the moment that another thread signals it.
- // If that just happened we now have a dangling signal event and
- // mode, but no threads to be woken up by it, and we need to clean
- // that up.
- BOOL success = ResetEvent(wakeOneEvent_);
- MOZ_RELEASE_ASSERT(success);
-
- // This is safe - we are certain there are no other sleepers that
- // could wake up right now, and the semaphore ensures that no
- // non-sleeping threads are messing with
- // sleepersCountAndWakeupMode_.
- sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE;
-
- // The signaling thread has acquired the sleep-wakeup semaphore and
- // expects the woken thread to release it. But since there are no
- // sleeping threads left this thread will do it instead.
- releaseSleepWakeupSemaphore = true;
-
- } else if (wakeupMode == WAKEUP_MODE_ALL && sleepersCount == 0) {
- // If this was the last thread waking up in response to a
- // notify_all, clear the wakeup mode and reset the wake-all event.
- // A race condition similar to the case described above could
- // occur, so waitResult could be WAIT_TIMEOUT, but that doesn't
- // matter for the actions that need to be taken.
- MOZ_RELEASE_ASSERT(waitResult = WAIT_OBJECT_0 + 1 ||
- waitResult == WAIT_TIMEOUT);
-
- BOOL success = ResetEvent(wakeAllEvent_);
- MOZ_RELEASE_ASSERT(success);
-
- sleepersCountAndWakeupMode_ = 0 | WAKEUP_MODE_NONE;
-
- // The broadcasting thread has acquired the enter-wakeup semaphore
- // and expects the last thread that wakes up to release it.
- releaseSleepWakeupSemaphore = true;
-
- } else if ((waitResult == WAIT_TIMEOUT && msec != INFINITE) ||
- (waitResult == WAIT_OBJECT_0 + 1 &&
- wakeupMode == WAKEUP_MODE_ALL)) {
- // Either:
- // * The wait timed out but found no active notify_one or notify_all
- // the moment it decreased the wait count.
- // * A notify_all woke up this thread but there are more threads
- // that need to be woken up by the wake-all event.
- // These are ordinary conditions in which we don't have to do
- // anything.
-
- } else {
- MOZ_CRASH("invalid wakeup condition");
- }
-
- // Release the enter-wakeup semaphore if the wakeup condition requires
- // us to do it.
- if (releaseSleepWakeupSemaphore) {
- BOOL success = ReleaseSemaphore(sleepWakeupSemaphore_, 1, NULL);
- MOZ_RELEASE_ASSERT(success);
- }
-
- // Reacquire the user mutex.
- EnterCriticalSection(userLock);
-
- // Return true if woken up, false when timed out.
- if (waitResult == WAIT_TIMEOUT) {
- SetLastError(ERROR_TIMEOUT);
- return false;
- }
- return true;
- }
-
-private:
- uint32_t sleepersCountAndWakeupMode_;
- HANDLE sleepWakeupSemaphore_;
- HANDLE wakeOneEvent_;
- HANDLE wakeAllEvent_;
-};
-
struct js::ConditionVariable::PlatformData
{
- union
- {
- ConditionVariableNative native;
- ConditionVariableFallback fallback;
- };
+ CONDITION_VARIABLE cv_;
};
js::ConditionVariable::ConditionVariable()
{
- if (sNativeImports.supported())
- platformData()->native.initialize();
- else
- platformData()->fallback.initialize();
+ InitializeConditionVariable(&platformData()->cv_);
}
void
js::ConditionVariable::notify_one()
{
- if (sNativeImports.supported())
- platformData()->native.notify_one();
- else
- platformData()->fallback.notify_one();
+ WakeConditionVariable(&platformData()->cv_);
}
void
js::ConditionVariable::notify_all()
{
- if (sNativeImports.supported())
- platformData()->native.notify_all();
- else
- platformData()->fallback.notify_all();
+ WakeAllConditionVariable(&platformData()->cv_);
}
void
js::ConditionVariable::wait(UniqueLock<Mutex>& lock)
{
CRITICAL_SECTION* cs = &lock.lock.platformData()->criticalSection;
- bool r;
- if (sNativeImports.supported())
- r = platformData()->native.wait(cs, INFINITE);
- else
- r = platformData()->fallback.wait(cs, INFINITE);
+ bool r = SleepConditionVariableCS(&platformData()->cv_, cs, INFINITE);
MOZ_RELEASE_ASSERT(r);
}
@@ -390,11 +82,7 @@ js::ConditionVariable::wait_for(UniqueLock<Mutex>& lock,
? INFINITE
: static_cast<DWORD>(msecd);
- BOOL r;
- if (sNativeImports.supported())
- r = platformData()->native.wait(cs, msec);
- else
- r = platformData()->fallback.wait(cs, msec);
+ BOOL r = SleepConditionVariableCS(&platformData()->cv_, cs, msec);
if (r)
return CVStatus::NoTimeout;
MOZ_RELEASE_ASSERT(GetLastError() == ERROR_TIMEOUT);
@@ -403,10 +91,7 @@ js::ConditionVariable::wait_for(UniqueLock<Mutex>& lock,
js::ConditionVariable::~ConditionVariable()
{
- if (sNativeImports.supported())
- platformData()->native.destroy();
- else
- platformData()->fallback.destroy();
+ // Native condition variables don't require cleanup.
}
inline js::ConditionVariable::PlatformData*
diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp
index 730578cd4..c69306aac 100644
--- a/js/src/vm/SharedArrayObject.cpp
+++ b/js/src/vm/SharedArrayObject.cpp
@@ -116,22 +116,22 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
if (allocSize <= length)
return nullptr;
+ // Test >= to guard against the case where multiple extant runtimes
+ // race to allocate.
+ if (++numLive >= maxLive) {
+ JSRuntime* rt = cx->runtime();
+ if (rt->largeAllocationFailureCallback)
+ rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
+ if (numLive >= maxLive) {
+ numLive--;
+ return nullptr;
+ }
+ }
+
bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length);
void* p = nullptr;
if (preparedForAsmJS) {
- // Test >= to guard against the case where multiple extant runtimes
- // race to allocate.
- if (++numLive >= maxLive) {
- JSRuntime* rt = cx->runtime();
- if (rt->largeAllocationFailureCallback)
- rt->largeAllocationFailureCallback(rt->largeAllocationFailureCallbackData);
- if (numLive >= maxLive) {
- numLive--;
- return nullptr;
- }
- }
-
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
// Get the entire reserved region (with all pages inaccessible)
@@ -154,8 +154,10 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length)
# endif
} else {
p = MapMemory(allocSize, true);
- if (!p)
+ if (!p) {
+ numLive--;
return nullptr;
+ }
}
uint8_t* buffer = reinterpret_cast<uint8_t*>(p) + gc::SystemPageSize();
@@ -189,8 +191,6 @@ SharedArrayRawBuffer::dropReference()
uint32_t allocSize = SharedArrayAllocSize(this->length);
if (this->preparedForAsmJS) {
- numLive--;
-
uint32_t mappedSize = SharedArrayMappedSize(allocSize);
UnmapMemory(address, mappedSize);
@@ -202,6 +202,10 @@ SharedArrayRawBuffer::dropReference()
} else {
UnmapMemory(address, allocSize);
}
+
+ // Decrement the buffer counter at the end -- otherwise, a race condition
+ // could enable the creation of unlimited buffers.
+ numLive--;
}
diff --git a/js/src/vm/Stack.cpp b/js/src/vm/Stack.cpp
index 7978d8dbc..439bb1ed4 100644
--- a/js/src/vm/Stack.cpp
+++ b/js/src/vm/Stack.cpp
@@ -1517,11 +1517,7 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
uint8_t* top = iter.fp();
RematerializedFrameTable::AddPtr p = rematerializedFrames_->lookupForAdd(top);
if (!p) {
- RematerializedFrameVector empty(cx);
- if (!rematerializedFrames_->add(p, top, Move(empty))) {
- ReportOutOfMemory(cx);
- return nullptr;
- }
+ RematerializedFrameVector frames(cx);
// The unit of rematerialization is an uninlined frame and its inlined
// frames. Since inlined frames do not exist outside of snapshots, it
@@ -1536,9 +1532,11 @@ jit::JitActivation::getRematerializedFrame(JSContext* cx, const JitFrameIterator
// be in the activation's compartment.
AutoCompartment ac(cx, compartment_);
- if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover,
- p->value()))
- {
+ if (!RematerializedFrame::RematerializeInlineFrames(cx, top, inlineIter, recover, frames))
+ return nullptr;
+
+ if (!rematerializedFrames_->add(p, top, Move(frames))) {
+ ReportOutOfMemory(cx);
return nullptr;
}
diff --git a/js/src/vm/Stopwatch.h b/js/src/vm/Stopwatch.h
index a1b8bbbcb..38a3eb801 100644
--- a/js/src/vm/Stopwatch.h
+++ b/js/src/vm/Stopwatch.h
@@ -301,9 +301,9 @@ struct PerformanceMonitoring {
#if WINVER >= 0x0600
struct cpuid_t {
- WORD group_;
- BYTE number_;
- cpuid_t(WORD group, BYTE number)
+ uint16_t group_;
+ uint8_t number_;
+ cpuid_t(uint16_t group, uint8_t number)
: group_(group),
number_(number)
{ }
diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp
index 5b55ba947..2a7762e4f 100644
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -1511,18 +1511,6 @@ js::FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList
return true;
}
-void
-js::InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script)
-{
- TypeZone& types = cx->zone()->types;
- if (types.compilerOutputs) {
- for (auto& co : *types.compilerOutputs) {
- if (co.script() == script)
- co.invalidate();
- }
- }
-}
-
static void
CheckDefinitePropertiesTypeSet(JSContext* cx, TemporaryTypeSet* frozen, StackTypeSet* actual)
{
diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h
index 45b2711e2..9ba1c3cc8 100644
--- a/js/src/vm/TypeInference.h
+++ b/js/src/vm/TypeInference.h
@@ -1093,10 +1093,6 @@ bool
FinishCompilation(JSContext* cx, HandleScript script, CompilerConstraintList* constraints,
RecompileInfo* precompileInfo, bool* isValidOut);
-// Reset any CompilerOutput present for a script.
-void
-InvalidateCompilerOutputsForScript(JSContext* cx, HandleScript script);
-
// Update the actual types in any scripts queried by constraints with any
// speculative types added during the definite properties analysis.
void
diff --git a/js/src/vm/Xdr.h b/js/src/vm/Xdr.h
index 8e8c5bf17..2a5c62480 100644
--- a/js/src/vm/Xdr.h
+++ b/js/src/vm/Xdr.h
@@ -143,13 +143,17 @@ class XDRState {
template <typename T>
bool codeEnum32(T* val, typename mozilla::EnableIf<mozilla::IsEnum<T>::value, T>::Type * = NULL)
{
+ // Mix the enumeration value with a random magic number, such that a
+ // corruption with a low-ranged value (like 0) is less likely to cause a
+ // miss-interpretation of the XDR content and instead cause a failure.
+ const uint32_t MAGIC = 0xAF647BCE;
uint32_t tmp;
if (mode == XDR_ENCODE)
- tmp = uint32_t(*val);
+ tmp = uint32_t(*val) ^ MAGIC;
if (!codeUint32(&tmp))
return false;
if (mode == XDR_DECODE)
- *val = T(tmp);
+ *val = T(tmp ^ MAGIC);
return true;
}
@@ -167,6 +171,18 @@ class XDRState {
return true;
}
+ bool codeMarker(uint32_t magic) {
+ uint32_t actual = magic;
+ if (!codeUint32(&actual))
+ return false;
+ if (actual != magic) {
+ // Fail in debug, but only soft-fail in release
+ MOZ_ASSERT(false, "Bad XDR marker");
+ return fail(JS::TranscodeResult_Failure_BadDecode);
+ }
+ return true;
+ }
+
bool codeBytes(void* bytes, size_t len) {
if (len == 0)
return true;
diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp
index 6964c5d62..34f5a8c0d 100644
--- a/js/src/wasm/AsmJS.cpp
+++ b/js/src/wasm/AsmJS.cpp
@@ -8661,9 +8661,6 @@ BuildConsoleMessage(ExclusiveContext* cx, unsigned time, JS::AsmJSCacheResult ca
case JS::AsmJSCache_Disabled_PrivateBrowsing:
cacheString = "caching disabled by private browsing mode";
break;
- case JS::AsmJSCache_ESR52:
- cacheString = "caching disabled in Firefox ESR52";
- break;
case JS::AsmJSCache_LIMIT:
MOZ_CRASH("bad AsmJSCacheResult");
break;
diff --git a/js/src/wasm/WasmJS.cpp b/js/src/wasm/WasmJS.cpp
index 07d6331b8..0b030c844 100644
--- a/js/src/wasm/WasmJS.cpp
+++ b/js/src/wasm/WasmJS.cpp
@@ -1484,6 +1484,20 @@ const JSPropertySpec WasmTableObject::properties[] =
JS_PS_END
};
+static bool
+ToTableIndex(JSContext* cx, HandleValue v, const Table& table, const char* noun, uint32_t* index)
+{
+ if (!ToNonWrappingUint32(cx, v, UINT32_MAX, "Table", noun, index))
+ return false;
+
+ if (*index >= table.length()) {
+ JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_WASM_BAD_UINT32, "Table", noun);
+ return false;
+ }
+
+ return true;
+}
+
/* static */ bool
WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
{
@@ -1491,7 +1505,7 @@ WasmTableObject::getImpl(JSContext* cx, const CallArgs& args)
const Table& table = tableObj->table();
uint32_t index;
- if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "get index", &index))
+ if (!ToTableIndex(cx, args.get(0), table, "get index", &index))
return false;
ExternalTableElem& elem = table.externalArray()[index];
@@ -1530,7 +1544,7 @@ WasmTableObject::setImpl(JSContext* cx, const CallArgs& args)
return false;
uint32_t index;
- if (!ToNonWrappingUint32(cx, args.get(0), table.length() - 1, "Table", "set index", &index))
+ if (!ToTableIndex(cx, args.get(0), table, "set index", &index))
return false;
RootedFunction value(cx);
diff --git a/js/src/wasm/WasmModule.cpp b/js/src/wasm/WasmModule.cpp
index be7ddba8f..b24e01a40 100644
--- a/js/src/wasm/WasmModule.cpp
+++ b/js/src/wasm/WasmModule.cpp
@@ -1007,12 +1007,16 @@ Module::instantiate(JSContext* cx,
maybeBytecode = bytecode_.get();
auto codeSegment = CodeSegment::create(cx, code_, linkData_, *metadata_, memory);
- if (!codeSegment)
+ if (!codeSegment) {
+ ReportOutOfMemory(cx);
return false;
+ }
auto code = cx->make_unique<Code>(Move(codeSegment), *metadata_, maybeBytecode);
- if (!code)
+ if (!code) {
+ ReportOutOfMemory(cx);
return false;
+ }
instance.set(WasmInstanceObject::create(cx,
Move(code),
diff --git a/js/xpconnect/shell/xpcshell.exe.manifest b/js/xpconnect/shell/xpcshell.exe.manifest
index db2aa0861..c35b77af4 100644
--- a/js/xpconnect/shell/xpcshell.exe.manifest
+++ b/js/xpconnect/shell/xpcshell.exe.manifest
@@ -25,7 +25,6 @@
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
- <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
</application>
</compatibility>
</assembly>
diff --git a/js/xpconnect/src/XPCJSID.cpp b/js/xpconnect/src/XPCJSID.cpp
index b9cbee7be..1e14c1bdf 100644
--- a/js/xpconnect/src/XPCJSID.cpp
+++ b/js/xpconnect/src/XPCJSID.cpp
@@ -456,27 +456,26 @@ nsJSIID::Enumerate(nsIXPConnectWrappedNative* wrapper,
static nsresult
FindObjectForHasInstance(JSContext* cx, HandleObject objArg, MutableHandleObject target)
{
+ using namespace mozilla::jsipc;
RootedObject obj(cx, objArg), proto(cx);
-
- while (obj && !IS_WN_REFLECTOR(obj) &&
- !IsDOMObject(obj) && !mozilla::jsipc::IsCPOW(obj))
- {
- if (js::IsWrapper(obj)) {
- obj = js::CheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
- continue;
+ while (true) {
+ // Try the object, or the wrappee if allowed.
+ JSObject* o = js::IsWrapper(obj) ? js::CheckedUnwrap(obj, false) : obj;
+ if (o && (IS_WN_REFLECTOR(o) || IsDOMObject(o) || IsCPOW(o))) {
+ target.set(o);
+ return NS_OK;
}
- {
- JSAutoCompartment ac(cx, obj);
- if (!js::GetObjectProto(cx, obj, &proto))
- return NS_ERROR_FAILURE;
+ // Walk the prototype chain from the perspective of the callee (i.e.
+ // respecting Xrays if they exist).
+ if (!js::GetObjectProto(cx, obj, &proto))
+ return NS_ERROR_FAILURE;
+ if (!proto) {
+ target.set(nullptr);
+ return NS_OK;
}
-
obj = proto;
}
-
- target.set(obj);
- return NS_OK;
}
nsresult
diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp
index 085e7100e..d17c0629e 100644
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -307,6 +307,20 @@ ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, W
// Unfortunately, |cx| can be in either compartment when we call ::check. :-(
JSAutoCompartment ac(cx, wrappedObject);
+ // Proxies are not allowed in the proto chain.
+ RootedObject o(cx, wrappedObject);
+ while (o) {
+ JSObject* unwrapped = js::IsWrapper(o) ? js::CheckedUnwrap(o, false) : o;
+ if (!unwrapped || js::IsProxy(unwrapped))
+ return false;
+
+ RootedObject p(cx);
+ if (!js::GetObjectProto(cx, o, &p))
+ return false;
+
+ o = p;
+ }
+
bool found = false;
if (!JS_HasPropertyById(cx, wrappedObject, exposedPropsId, &found))
return false;