summaryrefslogtreecommitdiffstats
path: root/js
diff options
context:
space:
mode:
authorjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
committerjanekptacijarabaci <janekptacijarabaci@seznam.cz>2018-07-06 15:53:52 +0200
commit941e54654eabed0a3568f7fefe424a45aa02eddb (patch)
tree49aa02b174c428962d99142d8061267bfcd79e69 /js
parentad9ee72dcd7981bc47b3844a224d69fadfdfd8ef (diff)
parent0daa12376295d5d796256a116eb2a348a3a9273f (diff)
downloadUXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.gz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.lz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.tar.xz
UXP-941e54654eabed0a3568f7fefe424a45aa02eddb.zip
Merge branch 'master' of https://github.com/MoonchildProductions/UXP into _testBranch_test_1
Diffstat (limited to 'js')
-rw-r--r--js/ipc/JavaScriptParent.cpp1
-rw-r--r--js/public/Date.h8
-rw-r--r--js/public/StructuredClone.h207
-rw-r--r--js/public/Value.h55
-rw-r--r--js/src/Makefile.in7
-rw-r--r--js/src/aclocal.m41
-rw-r--r--js/src/builtin/Array.js21
-rw-r--r--js/src/builtin/Intl.cpp801
-rw-r--r--js/src/builtin/Intl.h58
-rw-r--r--js/src/builtin/Intl.js478
-rw-r--r--js/src/builtin/IntlTimeZoneData.h2
-rw-r--r--js/src/builtin/Map.js6
-rw-r--r--js/src/builtin/Set.js6
-rw-r--r--js/src/builtin/String.js15
-rw-r--r--js/src/builtin/TestingFunctions.cpp34
-rw-r--r--js/src/builtin/TypedArray.js8
-rw-r--r--js/src/gc/GCRuntime.h18
-rw-r--r--js/src/gc/Nursery.cpp8
-rw-r--r--js/src/gc/Statistics.h3
-rw-r--r--js/src/gdb/moz.build2
-rw-r--r--js/src/jit/BaselineFrameInfo.h4
-rw-r--r--js/src/jit/CodeGenerator.cpp26
-rw-r--r--js/src/jit/CodeGenerator.h1
-rw-r--r--js/src/jit/InlinableNatives.h10
-rw-r--r--js/src/jit/IonBuilder.h1
-rw-r--r--js/src/jit/JitFrameIterator.h2
-rw-r--r--js/src/jit/JitFrames.cpp4
-rw-r--r--js/src/jit/Lowering.cpp10
-rw-r--r--js/src/jit/Lowering.h1
-rw-r--r--js/src/jit/MCallOptimize.cpp51
-rw-r--r--js/src/jit/MIR.h42
-rw-r--r--js/src/jit/MOpcodes.h1
-rw-r--r--js/src/jit/MacroAssembler.cpp6
-rw-r--r--js/src/jit/ProcessExecutableMemory.cpp8
-rw-r--r--js/src/jit/ProcessExecutableMemory.h8
-rw-r--r--js/src/jit/RegisterSets.h8
-rw-r--r--js/src/jit/RematerializedFrame.cpp14
-rw-r--r--js/src/jit/shared/IonAssemblerBuffer.h4
-rw-r--r--js/src/jit/shared/LIR-shared.h23
-rw-r--r--js/src/jit/shared/LOpcodes-shared.h1
-rw-r--r--js/src/jit/x86-shared/AssemblerBuffer-x86-shared.h32
-rw-r--r--js/src/js.msg2
-rw-r--r--js/src/jsapi-tests/moz.build2
-rw-r--r--js/src/jsapi.h2
-rwxr-xr-xjs/src/jsdate.cpp89
-rw-r--r--js/src/jsgc.cpp27
-rw-r--r--js/src/jsgc.h51
-rw-r--r--js/src/jsnativestack.cpp68
-rw-r--r--js/src/jsnum.cpp206
-rw-r--r--js/src/jsnum.h8
-rw-r--r--js/src/jsprototypes.h4
-rw-r--r--js/src/jsstr.cpp53
-rw-r--r--js/src/jsstr.h8
-rw-r--r--js/src/jstypes.h4
-rwxr-xr-xjs/src/make-source-package.sh1
-rw-r--r--js/src/moz.build25
-rw-r--r--js/src/old-configure.in16
-rw-r--r--js/src/shell/js.cpp5
-rw-r--r--js/src/shell/moz.build2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backzone.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_backzone_links.js2
-rw-r--r--js/src/tests/Intl/DateTimeFormat/timeZone_notbackward_links.js2
-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/tests/Intl/getDisplayNames.js238
-rw-r--r--js/src/tests/js1_8_5/extensions/clone-errors.js1
-rw-r--r--js/src/tests/js1_8_5/extensions/clone-transferables.js12
-rw-r--r--js/src/threading/windows/ConditionVariable.cpp8
-rw-r--r--js/src/threading/windows/MutexImpl.cpp47
-rw-r--r--js/src/threading/windows/MutexPlatformData.h2
-rw-r--r--js/src/vm/DateTime.cpp6
-rw-r--r--js/src/vm/GlobalObject.cpp4
-rw-r--r--js/src/vm/HelperThreads.cpp4
-rw-r--r--js/src/vm/Initialization.cpp10
-rw-r--r--js/src/vm/Runtime.cpp12
-rw-r--r--js/src/vm/Runtime.h7
-rw-r--r--js/src/vm/SelfHosting.cpp50
-rw-r--r--js/src/vm/StructuredClone.cpp389
-rw-r--r--js/src/wasm/AsmJS.cpp10
-rw-r--r--js/xpconnect/shell/moz.build16
-rw-r--r--js/xpconnect/shell/xpcshell.cpp11
-rw-r--r--js/xpconnect/src/ExportHelpers.cpp11
-rw-r--r--js/xpconnect/src/XPCJSContext.cpp26
-rw-r--r--js/xpconnect/src/XPCShellImpl.cpp18
-rw-r--r--js/xpconnect/src/XPCWrappedNative.cpp7
-rw-r--r--js/xpconnect/tests/unit/test_exportFunction.js3
87 files changed, 1670 insertions, 1849 deletions
diff --git a/js/ipc/JavaScriptParent.cpp b/js/ipc/JavaScriptParent.cpp
index 7fe92d662..ca0a0bd21 100644
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -16,6 +16,7 @@
#include "xpcprivate.h"
#include "mozilla/Casting.h"
#include "mozilla/Telemetry.h"
+#include "mozilla/Unused.h"
#include "nsAutoPtr.h"
using namespace js;
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/StructuredClone.h b/js/public/StructuredClone.h
index c48975cb9..ebff84387 100644
--- a/js/public/StructuredClone.h
+++ b/js/public/StructuredClone.h
@@ -9,6 +9,7 @@
#include "mozilla/Attributes.h"
#include "mozilla/BufferList.h"
+#include "mozilla/Move.h"
#include <stdint.h>
@@ -29,7 +30,35 @@ namespace JS {
enum class StructuredCloneScope : uint32_t {
SameProcessSameThread,
SameProcessDifferentThread,
- DifferentProcess
+
+ /**
+ * When writing, this means we're writing for an audience in a different
+ * process. Produce serialized data that can be sent to other processes,
+ * bitwise copied, or even stored as bytes in a database and read by later
+ * versions of Firefox years from now. The HTML5 spec refers to this as
+ * "ForStorage" as in StructuredSerializeForStorage, though we use
+ * DifferentProcess for IPC as well as storage.
+ *
+ * Transferable objects are limited to ArrayBuffers, whose contents are
+ * copied into the serialized data (rather than just writing a pointer).
+ */
+ DifferentProcess,
+
+ /**
+ * Handle a backwards-compatibility case with IndexedDB (bug 1434308): when
+ * reading, this means to treat legacy SameProcessSameThread data as if it
+ * were DifferentProcess.
+ *
+ * Do not use this for writing; use DifferentProcess instead.
+ */
+ DifferentProcessForIndexedDB,
+
+ /**
+ * Existing code wants to be able to create an uninitialized
+ * JSStructuredCloneData without knowing the scope, then populate it with
+ * data (at which point the scope *is* known.)
+ */
+ Unassigned
};
enum TransferableOwnership {
@@ -89,6 +118,10 @@ class CloneDataPolicy
} /* namespace JS */
+namespace js {
+template <typename T, typename AllocPolicy> struct BufferIterator;
+}
+
/**
* Read structured data from the reader r. This hook is used to read a value
* previously serialized by a call to the WriteStructuredCloneOp hook.
@@ -188,49 +221,152 @@ enum OwnTransferablePolicy {
NoTransferables
};
-class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) :
- public mozilla::BufferList<js::SystemAllocPolicy>
-{
- typedef js::SystemAllocPolicy AllocPolicy;
- typedef mozilla::BufferList<js::SystemAllocPolicy> BufferList;
+/**
+ * JSStructuredCloneData represents structured clone data together with the
+ * information needed to read/write/transfer/free the records within it, in the
+ * form of a set of callbacks.
+ */
+class MOZ_NON_MEMMOVABLE JS_PUBLIC_API(JSStructuredCloneData) {
+ public:
+ using BufferList = mozilla::BufferList<js::SystemAllocPolicy>;
+ using Iterator = BufferList::IterImpl;
- static const size_t kInitialSize = 0;
- static const size_t kInitialCapacity = 4096;
+ private:
static const size_t kStandardCapacity = 4096;
+ BufferList bufList_;
+
+ // The (address space, thread) scope within which this clone is valid. Note
+ // that this must be either set during construction, or start out as
+ // Unassigned and transition once to something else.
+ JS::StructuredCloneScope scope_;
+
const JSStructuredCloneCallbacks* callbacks_;
void* closure_;
OwnTransferablePolicy ownTransferables_;
- void setOptionalCallbacks(const JSStructuredCloneCallbacks* callbacks,
- void* closure,
- OwnTransferablePolicy policy) {
- callbacks_ = callbacks;
- closure_ = closure;
- ownTransferables_ = policy;
- }
-
friend struct JSStructuredCloneWriter;
friend class JS_PUBLIC_API(JSAutoStructuredCloneBuffer);
+ template <typename T, typename AllocPolicy> friend struct js::BufferIterator;
-public:
- explicit JSStructuredCloneData(AllocPolicy aAP = AllocPolicy())
- : BufferList(kInitialSize, kInitialCapacity, kStandardCapacity, aAP)
+ public:
+ // The constructor must be infallible but SystemAllocPolicy is not, so both
+ // the initial size and initial capacity of the BufferList must be zero.
+ explicit JSStructuredCloneData(JS::StructuredCloneScope aScope)
+ : bufList_(0, 0, kStandardCapacity, js::SystemAllocPolicy())
+ , scope_(aScope)
, callbacks_(nullptr)
, closure_(nullptr)
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
{}
- MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
- : BufferList(Move(buffers))
+
+ // Steal the raw data from a BufferList. In this case, we don't know the
+ // scope and none of the callback info is assigned yet.
+ JSStructuredCloneData(BufferList&& buffers, JS::StructuredCloneScope aScope)
+ : bufList_(mozilla::Move(buffers))
+ , scope_(aScope)
, callbacks_(nullptr)
, closure_(nullptr)
, ownTransferables_(OwnTransferablePolicy::NoTransferables)
{}
+ MOZ_IMPLICIT JSStructuredCloneData(BufferList&& buffers)
+ : JSStructuredCloneData(mozilla::Move(buffers), JS::StructuredCloneScope::Unassigned)
+ {}
JSStructuredCloneData(JSStructuredCloneData&& other) = default;
JSStructuredCloneData& operator=(JSStructuredCloneData&& other) = default;
- ~JSStructuredCloneData();
+ ~JSStructuredCloneData() { discardTransferables(); }
+
+ void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
+ void* closure,
+ OwnTransferablePolicy policy)
+ {
+ callbacks_ = callbacks;
+ closure_ = closure;
+ ownTransferables_ = policy;
+ }
+
+ JS::StructuredCloneScope scope() const { return scope_; }
+
+ void initScope(JS::StructuredCloneScope aScope) {
+ MOZ_ASSERT(Size() == 0, "initScope() of nonempty JSStructuredCloneData");
+ if (scope_ != JS::StructuredCloneScope::Unassigned)
+ MOZ_ASSERT(scope_ == aScope, "Cannot change scope after it has been initialized");
+ scope_ = aScope;
+ }
+
+ size_t Size() const { return bufList_.Size(); }
+
+ const Iterator Start() const { return bufList_.Iter(); }
+
+ bool Advance(Iterator& iter, size_t distance) const {
+ return iter.AdvanceAcrossSegments(bufList_, distance);
+ }
+
+ bool ReadBytes(Iterator& iter, char* buffer, size_t size) const {
+ return bufList_.ReadBytes(iter, buffer, size);
+ }
+
+ // Append new data to the end of the buffer.
+ bool AppendBytes(const char* data, size_t size) {
+ MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned);
+ return bufList_.WriteBytes(data, size);
+ }
- using BufferList::BufferList;
+ // Update data stored within the existing buffer. There must be at least
+ // 'size' bytes between the position of 'iter' and the end of the buffer.
+ bool UpdateBytes(Iterator& iter, const char* data, size_t size) const {
+ MOZ_ASSERT(scope_ != JS::StructuredCloneScope::Unassigned);
+ while (size > 0) {
+ size_t remaining = iter.RemainingInSegment();
+ size_t nbytes = std::min(remaining, size);
+ memcpy(iter.Data(), data, nbytes);
+ data += nbytes;
+ size -= nbytes;
+ iter.Advance(bufList_, nbytes);
+ }
+ return true;
+ }
+
+ void Clear() {
+ discardTransferables();
+ bufList_.Clear();
+ }
+
+ // Return a new read-only JSStructuredCloneData that "borrows" the contents
+ // of |this|. Its lifetime should not exceed the donor's. This is only
+ // allowed for DifferentProcess clones, so finalization of the borrowing
+ // clone will do nothing.
+ JSStructuredCloneData Borrow(Iterator& iter, size_t size, bool* success) const
+ {
+ MOZ_ASSERT(scope_ == JS::StructuredCloneScope::DifferentProcess);
+ return JSStructuredCloneData(bufList_.Borrow<js::SystemAllocPolicy>(iter, size, success),
+ scope_);
+ }
+
+ // Iterate over all contained data, one BufferList segment's worth at a
+ // time, and invoke the given FunctionToApply with the data pointer and
+ // size. The function should return a bool value, and this loop will exit
+ // with false if the function ever returns false.
+ template <typename FunctionToApply>
+ bool ForEachDataChunk(FunctionToApply&& function) const {
+ Iterator iter = bufList_.Iter();
+ while (!iter.Done()) {
+ if (!function(iter.Data(), iter.RemainingInSegment()))
+ return false;
+ iter.Advance(bufList_, iter.RemainingInSegment());
+ }
+ return true;
+ }
+
+ // Append the entire contents of other's bufList_ to our own.
+ bool Append(const JSStructuredCloneData& other) {
+ MOZ_ASSERT(scope_ == other.scope_);
+ return other.ForEachDataChunk([&](const char* data, size_t size) {
+ return AppendBytes(data, size);
+ });
+ }
+
+ void discardTransferables();
};
/** Note: if the *data contains transferable objects, it can be read only once. */
@@ -254,18 +390,29 @@ JS_PUBLIC_API(bool)
JS_StructuredClone(JSContext* cx, JS::HandleValue v, JS::MutableHandleValue vp,
const JSStructuredCloneCallbacks* optionalCallbacks, void* closure);
-/** RAII sugar for JS_WriteStructuredClone. */
+/**
+ * The C-style API calls to read and write structured clones are fragile --
+ * they rely on the caller to properly handle ownership of the clone data, and
+ * the handling of the input data as well as the interpretation of the contents
+ * of the clone buffer are dependent on the callbacks passed in. If you
+ * serialize and deserialize with different callbacks, the results are
+ * questionable.
+ *
+ * JSAutoStructuredCloneBuffer wraps things up in an RAII class for data
+ * management, and uses the same callbacks for both writing and reading
+ * (serializing and deserializing).
+ */
class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
const JS::StructuredCloneScope scope_;
JSStructuredCloneData data_;
uint32_t version_;
public:
- JSAutoStructuredCloneBuffer(JS::StructuredCloneScope scope,
+ JSAutoStructuredCloneBuffer(JS::StructuredCloneScope aScope,
const JSStructuredCloneCallbacks* callbacks, void* closure)
- : scope_(scope), version_(JS_STRUCTURED_CLONE_VERSION)
+ : scope_(aScope), data_(aScope), version_(JS_STRUCTURED_CLONE_VERSION)
{
- data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
+ data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
}
JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other);
@@ -276,11 +423,9 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
JSStructuredCloneData& data() { return data_; }
bool empty() const { return !data_.Size(); }
- void clear(const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
+ void clear();
- /** Copy some memory. It will be automatically freed by the destructor. */
- bool copy(const JSStructuredCloneData& data, uint32_t version=JS_STRUCTURED_CLONE_VERSION,
- const JSStructuredCloneCallbacks* callbacks=nullptr, void* closure=nullptr);
+ JS::StructuredCloneScope scope() const { return scope_; }
/**
* Adopt some memory. It will be automatically freed by the destructor.
diff --git a/js/public/Value.h b/js/public/Value.h
index a40e65c83..01666ed4e 100644
--- a/js/public/Value.h
+++ b/js/public/Value.h
@@ -140,12 +140,16 @@ static_assert(sizeof(JSValueShiftedTag) == sizeof(uint64_t),
#define JSVAL_TYPE_TO_TAG(type) ((JSValueTag)(JSVAL_TAG_CLEAR | (type)))
+#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)))
@@ -817,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;
@@ -843,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;
@@ -871,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;
@@ -895,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;
@@ -948,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)
{
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/Array.js b/js/src/builtin/Array.js
index 45f90a7b8..30e6fb35f 100644
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -711,13 +711,14 @@ function CreateArrayIterator(obj, kind) {
// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-%arrayiteratorprototype%.next
function ArrayIteratorNext() {
// Step 1-3.
- if (!IsObject(this) || !IsArrayIterator(this)) {
+ var obj;
+ if (!IsObject(this) || (obj = GuardToArrayIterator(this)) === null) {
return callFunction(CallArrayIteratorMethodIfWrapped, this,
"ArrayIteratorNext");
}
// Step 4.
- var a = UnsafeGetReservedSlot(this, ITERATOR_SLOT_TARGET);
+ var a = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_TARGET);
var result = { value: undefined, done: false };
// Step 5.
@@ -728,10 +729,10 @@ function ArrayIteratorNext() {
// Step 6.
// The index might not be an integer, so we have to do a generic get here.
- var index = UnsafeGetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+ var index = UnsafeGetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
// Step 7.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_ITEM_KIND);
// Step 8-9.
var len = IsPossiblyWrappedTypedArray(a)
@@ -740,13 +741,13 @@ function ArrayIteratorNext() {
// Step 10.
if (index >= len) {
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_TARGET, null);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_TARGET, null);
result.done = true;
return result;
}
// Step 11.
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + 1);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + 1);
// Step 16.
if (itemKind === ITEM_KIND_VALUE) {
@@ -900,11 +901,7 @@ function ArrayToLocaleString(locales, options) {
if (firstElement === undefined || firstElement === null) {
R = "";
} else {
-#if EXPOSE_INTL_API
R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options));
-#else
- R = ToString(callContentFunction(firstElement.toLocaleString, firstElement));
-#endif
}
// Step 3 (reordered).
@@ -919,11 +916,7 @@ function ArrayToLocaleString(locales, options) {
// Steps 9.a, 9.c-e.
R += separator;
if (!(nextElement === undefined || nextElement === null)) {
-#if EXPOSE_INTL_API
R += ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options));
-#else
- R += ToString(callContentFunction(nextElement.toLocaleString, nextElement));
-#endif
}
}
diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp
index 3a20c487b..71f7b58d4 100644
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -23,7 +23,6 @@
#include "jsobj.h"
#include "builtin/IntlTimeZoneData.h"
-#if ENABLE_INTL_API
#include "unicode/ucal.h"
#include "unicode/ucol.h"
#include "unicode/udat.h"
@@ -32,7 +31,6 @@
#include "unicode/unum.h"
#include "unicode/unumsys.h"
#include "unicode/ustring.h"
-#endif
#include "vm/DateTime.h"
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
@@ -60,512 +58,6 @@ using mozilla::PodCopy;
* http://userguide.icu-project.org/design#TOC-Error-Handling
*/
-
-/******************** ICU stubs ********************/
-
-#if !ENABLE_INTL_API
-
-/*
- * When the Internationalization API isn't enabled, we also shouldn't link
- * against ICU. However, we still want to compile this code in order to prevent
- * bit rot. The following stub implementations for ICU functions make this
- * possible. The functions using them should never be called, so they assert
- * and return error codes. Signatures adapted from ICU header files locid.h,
- * numsys.h, ucal.h, ucol.h, udat.h, udatpg.h, uenum.h, unum.h; see the ICU
- * directory for license.
- */
-
-typedef bool UBool;
-typedef char16_t UChar;
-typedef double UDate;
-
-enum UErrorCode {
- U_ZERO_ERROR,
- U_BUFFER_OVERFLOW_ERROR,
-};
-
-static inline UBool
-U_FAILURE(UErrorCode code)
-{
- MOZ_CRASH("U_FAILURE: Intl API disabled");
-}
-
-inline const UChar*
-Char16ToUChar(const char16_t* chars)
-{
- MOZ_CRASH("Char16ToUChar: Intl API disabled");
-}
-
-inline UChar*
-Char16ToUChar(char16_t* chars)
-{
- MOZ_CRASH("Char16ToUChar: Intl API disabled");
-}
-
-static int32_t
-u_strlen(const UChar* s)
-{
- MOZ_CRASH("u_strlen: Intl API disabled");
-}
-
-struct UEnumeration;
-
-static int32_t
-uenum_count(UEnumeration* en, UErrorCode* status)
-{
- MOZ_CRASH("uenum_count: Intl API disabled");
-}
-
-static const char*
-uenum_next(UEnumeration* en, int32_t* resultLength, UErrorCode* status)
-{
- MOZ_CRASH("uenum_next: Intl API disabled");
-}
-
-static void
-uenum_close(UEnumeration* en)
-{
- MOZ_CRASH("uenum_close: Intl API disabled");
-}
-
-struct UCollator;
-
-enum UColAttribute {
- UCOL_ALTERNATE_HANDLING,
- UCOL_CASE_FIRST,
- UCOL_CASE_LEVEL,
- UCOL_NORMALIZATION_MODE,
- UCOL_STRENGTH,
- UCOL_NUMERIC_COLLATION,
-};
-
-enum UColAttributeValue {
- UCOL_DEFAULT = -1,
- UCOL_PRIMARY = 0,
- UCOL_SECONDARY = 1,
- UCOL_TERTIARY = 2,
- UCOL_OFF = 16,
- UCOL_ON = 17,
- UCOL_SHIFTED = 20,
- UCOL_LOWER_FIRST = 24,
- UCOL_UPPER_FIRST = 25,
-};
-
-enum UCollationResult {
- UCOL_EQUAL = 0,
- UCOL_GREATER = 1,
- UCOL_LESS = -1
-};
-
-static int32_t
-ucol_countAvailable()
-{
- MOZ_CRASH("ucol_countAvailable: Intl API disabled");
-}
-
-static const char*
-ucol_getAvailable(int32_t localeIndex)
-{
- MOZ_CRASH("ucol_getAvailable: Intl API disabled");
-}
-
-static UCollator*
-ucol_open(const char* loc, UErrorCode* status)
-{
- MOZ_CRASH("ucol_open: Intl API disabled");
-}
-
-static void
-ucol_setAttribute(UCollator* coll, UColAttribute attr, UColAttributeValue value, UErrorCode* status)
-{
- MOZ_CRASH("ucol_setAttribute: Intl API disabled");
-}
-
-static UCollationResult
-ucol_strcoll(const UCollator* coll, const UChar* source, int32_t sourceLength,
- const UChar* target, int32_t targetLength)
-{
- MOZ_CRASH("ucol_strcoll: Intl API disabled");
-}
-
-static void
-ucol_close(UCollator* coll)
-{
- MOZ_CRASH("ucol_close: Intl API disabled");
-}
-
-static UEnumeration*
-ucol_getKeywordValuesForLocale(const char* key, const char* locale, UBool commonlyUsed,
- UErrorCode* status)
-{
- MOZ_CRASH("ucol_getKeywordValuesForLocale: Intl API disabled");
-}
-
-struct UParseError;
-struct UFieldPosition;
-struct UFieldPositionIterator;
-typedef void* UNumberFormat;
-
-enum UNumberFormatStyle {
- UNUM_DECIMAL = 1,
- UNUM_CURRENCY,
- UNUM_PERCENT,
- UNUM_CURRENCY_ISO,
- UNUM_CURRENCY_PLURAL,
-};
-
-enum UNumberFormatRoundingMode {
- UNUM_ROUND_HALFUP,
-};
-
-enum UNumberFormatAttribute {
- UNUM_GROUPING_USED,
- UNUM_MIN_INTEGER_DIGITS,
- UNUM_MAX_FRACTION_DIGITS,
- UNUM_MIN_FRACTION_DIGITS,
- UNUM_ROUNDING_MODE,
- UNUM_SIGNIFICANT_DIGITS_USED,
- UNUM_MIN_SIGNIFICANT_DIGITS,
- UNUM_MAX_SIGNIFICANT_DIGITS,
-};
-
-enum UNumberFormatTextAttribute {
- UNUM_CURRENCY_CODE,
-};
-
-static int32_t
-unum_countAvailable()
-{
- MOZ_CRASH("unum_countAvailable: Intl API disabled");
-}
-
-static const char*
-unum_getAvailable(int32_t localeIndex)
-{
- MOZ_CRASH("unum_getAvailable: Intl API disabled");
-}
-
-static UNumberFormat*
-unum_open(UNumberFormatStyle style, const UChar* pattern, int32_t patternLength,
- const char* locale, UParseError* parseErr, UErrorCode* status)
-{
- MOZ_CRASH("unum_open: Intl API disabled");
-}
-
-static void
-unum_setAttribute(UNumberFormat* fmt, UNumberFormatAttribute attr, int32_t newValue)
-{
- MOZ_CRASH("unum_setAttribute: Intl API disabled");
-}
-
-static int32_t
-unum_formatDouble(const UNumberFormat* fmt, double number, UChar* result,
- int32_t resultLength, UFieldPosition* pos, UErrorCode* status)
-{
- MOZ_CRASH("unum_formatDouble: Intl API disabled");
-}
-
-static void
-unum_close(UNumberFormat* fmt)
-{
- MOZ_CRASH("unum_close: Intl API disabled");
-}
-
-static void
-unum_setTextAttribute(UNumberFormat* fmt, UNumberFormatTextAttribute tag, const UChar* newValue,
- int32_t newValueLength, UErrorCode* status)
-{
- MOZ_CRASH("unum_setTextAttribute: Intl API disabled");
-}
-
-typedef void* UNumberingSystem;
-
-static UNumberingSystem*
-unumsys_open(const char* locale, UErrorCode* status)
-{
- MOZ_CRASH("unumsys_open: Intl API disabled");
-}
-
-static const char*
-unumsys_getName(const UNumberingSystem* unumsys)
-{
- MOZ_CRASH("unumsys_getName: Intl API disabled");
-}
-
-static void
-unumsys_close(UNumberingSystem* unumsys)
-{
- MOZ_CRASH("unumsys_close: Intl API disabled");
-}
-
-typedef void* UCalendar;
-
-enum UCalendarType {
- UCAL_TRADITIONAL,
- UCAL_DEFAULT = UCAL_TRADITIONAL,
- UCAL_GREGORIAN
-};
-
-enum UCalendarAttribute {
- UCAL_FIRST_DAY_OF_WEEK,
- UCAL_MINIMAL_DAYS_IN_FIRST_WEEK
-};
-
-enum UCalendarDaysOfWeek {
- UCAL_SUNDAY,
- UCAL_MONDAY,
- UCAL_TUESDAY,
- UCAL_WEDNESDAY,
- UCAL_THURSDAY,
- UCAL_FRIDAY,
- UCAL_SATURDAY
-};
-
-enum UCalendarWeekdayType {
- UCAL_WEEKDAY,
- UCAL_WEEKEND,
- UCAL_WEEKEND_ONSET,
- UCAL_WEEKEND_CEASE
-};
-
-enum UCalendarDateFields {
- UCAL_ERA,
- UCAL_YEAR,
- UCAL_MONTH,
- UCAL_WEEK_OF_YEAR,
- UCAL_WEEK_OF_MONTH,
- UCAL_DATE,
- UCAL_DAY_OF_YEAR,
- UCAL_DAY_OF_WEEK,
- UCAL_DAY_OF_WEEK_IN_MONTH,
- UCAL_AM_PM,
- UCAL_HOUR,
- UCAL_HOUR_OF_DAY,
- UCAL_MINUTE,
- UCAL_SECOND,
- UCAL_MILLISECOND,
- UCAL_ZONE_OFFSET,
- UCAL_DST_OFFSET,
- UCAL_YEAR_WOY,
- UCAL_DOW_LOCAL,
- UCAL_EXTENDED_YEAR,
- UCAL_JULIAN_DAY,
- UCAL_MILLISECONDS_IN_DAY,
- UCAL_IS_LEAP_MONTH,
- UCAL_FIELD_COUNT,
- UCAL_DAY_OF_MONTH = UCAL_DATE
-};
-
-static UCalendar*
-ucal_open(const UChar* zoneID, int32_t len, const char* locale,
- UCalendarType type, UErrorCode* status)
-{
- MOZ_CRASH("ucal_open: Intl API disabled");
-}
-
-static const char*
-ucal_getType(const UCalendar* cal, UErrorCode* status)
-{
- MOZ_CRASH("ucal_getType: Intl API disabled");
-}
-
-static UEnumeration*
-ucal_getKeywordValuesForLocale(const char* key, const char* locale,
- UBool commonlyUsed, UErrorCode* status)
-{
- MOZ_CRASH("ucal_getKeywordValuesForLocale: Intl API disabled");
-}
-
-static void
-ucal_close(UCalendar* cal)
-{
- MOZ_CRASH("ucal_close: Intl API disabled");
-}
-
-static UCalendarWeekdayType
-ucal_getDayOfWeekType(const UCalendar *cal, UCalendarDaysOfWeek dayOfWeek, UErrorCode* status)
-{
- MOZ_CRASH("ucal_getDayOfWeekType: Intl API disabled");
-}
-
-static int32_t
-ucal_getAttribute(const UCalendar* cal,
- UCalendarAttribute attr)
-{
- MOZ_CRASH("ucal_getAttribute: Intl API disabled");
-}
-
-static int32_t
-ucal_get(const UCalendar *cal, UCalendarDateFields field, UErrorCode *status)
-{
- MOZ_CRASH("ucal_get: Intl API disabled");
-}
-
-static UEnumeration*
-ucal_openTimeZones(UErrorCode* status)
-{
- MOZ_CRASH("ucal_openTimeZones: Intl API disabled");
-}
-
-static int32_t
-ucal_getCanonicalTimeZoneID(const UChar* id, int32_t len, UChar* result, int32_t resultCapacity,
- UBool* isSystemID, UErrorCode* status)
-{
- MOZ_CRASH("ucal_getCanonicalTimeZoneID: Intl API disabled");
-}
-
-static int32_t
-ucal_getDefaultTimeZone(UChar* result, int32_t resultCapacity, UErrorCode* status)
-{
- MOZ_CRASH("ucal_getDefaultTimeZone: Intl API disabled");
-}
-
-typedef void* UDateTimePatternGenerator;
-
-static UDateTimePatternGenerator*
-udatpg_open(const char* locale, UErrorCode* pErrorCode)
-{
- MOZ_CRASH("udatpg_open: Intl API disabled");
-}
-
-static int32_t
-udatpg_getBestPattern(UDateTimePatternGenerator* dtpg, const UChar* skeleton,
- int32_t length, UChar* bestPattern, int32_t capacity,
- UErrorCode* pErrorCode)
-{
- MOZ_CRASH("udatpg_getBestPattern: Intl API disabled");
-}
-
-static void
-udatpg_close(UDateTimePatternGenerator* dtpg)
-{
- MOZ_CRASH("udatpg_close: Intl API disabled");
-}
-
-typedef void* UCalendar;
-typedef void* UDateFormat;
-
-enum UDateFormatField {
- UDAT_ERA_FIELD = 0,
- UDAT_YEAR_FIELD = 1,
- UDAT_MONTH_FIELD = 2,
- UDAT_DATE_FIELD = 3,
- UDAT_HOUR_OF_DAY1_FIELD = 4,
- UDAT_HOUR_OF_DAY0_FIELD = 5,
- UDAT_MINUTE_FIELD = 6,
- UDAT_SECOND_FIELD = 7,
- UDAT_FRACTIONAL_SECOND_FIELD = 8,
- UDAT_DAY_OF_WEEK_FIELD = 9,
- UDAT_DAY_OF_YEAR_FIELD = 10,
- UDAT_DAY_OF_WEEK_IN_MONTH_FIELD = 11,
- UDAT_WEEK_OF_YEAR_FIELD = 12,
- UDAT_WEEK_OF_MONTH_FIELD = 13,
- UDAT_AM_PM_FIELD = 14,
- UDAT_HOUR1_FIELD = 15,
- UDAT_HOUR0_FIELD = 16,
- UDAT_TIMEZONE_FIELD = 17,
- UDAT_YEAR_WOY_FIELD = 18,
- UDAT_DOW_LOCAL_FIELD = 19,
- UDAT_EXTENDED_YEAR_FIELD = 20,
- UDAT_JULIAN_DAY_FIELD = 21,
- UDAT_MILLISECONDS_IN_DAY_FIELD = 22,
- UDAT_TIMEZONE_RFC_FIELD = 23,
- UDAT_TIMEZONE_GENERIC_FIELD = 24,
- UDAT_STANDALONE_DAY_FIELD = 25,
- UDAT_STANDALONE_MONTH_FIELD = 26,
- UDAT_QUARTER_FIELD = 27,
- UDAT_STANDALONE_QUARTER_FIELD = 28,
- UDAT_TIMEZONE_SPECIAL_FIELD = 29,
- UDAT_YEAR_NAME_FIELD = 30,
- UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD = 31,
- UDAT_TIMEZONE_ISO_FIELD = 32,
- UDAT_TIMEZONE_ISO_LOCAL_FIELD = 33,
- UDAT_RELATED_YEAR_FIELD = 34,
- UDAT_AM_PM_MIDNIGHT_NOON_FIELD = 35,
- UDAT_FLEXIBLE_DAY_PERIOD_FIELD = 36,
- UDAT_TIME_SEPARATOR_FIELD = 37,
- UDAT_FIELD_COUNT = 38
-};
-
-enum UDateFormatStyle {
- UDAT_PATTERN = -2,
- UDAT_IGNORE = UDAT_PATTERN
-};
-
-static int32_t
-udat_countAvailable()
-{
- MOZ_CRASH("udat_countAvailable: Intl API disabled");
-}
-
-static const char*
-udat_getAvailable(int32_t localeIndex)
-{
- MOZ_CRASH("udat_getAvailable: Intl API disabled");
-}
-
-static UDateFormat*
-udat_open(UDateFormatStyle timeStyle, UDateFormatStyle dateStyle, const char* locale,
- const UChar* tzID, int32_t tzIDLength, const UChar* pattern,
- int32_t patternLength, UErrorCode* status)
-{
- MOZ_CRASH("udat_open: Intl API disabled");
-}
-
-static const UCalendar*
-udat_getCalendar(const UDateFormat* fmt)
-{
- MOZ_CRASH("udat_getCalendar: Intl API disabled");
-}
-
-static void
-ucal_setGregorianChange(UCalendar* cal, UDate date, UErrorCode* pErrorCode)
-{
- MOZ_CRASH("ucal_setGregorianChange: Intl API disabled");
-}
-
-static int32_t
-udat_format(const UDateFormat* format, UDate dateToFormat, UChar* result,
- int32_t resultLength, UFieldPosition* position, UErrorCode* status)
-{
- MOZ_CRASH("udat_format: Intl API disabled");
-}
-
-static int32_t
-udat_formatForFields(const UDateFormat* format, UDate dateToFormat,
- UChar* result, int32_t resultLength, UFieldPositionIterator* fpositer,
- UErrorCode* status)
-{
- MOZ_CRASH("udat_formatForFields: Intl API disabled");
-}
-
-static UFieldPositionIterator*
-ufieldpositer_open(UErrorCode* status)
-{
- MOZ_CRASH("ufieldpositer_open: Intl API disabled");
-}
-
-static void
-ufieldpositer_close(UFieldPositionIterator* fpositer)
-{
- MOZ_CRASH("ufieldpositer_close: Intl API disabled");
-}
-
-static int32_t
-ufieldpositer_next(UFieldPositionIterator* fpositer, int32_t* beginIndex, int32_t* endIndex)
-{
- MOZ_CRASH("ufieldpositer_next: Intl API disabled");
-}
-
-static void
-udat_close(UDateFormat* format)
-{
- MOZ_CRASH("udat_close: Intl API disabled");
-}
-
-#endif
-
-
/******************** Common to Intl constructors ********************/
static bool
@@ -615,7 +107,6 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable,
if (!locales)
return false;
-#if ENABLE_INTL_API
uint32_t count = countAvailable();
RootedValue t(cx, BooleanValue(true));
for (uint32_t i = 0; i < count; i++) {
@@ -635,7 +126,7 @@ intl_availableLocales(JSContext* cx, CountAvailable countAvailable,
return false;
}
}
-#endif
+
result.setObject(*locales);
return true;
}
@@ -2921,6 +2412,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..9a1e44913 100644
--- a/js/src/builtin/Intl.h
+++ b/js/src/builtin/Intl.h
@@ -16,9 +16,7 @@
#include "js/GCAPI.h"
#include "js/GCHashTable.h"
-#if ENABLE_INTL_API
#include "unicode/utypes.h"
-#endif
/*
* The Intl module specified by standard ECMA-402,
@@ -387,7 +385,48 @@ intl_FormatDateTime(JSContext* cx, unsigned argc, Value* vp);
extern MOZ_MUST_USE bool
intl_GetCalendarInfo(JSContext* cx, unsigned argc, Value* vp);
-#if ENABLE_INTL_API
+/**
+ * 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);
+
/**
* Cast char16_t* strings to UChar* strings used by ICU.
*/
@@ -402,7 +441,18 @@ Char16ToUChar(char16_t* chars)
{
return reinterpret_cast<UChar*>(chars);
}
-#endif // ENABLE_INTL_API
+
+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);
+}
} // namespace js
diff --git a/js/src/builtin/Intl.js b/js/src/builtin/Intl.js
index 37c87365b..6391c3e70 100644
--- a/js/src/builtin/Intl.js
+++ b/js/src/builtin/Intl.js
@@ -21,9 +21,6 @@
intl_availableCalendars: false,
intl_patternForSkeleton: false,
intl_FormatDateTime: false,
- intl_SelectPluralRule: false,
- intl_GetPluralCategories: false,
- intl_GetCalendarInfo: false,
*/
/*
@@ -860,7 +857,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 +1184,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 +1196,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 +1270,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 +1320,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 +1377,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 +1708,6 @@ function Intl_Collator_compare_get() {
// Step 2.
return internals.boundCompare;
}
-_SetCanonicalName(Intl_Collator_compare_get, "get compare");
/**
@@ -1791,37 +1776,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 +1823,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 +1854,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 +1903,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 +1933,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 +2002,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 +2119,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 +2146,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 +2287,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 +2396,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 +2669,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 +2855,6 @@ function Intl_DateTimeFormat_format_get() {
// Step 2.
return internals.boundFormat;
}
-_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format");
function Intl_DateTimeFormat_formatToParts() {
@@ -2980,232 +2990,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 = [];
@@ -3362,5 +3146,5 @@ function Intl_getDisplayNames(locales, options) {
// 24. Return result.
return result;
-}
+}
diff --git a/js/src/builtin/IntlTimeZoneData.h b/js/src/builtin/IntlTimeZoneData.h
index f92c583df..fa808c0b9 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 = 2018e
#ifndef builtin_IntlTimeZoneData_h
#define builtin_IntlTimeZoneData_h
diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js
index 580629a13..434cd6529 100644
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -62,8 +62,8 @@ function MapIteratorNext() {
var O = this;
// Steps 2-3.
- if (!IsObject(O) || !IsMapIterator(O))
- return callFunction(CallMapIteratorMethodIfWrapped, O, "MapIteratorNext");
+ if (!IsObject(O) || (O = GuardToMapIterator(O)) === null)
+ return callFunction(CallMapIteratorMethodIfWrapped, this, "MapIteratorNext");
// Steps 4-5 (implemented in _GetNextMapEntryForIterator).
// Steps 8-9 (omitted).
@@ -82,7 +82,7 @@ function MapIteratorNext() {
// Steps 10.b-c (omitted).
// Step 6.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
var result;
if (itemKind === ITEM_KIND_KEY) {
diff --git a/js/src/builtin/Set.js b/js/src/builtin/Set.js
index 9af6cf8d1..e2571e66a 100644
--- a/js/src/builtin/Set.js
+++ b/js/src/builtin/Set.js
@@ -64,8 +64,8 @@ function SetIteratorNext() {
var O = this;
// Steps 2-3.
- if (!IsObject(O) || !IsSetIterator(O))
- return callFunction(CallSetIteratorMethodIfWrapped, O, "SetIteratorNext");
+ if (!IsObject(O) || (O = GuardToSetIterator(O)) === null)
+ return callFunction(CallSetIteratorMethodIfWrapped, this, "SetIteratorNext");
// Steps 4-5 (implemented in _GetNextSetEntryForIterator).
// Steps 8-9 (omitted).
@@ -83,7 +83,7 @@ function SetIteratorNext() {
// Steps 10.b-c (omitted).
// Step 6.
- var itemKind = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_ITEM_KIND);
+ var itemKind = UnsafeGetInt32FromReservedSlot(O, ITERATOR_SLOT_ITEM_KIND);
var result;
if (itemKind === ITEM_KIND_VALUE) {
diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js
index 4202d0de6..e5b2ad552 100644
--- a/js/src/builtin/String.js
+++ b/js/src/builtin/String.js
@@ -529,16 +529,17 @@ function String_iterator() {
}
function StringIteratorNext() {
- if (!IsObject(this) || !IsStringIterator(this)) {
+ var obj;
+ if (!IsObject(this) || (obj = GuardToStringIterator(this)) === null) {
return callFunction(CallStringIteratorMethodIfWrapped, this,
"StringIteratorNext");
}
- var S = UnsafeGetStringFromReservedSlot(this, ITERATOR_SLOT_TARGET);
+ var S = UnsafeGetStringFromReservedSlot(obj, ITERATOR_SLOT_TARGET);
// We know that JSString::MAX_LENGTH <= INT32_MAX (and assert this in
// SelfHostring.cpp) so our current index can never be anything other than
// an Int32Value.
- var index = UnsafeGetInt32FromReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX);
+ var index = UnsafeGetInt32FromReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX);
var size = S.length;
var result = { value: undefined, done: false };
@@ -556,7 +557,7 @@ function StringIteratorNext() {
}
}
- UnsafeSetReservedSlot(this, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
+ UnsafeSetReservedSlot(obj, ITERATOR_SLOT_NEXT_INDEX, index + charCount);
result.value = callFunction(String_substring, S, index, index + charCount);
return result;
@@ -659,11 +660,7 @@ function String_static_localeCompare(str1, str2) {
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, "String.localeCompare");
var locales = arguments.length > 2 ? arguments[2] : undefined;
var options = arguments.length > 3 ? arguments[3] : undefined;
-#if EXPOSE_INTL_API
return callFunction(String_localeCompare, str1, str2, locales, options);
-#else
- return callFunction(std_String_localeCompare, str1, str2, locales, options);
-#endif
}
// ES6 draft 2014-04-27 B.2.3.3
@@ -855,14 +852,12 @@ function String_static_toLocaleUpperCase(string) {
return callFunction(std_String_toLocaleUpperCase, string);
}
-#if EXPOSE_INTL_API
function String_static_normalize(string) {
if (arguments.length < 1)
ThrowTypeError(JSMSG_MISSING_FUN_ARG, 0, 'String.normalize');
var form = arguments.length > 1 ? arguments[1] : undefined;
return callFunction(std_String_normalize, string, form);
}
-#endif
function String_static_concat(string, arg1) {
if (arguments.length < 1)
diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp
index a14f9ba69..373b6c9ed 100644
--- a/js/src/builtin/TestingFunctions.cpp
+++ b/js/src/builtin/TestingFunctions.cpp
@@ -236,11 +236,7 @@ GetBuildConfiguration(JSContext* cx, unsigned argc, Value* vp)
if (!JS_SetProperty(cx, info, "binary-data", value))
return false;
-#ifdef EXPOSE_INTL_API
value = BooleanValue(true);
-#else
- value = BooleanValue(false);
-#endif
if (!JS_SetProperty(cx, info, "intl-api", value))
return false;
@@ -2092,7 +2088,7 @@ class CloneBufferObject : public NativeObject {
Rooted<CloneBufferObject*> obj(cx, Create(cx));
if (!obj)
return nullptr;
- auto data = js::MakeUnique<JSStructuredCloneData>();
+ auto data = js::MakeUnique<JSStructuredCloneData>(buffer->scope());
if (!data) {
ReportOutOfMemory(cx);
return nullptr;
@@ -2145,8 +2141,11 @@ class CloneBufferObject : public NativeObject {
return false;
size_t nbytes = JS_GetStringLength(args[0].toString());
MOZ_ASSERT(nbytes % sizeof(uint64_t) == 0);
- auto buf = js::MakeUnique<JSStructuredCloneData>(nbytes, nbytes, nbytes);
- js_memcpy(buf->Start(), str, nbytes);
+ auto buf = js::MakeUnique<JSStructuredCloneData>(JS::StructuredCloneScope::DifferentProcess);
+ if (!buf->AppendBytes(str, nbytes)) {
+ ReportOutOfMemory(cx);
+ return false;
+ }
JS_free(cx, str);
obj->setData(buf.release());
@@ -2190,7 +2189,7 @@ class CloneBufferObject : public NativeObject {
ReportOutOfMemory(cx);
return false;
}
- auto iter = obj->data()->Iter();
+ auto iter = obj->data()->Start();
obj->data()->ReadBytes(iter, buffer.get(), size);
JSString* str = JS_NewStringCopyN(cx, buffer.get(), size);
if (!str)
@@ -2248,6 +2247,8 @@ ParseCloneScope(JSContext* cx, HandleString str)
scope.emplace(JS::StructuredCloneScope::SameProcessDifferentThread);
else if (strcmp(scopeStr.ptr(), "DifferentProcess") == 0)
scope.emplace(JS::StructuredCloneScope::DifferentProcess);
+ else if (strcmp(scopeStr.ptr(), "DifferentProcessForIndexedDB") == 0)
+ scope.emplace(JS::StructuredCloneScope::DifferentProcessForIndexedDB);
return scope;
}
@@ -4374,19 +4375,22 @@ JS_FN_HELP("rejectPromise", RejectPromise, 2, 0,
" clone buffer object. 'policy' may be an options hash. Valid keys:\n"
" 'SharedArrayBuffer' - either 'allow' (the default) or 'deny'\n"
" to specify whether SharedArrayBuffers may be serialized.\n"
-"\n"
-" 'scope' - SameProcessSameThread, SameProcessDifferentThread, or\n"
-" DifferentProcess. Determines how some values will be serialized.\n"
-" Clone buffers may only be deserialized with a compatible scope."),
+" 'scope' - SameProcessSameThread, SameProcessDifferentThread,\n"
+" DifferentProcess, or DifferentProcessForIndexedDB. Determines how some\n"
+" values will be serialized. Clone buffers may only be deserialized with a\n"
+" compatible scope. NOTE - For DifferentProcess/DifferentProcessForIndexedDB,\n"
+" must also set SharedArrayBuffer:'deny' if data contains any shared memory\n"
+" object."),
JS_FN_HELP("deserialize", Deserialize, 1, 0,
"deserialize(clonebuffer[, opts])",
" Deserialize data generated by serialize. 'opts' is an options hash with one\n"
" recognized key 'scope', which limits the clone buffers that are considered\n"
" valid. Allowed values: 'SameProcessSameThread', 'SameProcessDifferentThread',\n"
-" and 'DifferentProcess'. So for example, a DifferentProcess clone buffer\n"
-" may be deserialized in any scope, but a SameProcessSameThread clone buffer\n"
-" cannot be deserialized in a DifferentProcess scope."),
+" 'DifferentProcess', and 'DifferentProcessForIndexedDB'. So for example, a\n"
+" DifferentProcessForIndexedDB clone buffer may be deserialized in any scope, but\n"
+" a SameProcessSameThread clone buffer cannot be deserialized in a\n"
+" DifferentProcess scope."),
JS_FN_HELP("detachArrayBuffer", DetachArrayBuffer, 1, 0,
"detachArrayBuffer(buffer)",
diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js
index a2205dc92..a1934051d 100644
--- a/js/src/builtin/TypedArray.js
+++ b/js/src/builtin/TypedArray.js
@@ -1232,11 +1232,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
// Steps 6-7.
// Omit the 'if' clause in step 6, since typed arrays can't have undefined
// or null elements.
-#if EXPOSE_INTL_API
var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement, locales, options));
-#else
- var R = ToString(callContentFunction(firstElement.toLocaleString, firstElement));
-#endif
// Step 3 (reordered).
// We don't (yet?) implement locale-dependent separators.
@@ -1258,11 +1254,7 @@ function TypedArrayToLocaleString(locales = undefined, options = undefined) {
// the error message. So despite bug 1079853, we can skip step 9.c.
// Step 9.d.
-#if EXPOSE_INTL_API
R = ToString(callContentFunction(nextElement.toLocaleString, nextElement, locales, options));
-#else
- R = ToString(callContentFunction(nextElement.toLocaleString, nextElement));
-#endif
// Step 9.e.
R = S + R;
diff --git a/js/src/gc/GCRuntime.h b/js/src/gc/GCRuntime.h
index 19737c9ee..5c2576efd 100644
--- a/js/src/gc/GCRuntime.h
+++ b/js/src/gc/GCRuntime.h
@@ -73,7 +73,7 @@ class ChunkPool
// Performs extra allocation off the main thread so that when memory is
// required on the main thread it will already be available and waiting.
-class BackgroundAllocTask : public GCParallelTask
+class BackgroundAllocTask : public GCParallelTaskHelper<BackgroundAllocTask>
{
// Guarded by the GC lock.
JSRuntime* runtime;
@@ -85,12 +85,11 @@ class BackgroundAllocTask : public GCParallelTask
BackgroundAllocTask(JSRuntime* rt, ChunkPool& pool);
bool enabled() const { return enabled_; }
- protected:
- void run() override;
+ void run();
};
-// Search the provided Chunks for free arenas and decommit them.
-class BackgroundDecommitTask : public GCParallelTask
+// Search the provided Chunks for free arenas and recommit them.
+class BackgroundDecommitTask : public GCParallelTaskHelper<BackgroundDecommitTask>
{
public:
using ChunkVector = mozilla::Vector<Chunk*>;
@@ -98,8 +97,7 @@ class BackgroundDecommitTask : public GCParallelTask
explicit BackgroundDecommitTask(JSRuntime *rt) : runtime(rt) {}
void setChunksToScan(ChunkVector &chunks);
- protected:
- void run() override;
+ void run();
private:
JSRuntime* runtime;
@@ -1171,8 +1169,10 @@ class GCRuntime
/*
* Concurrent sweep infrastructure.
*/
- void startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
- void joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked);
+ void startTask(GCParallelTask& task, gcstats::Phase phase,
+ AutoLockHelperThreadState& locked);
+ void joinTask(GCParallelTask& task, gcstats::Phase phase,
+ AutoLockHelperThreadState& locked);
/*
* List head of arenas allocated during the sweep phase.
diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp
index aa50bf29e..55ca5a059 100644
--- a/js/src/gc/Nursery.cpp
+++ b/js/src/gc/Nursery.cpp
@@ -43,19 +43,19 @@ using mozilla::PodZero;
static const uintptr_t CanaryMagicValue = 0xDEADB15D;
-struct js::Nursery::FreeMallocedBuffersTask : public GCParallelTask
+struct js::Nursery::FreeMallocedBuffersTask : public GCParallelTaskHelper<FreeMallocedBuffersTask>
{
explicit FreeMallocedBuffersTask(FreeOp* fop) : fop_(fop) {}
bool init() { return buffers_.init(); }
void transferBuffersToFree(MallocedBuffersSet& buffersToFree,
const AutoLockHelperThreadState& lock);
- ~FreeMallocedBuffersTask() override { join(); }
+ ~FreeMallocedBuffersTask() { join(); }
+
+ void run();
private:
FreeOp* fop_;
MallocedBuffersSet buffers_;
-
- virtual void run() override;
};
struct js::Nursery::SweepAction
diff --git a/js/src/gc/Statistics.h b/js/src/gc/Statistics.h
index c9e5871e3..ca1969b2c 100644
--- a/js/src/gc/Statistics.h
+++ b/js/src/gc/Statistics.h
@@ -22,9 +22,6 @@
using mozilla::Maybe;
namespace js {
-
-class GCParallelTask;
-
namespace gcstats {
enum Phase : uint8_t {
diff --git a/js/src/gdb/moz.build b/js/src/gdb/moz.build
index 681f9807c..faa69eb7b 100644
--- a/js/src/gdb/moz.build
+++ b/js/src/gdb/moz.build
@@ -34,7 +34,7 @@ USE_LIBS += [
'static:js',
]
-if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']:
+if CONFIG['MOZ_ICU_DATA_ARCHIVE']:
# The ICU libraries linked into libmozjs will not include the ICU data,
# so link it directly.
USE_LIBS += ['icudata']
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 7b2f8214b..16d026092 100644
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -11529,6 +11529,32 @@ CodeGenerator::visitHasClass(LHasClass* ins)
}
void
+CodeGenerator::visitGuardToClass(LGuardToClass* ins)
+{
+ Register lhs = ToRegister(ins->lhs());
+ Register output = ToRegister(ins->output());
+ Register temp = ToRegister(ins->temp());
+
+ Label notEqual;
+
+ masm.branchTestObjClass(Assembler::NotEqual, lhs, temp, ins->mir()->getClass(), &notEqual);
+ masm.mov(lhs, output);
+
+ if (ins->mir()->type() == MIRType::Object) {
+ // Can't return null-return here, so bail
+ bailoutFrom(&notEqual, ins->snapshot());
+ } else {
+ Label done;
+ masm.jump(&done);
+
+ masm.bind(&notEqual);
+ masm.mov(ImmPtr(0), output);
+
+ masm.bind(&done);
+ }
+}
+
+void
CodeGenerator::visitWasmParameter(LWasmParameter* lir)
{
}
diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h
index d3126651b..b226f6cc9 100644
--- a/js/src/jit/CodeGenerator.h
+++ b/js/src/jit/CodeGenerator.h
@@ -377,6 +377,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitIsObject(LIsObject* lir);
void visitIsObjectAndBranch(LIsObjectAndBranch* lir);
void visitHasClass(LHasClass* lir);
+ void visitGuardToClass(LGuardToClass* lir);
void visitWasmParameter(LWasmParameter* lir);
void visitWasmParameterI64(LWasmParameterI64* lir);
void visitWasmReturn(LWasmReturn* ret);
diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h
index 15352c04f..23d3143a7 100644
--- a/js/src/jit/InlinableNatives.h
+++ b/js/src/jit/InlinableNatives.h
@@ -117,13 +117,15 @@
_(IntrinsicDefineDataProperty) \
_(IntrinsicObjectHasPrototype) \
\
- _(IntrinsicIsArrayIterator) \
- _(IntrinsicIsMapIterator) \
- _(IntrinsicIsSetIterator) \
- _(IntrinsicIsStringIterator) \
+ _(IntrinsicGuardToArrayIterator) \
+ _(IntrinsicGuardToMapIterator) \
+ _(IntrinsicGuardToSetIterator) \
+ _(IntrinsicGuardToStringIterator) \
\
+ _(IntrinsicGuardToMapObject) \
_(IntrinsicGetNextMapEntryForIterator) \
\
+ _(IntrinsicGuardToSetObject) \
_(IntrinsicGetNextSetEntryForIterator) \
\
_(IntrinsicArrayBufferByteLength) \
diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h
index 35ad120f7..f24ef30c8 100644
--- a/js/src/jit/IonBuilder.h
+++ b/js/src/jit/IonBuilder.h
@@ -969,6 +969,7 @@ class IonBuilder
const Class* clasp2 = nullptr,
const Class* clasp3 = nullptr,
const Class* clasp4 = nullptr);
+ InliningStatus inlineGuardToClass(CallInfo& callInfo, const Class* clasp);
InliningStatus inlineIsConstructing(CallInfo& callInfo);
InliningStatus inlineSubstringKernel(CallInfo& callInfo);
InliningStatus inlineObjectHasPrototype(CallInfo& callInfo);
diff --git a/js/src/jit/JitFrameIterator.h b/js/src/jit/JitFrameIterator.h
index ba5efef6a..3620badbd 100644
--- a/js/src/jit/JitFrameIterator.h
+++ b/js/src/jit/JitFrameIterator.h
@@ -322,9 +322,7 @@ class RInstructionResults
MOZ_MUST_USE bool init(JSContext* cx, uint32_t numResults);
bool isInitialized() const;
-#ifdef DEBUG
size_t length() const;
-#endif
JitFrameLayout* frame() const;
diff --git a/js/src/jit/JitFrames.cpp b/js/src/jit/JitFrames.cpp
index f11f17225..019be46dd 100644
--- a/js/src/jit/JitFrames.cpp
+++ b/js/src/jit/JitFrames.cpp
@@ -1688,13 +1688,11 @@ RInstructionResults::isInitialized() const
return initialized_;
}
-#ifdef DEBUG
size_t
RInstructionResults::length() const
{
return results_->length();
}
-#endif
JitFrameLayout*
RInstructionResults::frame() const
@@ -2150,7 +2148,7 @@ SnapshotIterator::initInstructionResults(MaybeReadFallback& fallback)
}
MOZ_ASSERT(results->isInitialized());
- MOZ_ASSERT(results->length() == recover_.numInstructions() - 1);
+ MOZ_RELEASE_ASSERT(results->length() == recover_.numInstructions() - 1);
instructionResults_ = results;
return true;
}
diff --git a/js/src/jit/Lowering.cpp b/js/src/jit/Lowering.cpp
index 730697163..709de9987 100644
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -4171,6 +4171,16 @@ LIRGenerator::visitHasClass(MHasClass* ins)
}
void
+LIRGenerator::visitGuardToClass(MGuardToClass* ins)
+{
+ MOZ_ASSERT(ins->object()->type() == MIRType::Object);
+ MOZ_ASSERT(ins->type() == MIRType::ObjectOrNull|| ins->type() == MIRType::Object);
+ LGuardToClass* lir = new(alloc()) LGuardToClass(useRegister(ins->object()), temp());
+ assignSnapshot(lir, Bailout_TypeBarrierO);
+ define(lir, ins);
+}
+
+void
LIRGenerator::visitWasmAddOffset(MWasmAddOffset* ins)
{
MOZ_ASSERT(ins->base()->type() == MIRType::Int32);
diff --git a/js/src/jit/Lowering.h b/js/src/jit/Lowering.h
index b2805cb7a..9b4095aec 100644
--- a/js/src/jit/Lowering.h
+++ b/js/src/jit/Lowering.h
@@ -289,6 +289,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitIsConstructor(MIsConstructor* ins);
void visitIsObject(MIsObject* ins);
void visitHasClass(MHasClass* ins);
+ void visitGuardToClass(MGuardToClass* ins);
void visitWasmAddOffset(MWasmAddOffset* ins);
void visitWasmBoundsCheck(MWasmBoundsCheck* ins);
void visitWasmLoadGlobalVar(MWasmLoadGlobalVar* ins);
diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp
index 293253253..736c6c892 100644
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -280,24 +280,28 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineIsConstructing(callInfo);
case InlinableNative::IntrinsicSubstringKernel:
return inlineSubstringKernel(callInfo);
- case InlinableNative::IntrinsicIsArrayIterator:
- return inlineHasClass(callInfo, &ArrayIteratorObject::class_);
- case InlinableNative::IntrinsicIsMapIterator:
- return inlineHasClass(callInfo, &MapIteratorObject::class_);
- case InlinableNative::IntrinsicIsSetIterator:
- return inlineHasClass(callInfo, &SetIteratorObject::class_);
- case InlinableNative::IntrinsicIsStringIterator:
- return inlineHasClass(callInfo, &StringIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToArrayIterator:
+ return inlineGuardToClass(callInfo, &ArrayIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToMapIterator:
+ return inlineGuardToClass(callInfo, &MapIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToSetIterator:
+ return inlineGuardToClass(callInfo, &SetIteratorObject::class_);
+ case InlinableNative::IntrinsicGuardToStringIterator:
+ return inlineGuardToClass(callInfo, &StringIteratorObject::class_);
case InlinableNative::IntrinsicDefineDataProperty:
return inlineDefineDataProperty(callInfo);
case InlinableNative::IntrinsicObjectHasPrototype:
return inlineObjectHasPrototype(callInfo);
// Map intrinsics.
+ case InlinableNative::IntrinsicGuardToMapObject:
+ return inlineGuardToClass(callInfo, &MapObject::class_);
case InlinableNative::IntrinsicGetNextMapEntryForIterator:
return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Map);
// Set intrinsics.
+ case InlinableNative::IntrinsicGuardToSetObject:
+ return inlineGuardToClass(callInfo, &SetObject::class_);
case InlinableNative::IntrinsicGetNextSetEntryForIterator:
return inlineGetNextEntryForIterator(callInfo, MGetNextEntryForIterator::Set);
@@ -2218,6 +2222,37 @@ IonBuilder::inlineHasClass(CallInfo& callInfo,
}
IonBuilder::InliningStatus
+IonBuilder::inlineGuardToClass(CallInfo& callInfo, const Class* clasp)
+{
+ MOZ_ASSERT(!callInfo.constructing());
+ MOZ_ASSERT(callInfo.argc() == 1);
+
+ if (callInfo.getArg(0)->type() != MIRType::Object)
+ return InliningStatus_NotInlined;
+
+ if (getInlineReturnType() != MIRType::ObjectOrNull &&
+ getInlineReturnType() != MIRType::Object)
+ {
+ return InliningStatus_NotInlined;
+ }
+
+ TemporaryTypeSet* types = callInfo.getArg(0)->resultTypeSet();
+ const Class* knownClass = types ? types->getKnownClass(constraints()) : nullptr;
+
+ if (knownClass && knownClass == clasp) {
+ current->push(callInfo.getArg(0));
+ } else {
+ MGuardToClass* guardToClass = MGuardToClass::New(alloc(), callInfo.getArg(0),
+ clasp, getInlineReturnType());
+ current->add(guardToClass);
+ current->push(guardToClass);
+ }
+
+ callInfo.setImplicitlyUsedUnchecked();
+ return InliningStatus_Inlined;
+}
+
+IonBuilder::InliningStatus
IonBuilder::inlineGetNextEntryForIterator(CallInfo& callInfo, MGetNextEntryForIterator::Mode mode)
{
if (callInfo.argc() != 2 || callInfo.constructing()) {
diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h
index 2de91e2df..6ec05af76 100644
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -13192,6 +13192,48 @@ class MHasClass
}
};
+class MGuardToClass
+ : public MUnaryInstruction,
+ public SingleObjectPolicy::Data
+{
+ const Class* class_;
+
+ MGuardToClass(MDefinition* object, const Class* clasp, MIRType resultType)
+ : MUnaryInstruction(object)
+ , class_(clasp)
+ {
+ MOZ_ASSERT(object->type() == MIRType::Object ||
+ (object->type() == MIRType::Value && object->mightBeType(MIRType::Object)));
+ MOZ_ASSERT(resultType == MIRType::Object || resultType == MIRType::ObjectOrNull);
+ setResultType(resultType);
+ setMovable();
+ if (resultType == MIRType::Object) {
+ // We will bail out if the class type is incorrect,
+ // so we need to ensure we don't eliminate this instruction
+ setGuard();
+ }
+ }
+
+ public:
+ INSTRUCTION_HEADER(GuardToClass)
+ TRIVIAL_NEW_WRAPPERS
+ NAMED_OPERANDS((0, object))
+
+ const Class* getClass() const {
+ return class_;
+ }
+ AliasSet getAliasSet() const override {
+ return AliasSet::None();
+ }
+ bool congruentTo(const MDefinition* ins) const override {
+ if (!ins->isGuardToClass())
+ return false;
+ if (getClass() != ins->toGuardToClass()->getClass())
+ return false;
+ return congruentIfOperandsEqual(ins);
+ }
+};
+
class MCheckReturn
: public MBinaryInstruction,
public BoxInputsPolicy::Data
diff --git a/js/src/jit/MOpcodes.h b/js/src/jit/MOpcodes.h
index bb2ab8190..fddc1e637 100644
--- a/js/src/jit/MOpcodes.h
+++ b/js/src/jit/MOpcodes.h
@@ -272,6 +272,7 @@ namespace jit {
_(IsCallable) \
_(IsObject) \
_(HasClass) \
+ _(GuardToClass) \
_(CopySign) \
_(Rotate) \
_(NewDerivedTypedObject) \
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/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/shared/LIR-shared.h b/js/src/jit/shared/LIR-shared.h
index 9dcb527c5..f4adcc63c 100644
--- a/js/src/jit/shared/LIR-shared.h
+++ b/js/src/jit/shared/LIR-shared.h
@@ -7867,6 +7867,29 @@ class LHasClass : public LInstructionHelper<1, 1, 0>
}
};
+class LGuardToClass : public LInstructionHelper<1, 1, 1>
+{
+ public:
+ LIR_HEADER(GuardToClass);
+ explicit LGuardToClass(const LAllocation& lhs, const LDefinition& temp)
+ {
+ setOperand(0, lhs);
+ setTemp(0, temp);
+ }
+
+ const LAllocation* lhs() {
+ return getOperand(0);
+ }
+
+ const LDefinition* temp() {
+ return getTemp(0);
+ }
+
+ MGuardToClass* mir() const {
+ return mir_->toGuardToClass();
+ }
+};
+
template<size_t Defs, size_t Ops>
class LWasmSelectBase : public LInstructionHelper<Defs, Ops, 0>
{
diff --git a/js/src/jit/shared/LOpcodes-shared.h b/js/src/jit/shared/LOpcodes-shared.h
index 3eea1b449..fe2ab5ea3 100644
--- a/js/src/jit/shared/LOpcodes-shared.h
+++ b/js/src/jit/shared/LOpcodes-shared.h
@@ -386,6 +386,7 @@
_(IsObject) \
_(IsObjectAndBranch) \
_(HasClass) \
+ _(GuardToClass) \
_(RecompileCheck) \
_(MemoryBarrier) \
_(AssertRangeI) \
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/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/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build
index f7a6080aa..277a145b0 100644
--- a/js/src/jsapi-tests/moz.build
+++ b/js/src/jsapi-tests/moz.build
@@ -135,7 +135,7 @@ LOCAL_INCLUDES += [
'..',
]
-if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']:
+if CONFIG['MOZ_ICU_DATA_ARCHIVE']:
# The ICU libraries linked into libmozjs will not include the ICU data,
# so link it directly.
USE_LIBS += ['icudata']
diff --git a/js/src/jsapi.h b/js/src/jsapi.h
index 989abe47c..c1195cc00 100644
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -5222,7 +5222,7 @@ JS_ResetDefaultLocale(JSContext* cx);
struct JSLocaleCallbacks {
JSLocaleToUpperCase localeToUpperCase;
JSLocaleToLowerCase localeToLowerCase;
- JSLocaleCompare localeCompare; // not used #if EXPOSE_INTL_API
+ JSLocaleCompare localeCompare; // not used
JSLocaleToUnicode localeToUnicode;
};
diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp
index ccaeda2a3..52294a5df 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);
@@ -2731,77 +2743,6 @@ ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, Mutabl
return true;
}
-#if !EXPOSE_INTL_API
-/* ES5 15.9.5.5. */
-MOZ_ALWAYS_INLINE bool
-date_toLocaleString_impl(JSContext* cx, const CallArgs& args)
-{
- /*
- * Use '%#c' for windows, because '%c' is backward-compatible and non-y2k
- * with msvc; '%#c' requests that a full year be used in the result string.
- */
- static const char format[] =
-#if defined(_WIN32) && !defined(__MWERKS__)
- "%#c"
-#else
- "%c"
-#endif
- ;
-
- Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
- return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
-}
-
-static bool
-date_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsDate, date_toLocaleString_impl>(cx, args);
-}
-
-/* ES5 15.9.5.6. */
-MOZ_ALWAYS_INLINE bool
-date_toLocaleDateString_impl(JSContext* cx, const CallArgs& args)
-{
- /*
- * Use '%#x' for windows, because '%x' is backward-compatible and non-y2k
- * with msvc; '%#x' requests that a full year be used in the result string.
- */
- static const char format[] =
-#if defined(_WIN32) && !defined(__MWERKS__)
- "%#x"
-#else
- "%x"
-#endif
- ;
-
- Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
- return ToLocaleFormatHelper(cx, dateObj, format, args.rval());
-}
-
-static bool
-date_toLocaleDateString(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsDate, date_toLocaleDateString_impl>(cx, args);
-}
-
-/* ES5 15.9.5.7. */
-MOZ_ALWAYS_INLINE bool
-date_toLocaleTimeString_impl(JSContext* cx, const CallArgs& args)
-{
- Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
- return ToLocaleFormatHelper(cx, dateObj, "%X", args.rval());
-}
-
-static bool
-date_toLocaleTimeString(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsDate, date_toLocaleTimeString_impl>(cx, args);
-}
-#endif /* !EXPOSE_INTL_API */
-
MOZ_ALWAYS_INLINE bool
date_toLocaleFormat_impl(JSContext* cx, const CallArgs& args)
{
@@ -3025,15 +2966,9 @@ static const JSFunctionSpec date_methods[] = {
JS_FN("setUTCMilliseconds", date_setUTCMilliseconds, 1,0),
JS_FN("toUTCString", date_toGMTString, 0,0),
JS_FN("toLocaleFormat", date_toLocaleFormat, 0,0),
-#if EXPOSE_INTL_API
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Date_toLocaleString", 0,0),
JS_SELF_HOSTED_FN("toLocaleDateString", "Date_toLocaleDateString", 0,0),
JS_SELF_HOSTED_FN("toLocaleTimeString", "Date_toLocaleTimeString", 0,0),
-#else
- JS_FN(js_toLocaleString_str, date_toLocaleString, 0,0),
- JS_FN("toLocaleDateString", date_toLocaleDateString, 0,0),
- JS_FN("toLocaleTimeString", date_toLocaleTimeString, 0,0),
-#endif
JS_FN("toDateString", date_toDateString, 0,0),
JS_FN("toTimeString", date_toTimeString, 0,0),
JS_FN("toISOString", date_toISOString, 0,0),
diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp
index 45301dac8..3d4dae9bb 100644
--- a/js/src/jsgc.cpp
+++ b/js/src/jsgc.cpp
@@ -2156,7 +2156,7 @@ ArenasToUpdate::getArenasToUpdate(AutoLockHelperThreadState& lock, unsigned maxL
return { begin, last->next };
}
-struct UpdatePointersTask : public GCParallelTask
+struct UpdatePointersTask : public GCParallelTaskHelper<UpdatePointersTask>
{
// Maximum number of arenas to update in one block.
#ifdef DEBUG
@@ -2172,14 +2172,13 @@ struct UpdatePointersTask : public GCParallelTask
arenas_.end = nullptr;
}
- ~UpdatePointersTask() override { join(); }
+ void run();
private:
JSRuntime* rt_;
ArenasToUpdate* source_;
ArenaListSegment arenas_;
- virtual void run() override;
bool getArenasToUpdate();
void updateArenas();
};
@@ -2276,7 +2275,7 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s
for (size_t i = 0; i < bgTaskCount && !bgArenas.done(); i++) {
bgTasks[i].emplace(rt, &bgArenas, lock);
startTask(*bgTasks[i], gcstats::PHASE_COMPACT_UPDATE_CELLS, lock);
- tasksStarted = i;
+ tasksStarted++;
}
}
@@ -2985,7 +2984,6 @@ js::gc::BackgroundDecommitTask::run()
AutoLockGC lock(runtime);
for (Chunk* chunk : toDecommit) {
-
// The arena list is not doubly-linked, so we have to work in the free
// list order and not in the natural order.
while (chunk->info.numArenasFreeCommitted) {
@@ -4359,7 +4357,8 @@ GCRuntime::endMarkingZoneGroup()
marker.setMarkColorBlack();
}
-class GCSweepTask : public GCParallelTask
+template <typename Derived>
+class GCSweepTask : public GCParallelTaskHelper<Derived>
{
GCSweepTask(const GCSweepTask&) = delete;
@@ -4369,13 +4368,13 @@ class GCSweepTask : public GCParallelTask
public:
explicit GCSweepTask(JSRuntime* rt) : runtime(rt) {}
GCSweepTask(GCSweepTask&& other)
- : GCParallelTask(mozilla::Move(other)),
+ : GCParallelTaskHelper<Derived>(mozilla::Move(other)),
runtime(other.runtime)
{}
};
// Causes the given WeakCache to be swept when run.
-class SweepWeakCacheTask : public GCSweepTask
+class SweepWeakCacheTask : public GCSweepTask<SweepWeakCacheTask>
{
JS::WeakCache<void*>& cache;
@@ -4387,15 +4386,15 @@ class SweepWeakCacheTask : public GCSweepTask
: GCSweepTask(mozilla::Move(other)), cache(other.cache)
{}
- void run() override {
+ void run() {
cache.sweep();
}
};
#define MAKE_GC_SWEEP_TASK(name) \
- class name : public GCSweepTask { \
- void run() override; \
+ class name : public GCSweepTask<name> { \
public: \
+ void run(); \
explicit name (JSRuntime* rt) : GCSweepTask(rt) {} \
}
MAKE_GC_SWEEP_TASK(SweepAtomsTask);
@@ -4447,7 +4446,8 @@ SweepMiscTask::run()
}
void
-GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
+GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase,
+ AutoLockHelperThreadState& locked)
{
if (!task.startWithLockHeld(locked)) {
AutoUnlockHelperThreadState unlock(locked);
@@ -4457,7 +4457,8 @@ GCRuntime::startTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperT
}
void
-GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase, AutoLockHelperThreadState& locked)
+GCRuntime::joinTask(GCParallelTask& task, gcstats::Phase phase,
+ AutoLockHelperThreadState& locked)
{
gcstats::AutoPhase ap(stats, task, phase);
task.joinWithLockHeld(locked);
diff --git a/js/src/jsgc.h b/js/src/jsgc.h
index 7ad176d84..d3cf31fe7 100644
--- a/js/src/jsgc.h
+++ b/js/src/jsgc.h
@@ -12,6 +12,7 @@
#include "mozilla/Atomics.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
#include "mozilla/TypeTraits.h"
#include "js/GCAPI.h"
@@ -936,10 +937,19 @@ class GCHelperState
};
// A generic task used to dispatch work to the helper thread system.
-// Users should derive from GCParallelTask add what data they need and
-// override |run|.
+// Users supply a function pointer to call.
+//
+// Note that we don't use virtual functions here because destructors can write
+// the vtable pointer on entry, which can causes races if synchronization
+// happens there.
class GCParallelTask
{
+ public:
+ using TaskFunc = void (*)(GCParallelTask*);
+
+ private:
+ TaskFunc func_;
+
// The state of the parallel computation.
enum TaskState {
NotStarted,
@@ -956,19 +966,24 @@ class GCParallelTask
// A flag to signal a request for early completion of the off-thread task.
mozilla::Atomic<bool> cancel_;
- virtual void run() = 0;
-
public:
- GCParallelTask() : state(NotStarted), duration_(0) {}
+ explicit GCParallelTask(TaskFunc func)
+ : func_(func),
+ state(NotStarted),
+ duration_(0),
+ cancel_(false)
+ {}
+
GCParallelTask(GCParallelTask&& other)
- : state(other.state),
+ : func_(other.func_),
+ state(other.state),
duration_(0),
cancel_(false)
{}
// Derived classes must override this to ensure that join() gets called
// before members get destructed.
- virtual ~GCParallelTask();
+ ~GCParallelTask();
// Time spent in the most recent invocation of this task.
int64_t duration() const { return duration_; }
@@ -997,12 +1012,34 @@ class GCParallelTask
bool isRunningWithLockHeld(const AutoLockHelperThreadState& locked) const;
bool isRunning() const;
+ void runTask() {
+ func_(this);
+ }
+
// This should be friended to HelperThread, but cannot be because it
// would introduce several circular dependencies.
public:
void runFromHelperThread(AutoLockHelperThreadState& locked);
};
+// CRTP template to handle cast to derived type when calling run().
+template <typename Derived>
+class GCParallelTaskHelper : public GCParallelTask
+{
+ public:
+ GCParallelTaskHelper()
+ : GCParallelTask(&runTaskTyped)
+ {}
+ GCParallelTaskHelper(GCParallelTaskHelper&& other)
+ : GCParallelTask(mozilla::Move(other))
+ {}
+
+ private:
+ static void runTaskTyped(GCParallelTask* task) {
+ static_cast<Derived*>(task)->run();
+ }
+};
+
typedef void (*IterateChunkCallback)(JSRuntime* rt, void* data, gc::Chunk* chunk);
typedef void (*IterateZoneCallback)(JSRuntime* rt, void* data, JS::Zone* zone);
typedef void (*IterateArenaCallback)(JSRuntime* rt, void* data, gc::Arena* arena,
diff --git a/js/src/jsnativestack.cpp b/js/src/jsnativestack.cpp
index 05928ea3d..166a5a4f7 100644
--- a/js/src/jsnativestack.cpp
+++ b/js/src/jsnativestack.cpp
@@ -21,6 +21,18 @@
# include <unistd.h>
# endif
+# if defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
+# include <dlfcn.h>
+# include <sys/syscall.h>
+# include <sys/types.h>
+# include <unistd.h>
+static pid_t
+gettid()
+{
+ return syscall(__NR_gettid);
+}
+# endif
+
#else
# error "Unsupported platform"
@@ -88,6 +100,52 @@ js::GetNativeStackBaseImpl()
context.uc_stack.ss_size;
}
+#elif defined(XP_LINUX) && !defined(ANDROID) && defined(__GLIBC__)
+void*
+js::GetNativeStackBaseImpl()
+{
+ // On the main thread, get stack base from glibc's __libc_stack_end rather than pthread APIs
+ // to avoid filesystem calls /proc/self/maps. Non-main threads spawned with pthreads can read
+ // this information directly from their pthread struct, but when using the pthreads API, the
+ // main thread must go parse /proc/self/maps to figure the mapped stack address space ranges.
+ // We want to avoid reading from /proc/ so that the application can run in restricted
+ // environments where /proc may not be mounted (e.g. chroot).
+ if (gettid() == getpid()) {
+ void** pLibcStackEnd = (void**)dlsym(RTLD_DEFAULT, "__libc_stack_end");
+
+ // If __libc_stack_end is not found, architecture specific frame pointer hopping will need
+ // to be implemented.
+ MOZ_RELEASE_ASSERT(pLibcStackEnd, "__libc_stack_end unavailable, unable to setup stack range for JS.");
+ void* stackBase = *pLibcStackEnd;
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
+
+ // We don't need to fix stackBase, as it already roughly points to beginning of the stack.
+ return stackBase;
+ }
+
+ // Non-main threads have the required info stored in memory, so no filesystem calls are made.
+ pthread_t thread = pthread_self();
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+ pthread_getattr_np(thread, &sattr);
+
+ // stackBase will be the *lowest* address on all architectures.
+ void* stackBase = nullptr;
+ size_t stackSize = 0;
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ if (rc) {
+ MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS.");
+ }
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
+ pthread_attr_destroy(&sattr);
+
+# if JS_STACK_GROWTH_DIRECTION > 0
+ return stackBase;
+# else
+ return static_cast<char*>(stackBase) + stackSize;
+# endif
+}
+
#else /* XP_UNIX */
void*
@@ -156,11 +214,15 @@ js::GetNativeStackBaseImpl()
// the truth.
rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
# else
+ // Use the default pthread_attr_getstack() call. Note that this function
+ // differs between libc implementations and could imply /proc access etc.
+ // which may not work in restricted environments.
rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
# endif
- if (rc)
- MOZ_CRASH();
- MOZ_ASSERT(stackBase);
+ if (rc) {
+ MOZ_CRASH("Call to pthread_attr_getstack failed, unable to setup stack range for JS.");
+ }
+ MOZ_RELEASE_ASSERT(stackBase, "Invalid stack base, unable to setup stack range for JS.");
pthread_attr_destroy(&sattr);
# if JS_STACK_GROWTH_DIRECTION > 0
diff --git a/js/src/jsnum.cpp b/js/src/jsnum.cpp
index 8885737f7..28ed15159 100644
--- a/js/src/jsnum.cpp
+++ b/js/src/jsnum.cpp
@@ -724,141 +724,6 @@ js::num_toString(JSContext* cx, unsigned argc, Value* vp)
return CallNonGenericMethod<IsNumber, num_toString_impl>(cx, args);
}
-#if !EXPOSE_INTL_API
-MOZ_ALWAYS_INLINE bool
-num_toLocaleString_impl(JSContext* cx, const CallArgs& args)
-{
- MOZ_ASSERT(IsNumber(args.thisv()));
-
- double d = Extract(args.thisv());
-
- RootedString str(cx, NumberToStringWithBase<CanGC>(cx, d, 10));
- if (!str) {
- JS_ReportOutOfMemory(cx);
- return false;
- }
-
- /*
- * Create the string, move back to bytes to make string twiddling
- * a bit easier and so we can insert platform charset seperators.
- */
- JSAutoByteString numBytes(cx, str);
- if (!numBytes)
- return false;
- const char* num = numBytes.ptr();
- if (!num)
- return false;
-
- /*
- * Find the first non-integer value, whether it be a letter as in
- * 'Infinity', a decimal point, or an 'e' from exponential notation.
- */
- const char* nint = num;
- if (*nint == '-')
- nint++;
- while (*nint >= '0' && *nint <= '9')
- nint++;
- int digits = nint - num;
- const char* end = num + digits;
- if (!digits) {
- args.rval().setString(str);
- return true;
- }
-
- JSRuntime* rt = cx->runtime();
- size_t thousandsLength = strlen(rt->thousandsSeparator);
- size_t decimalLength = strlen(rt->decimalSeparator);
-
- /* Figure out how long resulting string will be. */
- int buflen = strlen(num);
- if (*nint == '.')
- buflen += decimalLength - 1; /* -1 to account for existing '.' */
-
- const char* numGrouping;
- const char* tmpGroup;
- numGrouping = tmpGroup = rt->numGrouping;
- int remainder = digits;
- if (*num == '-')
- remainder--;
-
- while (*tmpGroup != CHAR_MAX && *tmpGroup != '\0') {
- if (*tmpGroup >= remainder)
- break;
- buflen += thousandsLength;
- remainder -= *tmpGroup;
- tmpGroup++;
- }
-
- int nrepeat;
- if (*tmpGroup == '\0' && *numGrouping != '\0') {
- nrepeat = (remainder - 1) / tmpGroup[-1];
- buflen += thousandsLength * nrepeat;
- remainder -= nrepeat * tmpGroup[-1];
- } else {
- nrepeat = 0;
- }
- tmpGroup--;
-
- char* buf = cx->pod_malloc<char>(buflen + 1);
- if (!buf)
- return false;
-
- char* tmpDest = buf;
- const char* tmpSrc = num;
-
- while (*tmpSrc == '-' || remainder--) {
- MOZ_ASSERT(tmpDest - buf < buflen);
- *tmpDest++ = *tmpSrc++;
- }
- while (tmpSrc < end) {
- MOZ_ASSERT(tmpDest - buf + ptrdiff_t(thousandsLength) <= buflen);
- strcpy(tmpDest, rt->thousandsSeparator);
- tmpDest += thousandsLength;
- MOZ_ASSERT(tmpDest - buf + *tmpGroup <= buflen);
- js_memcpy(tmpDest, tmpSrc, *tmpGroup);
- tmpDest += *tmpGroup;
- tmpSrc += *tmpGroup;
- if (--nrepeat < 0)
- tmpGroup--;
- }
-
- if (*nint == '.') {
- MOZ_ASSERT(tmpDest - buf + ptrdiff_t(decimalLength) <= buflen);
- strcpy(tmpDest, rt->decimalSeparator);
- tmpDest += decimalLength;
- MOZ_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint + 1)) <= buflen);
- strcpy(tmpDest, nint + 1);
- } else {
- MOZ_ASSERT(tmpDest - buf + ptrdiff_t(strlen(nint)) <= buflen);
- strcpy(tmpDest, nint);
- }
-
- if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeToUnicode) {
- Rooted<Value> v(cx, StringValue(str));
- bool ok = !!cx->runtime()->localeCallbacks->localeToUnicode(cx, buf, &v);
- if (ok)
- args.rval().set(v);
- js_free(buf);
- return ok;
- }
-
- str = NewStringCopyN<CanGC>(cx, buf, buflen);
- js_free(buf);
- if (!str)
- return false;
-
- args.rval().setString(str);
- return true;
-}
-
-static bool
-num_toLocaleString(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- return CallNonGenericMethod<IsNumber, num_toLocaleString_impl>(cx, args);
-}
-#endif /* !EXPOSE_INTL_API */
-
MOZ_ALWAYS_INLINE bool
num_valueOf_impl(JSContext* cx, const CallArgs& args)
{
@@ -1075,11 +940,7 @@ static const JSFunctionSpec number_methods[] = {
JS_FN(js_toSource_str, num_toSource, 0, 0),
#endif
JS_FN(js_toString_str, num_toString, 1, 0),
-#if EXPOSE_INTL_API
JS_SELF_HOSTED_FN(js_toLocaleString_str, "Number_toLocaleString", 0,0),
-#else
- JS_FN(js_toLocaleString_str, num_toLocaleString, 0,0),
-#endif
JS_FN(js_valueOf_str, num_valueOf, 0, 0),
JS_FN("toFixed", num_toFixed, 1, 0),
JS_FN("toExponential", num_toExponential, 1, 0),
@@ -1130,76 +991,11 @@ js::FIX_FPU()
#endif
}
-bool
+void
js::InitRuntimeNumberState(JSRuntime* rt)
{
FIX_FPU();
-
- // XXX If EXPOSE_INTL_API becomes true all the time at some point,
- // js::InitRuntimeNumberState is no longer fallible, and we should
- // change its return type.
-#if !EXPOSE_INTL_API
- /* Copy locale-specific separators into the runtime strings. */
- const char* thousandsSeparator;
- const char* decimalPoint;
- const char* grouping;
-#ifdef HAVE_LOCALECONV
- struct lconv* locale = localeconv();
- thousandsSeparator = locale->thousands_sep;
- decimalPoint = locale->decimal_point;
- grouping = locale->grouping;
-#else
- thousandsSeparator = getenv("LOCALE_THOUSANDS_SEP");
- decimalPoint = getenv("LOCALE_DECIMAL_POINT");
- grouping = getenv("LOCALE_GROUPING");
-#endif
- if (!thousandsSeparator)
- thousandsSeparator = "'";
- if (!decimalPoint)
- decimalPoint = ".";
- if (!grouping)
- grouping = "\3\0";
-
- /*
- * We use single malloc to get the memory for all separator and grouping
- * strings.
- */
- size_t thousandsSeparatorSize = strlen(thousandsSeparator) + 1;
- size_t decimalPointSize = strlen(decimalPoint) + 1;
- size_t groupingSize = strlen(grouping) + 1;
-
- char* storage = js_pod_malloc<char>(thousandsSeparatorSize +
- decimalPointSize +
- groupingSize);
- if (!storage)
- return false;
-
- js_memcpy(storage, thousandsSeparator, thousandsSeparatorSize);
- rt->thousandsSeparator = storage;
- storage += thousandsSeparatorSize;
-
- js_memcpy(storage, decimalPoint, decimalPointSize);
- rt->decimalSeparator = storage;
- storage += decimalPointSize;
-
- js_memcpy(storage, grouping, groupingSize);
- rt->numGrouping = grouping;
-#endif /* !EXPOSE_INTL_API */
- return true;
-}
-
-#if !EXPOSE_INTL_API
-void
-js::FinishRuntimeNumberState(JSRuntime* rt)
-{
- /*
- * The free also releases the memory for decimalSeparator and numGrouping
- * strings.
- */
- char* storage = const_cast<char*>(rt->thousandsSeparator);
- js_free(storage);
}
-#endif
JSObject*
js::InitNumberClass(JSContext* cx, HandleObject obj)
diff --git a/js/src/jsnum.h b/js/src/jsnum.h
index 62b3d617f..8dff45f69 100644
--- a/js/src/jsnum.h
+++ b/js/src/jsnum.h
@@ -34,13 +34,7 @@ namespace js {
class StringBuffer;
-extern MOZ_MUST_USE bool
-InitRuntimeNumberState(JSRuntime* rt);
-
-#if !EXPOSE_INTL_API
-extern void
-FinishRuntimeNumberState(JSRuntime* rt);
-#endif
+void InitRuntimeNumberState(JSRuntime* rt);
/* Initialize the Number class, returning its prototype object. */
extern JSObject*
diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h
index f409dce95..dc7cdb85a 100644
--- a/js/src/jsprototypes.h
+++ b/js/src/jsprototypes.h
@@ -37,11 +37,7 @@
#define TYPED_ARRAY_CLASP(type) (&TypedArrayObject::classes[Scalar::type])
#define ERROR_CLASP(type) (&ErrorObject::classes[type])
-#ifdef EXPOSE_INTL_API
#define IF_INTL(real,imaginary) real
-#else
-#define IF_INTL(real,imaginary) imaginary
-#endif
#ifdef ENABLE_BINARYDATA
#define IF_BDATA(real,imaginary) real
diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp
index 7adeed620..4151d012b 100644
--- a/js/src/jsstr.cpp
+++ b/js/src/jsstr.cpp
@@ -36,9 +36,7 @@
#include "jit/InlinableNatives.h"
#include "js/Conversions.h"
#include "js/UniquePtr.h"
-#if ENABLE_INTL_API
#include "unicode/unorm.h"
-#endif
#include "vm/GlobalObject.h"
#include "vm/Interpreter.h"
#include "vm/Opcodes.h"
@@ -899,38 +897,6 @@ js::str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp)
return ToUpperCaseHelper(cx, args);
}
-#if !EXPOSE_INTL_API
-bool
-js::str_localeCompare(JSContext* cx, unsigned argc, Value* vp)
-{
- CallArgs args = CallArgsFromVp(argc, vp);
- RootedString str(cx, ToStringForStringFunction(cx, args.thisv()));
- if (!str)
- return false;
-
- RootedString thatStr(cx, ToString<CanGC>(cx, args.get(0)));
- if (!thatStr)
- return false;
-
- if (cx->runtime()->localeCallbacks && cx->runtime()->localeCallbacks->localeCompare) {
- RootedValue result(cx);
- if (!cx->runtime()->localeCallbacks->localeCompare(cx, str, thatStr, &result))
- return false;
-
- args.rval().set(result);
- return true;
- }
-
- int32_t result;
- if (!CompareStrings(cx, str, thatStr, &result))
- return false;
-
- args.rval().setInt32(result);
- return true;
-}
-#endif
-
-#if EXPOSE_INTL_API
/* ES6 20140210 draft 21.1.3.12. */
bool
js::str_normalize(JSContext* cx, unsigned argc, Value* vp)
@@ -1007,7 +973,6 @@ js::str_normalize(JSContext* cx, unsigned argc, Value* vp)
args.rval().setString(ns);
return true;
}
-#endif
bool
js::str_charAt(JSContext* cx, unsigned argc, Value* vp)
@@ -1569,7 +1534,7 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match)
return true;
}
-/* ES6 draft rc4 21.1.3.7. */
+/* ES6 2015 ST 21.1.3.7 String.prototype.includes */
bool
js::str_includes(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1626,6 +1591,13 @@ js::str_includes(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+/* ES6 draft <RC4 String.prototype.contains for compatibility */
+bool
+js::str_contains(JSContext* cx, unsigned argc, Value* vp)
+{
+ return js::str_includes(cx, argc, vp);
+}
+
/* ES6 20120927 draft 15.5.4.7. */
bool
js::str_indexOf(JSContext* cx, unsigned argc, Value* vp)
@@ -2590,6 +2562,7 @@ static const JSFunctionSpec string_methods[] = {
JS_SELF_HOSTED_FN("padEnd", "String_pad_end", 2,0),
JS_SELF_HOSTED_FN("codePointAt", "String_codePointAt", 1,0),
JS_FN("includes", str_includes, 1,0),
+ JS_FN("contains", str_contains, 1,0),
JS_FN("indexOf", str_indexOf, 1,0),
JS_FN("lastIndexOf", str_lastIndexOf, 1,0),
JS_FN("startsWith", str_startsWith, 1,0),
@@ -2599,15 +2572,9 @@ static const JSFunctionSpec string_methods[] = {
JS_FN("trimRight", str_trimRight, 0,0),
JS_FN("toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
JS_FN("toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
-#if EXPOSE_INTL_API
JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0),
-#else
- JS_FN("localeCompare", str_localeCompare, 1,0),
-#endif
JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0),
-#if EXPOSE_INTL_API
JS_FN("normalize", str_normalize, 0,0),
-#endif
/* Perl-ish methods (search is actually Python-esque). */
JS_SELF_HOSTED_FN("match", "String_match", 1,0),
@@ -2918,9 +2885,7 @@ static const JSFunctionSpec string_static_methods[] = {
JS_SELF_HOSTED_FN("trimRight", "String_static_trimRight", 1,0),
JS_SELF_HOSTED_FN("toLocaleLowerCase","String_static_toLocaleLowerCase",1,0),
JS_SELF_HOSTED_FN("toLocaleUpperCase","String_static_toLocaleUpperCase",1,0),
-#if EXPOSE_INTL_API
JS_SELF_HOSTED_FN("normalize", "String_static_normalize", 1,0),
-#endif
JS_SELF_HOSTED_FN("concat", "String_static_concat", 2,0),
JS_SELF_HOSTED_FN("localeCompare", "String_static_localeCompare", 2,0),
diff --git a/js/src/jsstr.h b/js/src/jsstr.h
index 3b92aa21b..118118839 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);
@@ -377,13 +378,8 @@ str_toLocaleLowerCase(JSContext* cx, unsigned argc, Value* vp);
extern bool
str_toLocaleUpperCase(JSContext* cx, unsigned argc, Value* vp);
-#if !EXPOSE_INTL_API
-extern bool
-str_localeCompare(JSContext* cx, unsigned argc, Value* vp);
-#else
extern bool
str_normalize(JSContext* cx, unsigned argc, Value* vp);
-#endif
extern bool
str_concat(JSContext* cx, unsigned argc, Value* vp);
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..a3283b5d6 100644
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -645,18 +645,17 @@ else:
FORCE_STATIC_LIB = True
STATIC_LIBRARY_NAME = 'js_static'
-if CONFIG['ENABLE_INTL_API']:
- if not CONFIG['MOZ_ICU_DATA_ARCHIVE']:
- USE_LIBS += [
- 'icu',
- ]
- else:
- # Linking 'icu' will pull in the stubdata library,
- # which the shell doesn't want, so link the other bits.
- USE_LIBS += [
- 'icui18n',
- 'icuuc',
- ]
+if not CONFIG['MOZ_ICU_DATA_ARCHIVE']:
+ USE_LIBS += [
+ 'icu',
+ ]
+else:
+ # Linking 'icu' will pull in the stubdata library,
+ # which the shell doesn't want, so link the other bits.
+ USE_LIBS += [
+ 'icui18n',
+ 'icuuc',
+ ]
USE_LIBS += [
'nspr',
@@ -708,7 +707,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 1736cc5d4..8abea5956 100644
--- a/js/src/old-configure.in
+++ b/js/src/old-configure.in
@@ -734,12 +734,14 @@ case "$target" in
dnl VS2012+ defaults to -arch:SSE2. We want to target nothing
dnl more recent, so set that explicitly here unless another
dnl target arch has already been set.
+ changequote(,)
if test -z `echo $CFLAGS | grep -i [-/]arch:` ; then
CFLAGS="$CFLAGS -arch:SSE2"
- fi
+ fi
if test -z `echo $CXXFLAGS | grep -i [-/]arch:` ; then
CXXFLAGS="$CXXFLAGS -arch:SSE2"
fi
+ changequote([,])
fi
dnl VS2013+ requires -FS when parallel building by make -jN.
dnl If nothing, compiler sometimes causes C1041 error.
@@ -1534,6 +1536,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 +2101,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)
@@ -2244,8 +2256,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..8d144417a 100644
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -893,7 +893,6 @@ SetPromiseRejectionTrackerCallback(JSContext* cx, unsigned argc, Value* vp)
return true;
}
-#ifdef ENABLE_INTL_API
static bool
AddIntlExtras(JSContext* cx, unsigned argc, Value* vp)
{
@@ -906,6 +905,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
};
@@ -915,7 +915,6 @@ AddIntlExtras(JSContext* cx, unsigned argc, Value* vp)
args.rval().setUndefined();
return true;
}
-#endif // ENABLE_INTL_API
static bool
EvalAndPrint(JSContext* cx, const char* bytes, size_t length,
@@ -6139,7 +6138,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"Sets the callback to be invoked whenever a Promise rejection is unhandled\n"
"or a previously-unhandled rejection becomes handled."),
-#ifdef ENABLE_INTL_API
JS_FN_HELP("addIntlExtras", AddIntlExtras, 1, 0,
"addIntlExtras(obj)",
"Adds various not-yet-standardized Intl functions as properties on the\n"
@@ -6147,7 +6145,6 @@ static const JSFunctionSpecWithHelp shell_functions[] = {
"functions and their behavior are experimental: don't depend upon them\n"
"unless you're willing to update your code if these experimental APIs change\n"
"underneath you."),
-#endif // ENABLE_INTL_API
JS_FS_HELP_END
};
diff --git a/js/src/shell/moz.build b/js/src/shell/moz.build
index 72ea8145c..e18bad238 100644
--- a/js/src/shell/moz.build
+++ b/js/src/shell/moz.build
@@ -36,7 +36,7 @@ LOCAL_INCLUDES += [
OS_LIBS += CONFIG['EDITLINE_LIBS']
OS_LIBS += CONFIG['MOZ_ZLIB_LIBS']
-if CONFIG['ENABLE_INTL_API'] and CONFIG['MOZ_ICU_DATA_ARCHIVE']:
+if CONFIG['MOZ_ICU_DATA_ARCHIVE']:
# The ICU libraries linked into libmozjs will not include the ICU data,
# so link it directly.
USE_LIBS += ['icudata']
diff --git a/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js b/js/src/tests/Intl/DateTimeFormat/timeZone_backward_links.js
index 890b1c1d5..d87abd7be 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 = 2018e
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..b96dac96f 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 = 2018e
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..66ef3075d 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 = 2018e
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..8d44204bc 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 = 2018e
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/tests/js1_8_5/extensions/clone-errors.js b/js/src/tests/js1_8_5/extensions/clone-errors.js
index f65578a06..d2ccea2e8 100644
--- a/js/src/tests/js1_8_5/extensions/clone-errors.js
+++ b/js/src/tests/js1_8_5/extensions/clone-errors.js
@@ -25,6 +25,7 @@ check({get x() { throw new Error("fail"); }});
// Mismatched scopes.
for (let [write_scope, read_scope] of [['SameProcessSameThread', 'SameProcessDifferentThread'],
['SameProcessSameThread', 'DifferentProcess'],
+ ['SameProcessDifferentThread', 'DifferentProcessForIndexedDB'],
['SameProcessDifferentThread', 'DifferentProcess']])
{
var ab = new ArrayBuffer(12);
diff --git a/js/src/tests/js1_8_5/extensions/clone-transferables.js b/js/src/tests/js1_8_5/extensions/clone-transferables.js
index 673684b95..9aad27208 100644
--- a/js/src/tests/js1_8_5/extensions/clone-transferables.js
+++ b/js/src/tests/js1_8_5/extensions/clone-transferables.js
@@ -3,11 +3,15 @@
// http://creativecommons.org/licenses/publicdomain/
function* buffer_options() {
- for (var scope of ["SameProcessSameThread", "SameProcessDifferentThread", "DifferentProcess"]) {
- for (var size of [0, 8, 16, 200, 1000, 4096, 8192, 65536]) {
- yield { scope, size };
+ for (var scope of ["SameProcessSameThread",
+ "SameProcessDifferentThread",
+ "DifferentProcess",
+ "DifferentProcessForIndexedDB"])
+ {
+ for (var size of [0, 8, 16, 200, 1000, 4096, 8192, 65536]) {
+ yield { scope, size };
+ }
}
- }
}
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/DateTime.cpp b/js/src/vm/DateTime.cpp
index e35ad4285..ba3145af2 100644
--- a/js/src/vm/DateTime.cpp
+++ b/js/src/vm/DateTime.cpp
@@ -13,9 +13,7 @@
#include "jsutil.h"
#include "js/Date.h"
-#if ENABLE_INTL_API
#include "unicode/timezone.h"
-#endif
using mozilla::Atomic;
using mozilla::ReleaseAcquire;
@@ -333,7 +331,7 @@ JS::ResetTimeZone()
{
js::DateTimeInfo::updateTimeZoneAdjustment();
-#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
+#if defined(ICU_TZ_HAS_RECREATE_DEFAULT)
TZInfo.acquire();
TZInfo.status = IcuTimeZoneInfo::NeedsUpdate;
TZInfo.release();
@@ -343,7 +341,7 @@ JS::ResetTimeZone()
void
js::ResyncICUDefaultTimeZone()
{
-#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
+#if defined(ICU_TZ_HAS_RECREATE_DEFAULT)
TZInfo.acquire();
if (TZInfo.status == IcuTimeZoneInfo::NeedsUpdate) {
icu::TimeZone::recreateDefault();
diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp
index 280548cd6..c90b6b85f 100644
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -17,9 +17,7 @@
#include "builtin/AtomicsObject.h"
#include "builtin/Eval.h"
-#if EXPOSE_INTL_API
-# include "builtin/Intl.h"
-#endif
+#include "builtin/Intl.h"
#include "builtin/MapObject.h"
#include "builtin/ModuleObject.h"
#include "builtin/Object.h"
diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp
index 7381a97b5..bd29d0c79 100644
--- a/js/src/vm/HelperThreads.cpp
+++ b/js/src/vm/HelperThreads.cpp
@@ -1144,7 +1144,7 @@ js::GCParallelTask::runFromMainThread(JSRuntime* rt)
MOZ_ASSERT(state == NotStarted);
MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(rt));
uint64_t timeStart = PRMJ_Now();
- run();
+ runTask();
duration_ = PRMJ_Now() - timeStart;
}
@@ -1155,7 +1155,7 @@ js::GCParallelTask::runFromHelperThread(AutoLockHelperThreadState& locked)
AutoUnlockHelperThreadState parallelSection(locked);
gc::AutoSetThreadIsPerformingGC performingGC;
uint64_t timeStart = PRMJ_Now();
- run();
+ runTask();
duration_ = PRMJ_Now() - timeStart;
}
diff --git a/js/src/vm/Initialization.cpp b/js/src/vm/Initialization.cpp
index 05cc087cc..39acdf9a8 100644
--- a/js/src/vm/Initialization.cpp
+++ b/js/src/vm/Initialization.cpp
@@ -20,10 +20,8 @@
#include "jit/ExecutableAllocator.h"
#include "jit/Ion.h"
#include "js/Utility.h"
-#if ENABLE_INTL_API
#include "unicode/uclean.h"
#include "unicode/utypes.h"
-#endif // ENABLE_INTL_API
#include "vm/DateTime.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
@@ -113,12 +111,10 @@ JS::detail::InitWithFailureDiagnostic(bool isDebugBuild)
js::DateTimeInfo::init();
-#if EXPOSE_INTL_API
UErrorCode err = U_ZERO_ERROR;
u_init(&err);
if (U_FAILURE(err))
return "u_init() failed";
-#endif // EXPOSE_INTL_API
RETURN_IF_FAIL(js::CreateHelperThreadsState());
RETURN_IF_FAIL(FutexRuntime::initialize());
@@ -171,9 +167,7 @@ JS_ShutDown(void)
// to do it only when PRMJ_Now is eventually called.
PRMJ_NowShutdown();
-#if EXPOSE_INTL_API
u_cleanup();
-#endif // EXPOSE_INTL_API
if (!JSRuntime::hasLiveRuntimes())
js::jit::ReleaseProcessExecutableMemory();
@@ -188,11 +182,7 @@ JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_IC
"must call JS_SetICUMemoryFunctions before any other JSAPI "
"operation (including JS_Init)");
-#if EXPOSE_INTL_API
UErrorCode status = U_ZERO_ERROR;
u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
return U_SUCCESS(status);
-#else
- return true;
-#endif
}
diff --git a/js/src/vm/Runtime.cpp b/js/src/vm/Runtime.cpp
index 0d6a3922c..174e23594 100644
--- a/js/src/vm/Runtime.cpp
+++ b/js/src/vm/Runtime.cpp
@@ -213,11 +213,6 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
warningReporter(nullptr),
buildIdOp(nullptr),
propertyRemovals(0),
-#if !EXPOSE_INTL_API
- thousandsSeparator(0),
- decimalSeparator(0),
- numGrouping(0),
-#endif
keepAtoms_(0),
trustedPrincipals_(nullptr),
beingDestroyed_(false),
@@ -330,8 +325,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
/* The garbage collector depends on everything before this point being initialized. */
gcInitialized = true;
- if (!InitRuntimeNumberState(this))
- return false;
+ InitRuntimeNumberState(this);
JS::ResetTimeZone();
@@ -425,10 +419,6 @@ JSRuntime::destroyRuntime()
*/
FreeScriptData(this, lock);
-#if !EXPOSE_INTL_API
- FinishRuntimeNumberState(this);
-#endif
-
gc.finish();
atomsCompartment_ = nullptr;
diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h
index 734543c4e..735adadf2 100644
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -978,13 +978,6 @@ struct JSRuntime : public JS::shadow::Runtime,
*/
uint32_t propertyRemovals;
-#if !EXPOSE_INTL_API
- /* Number localization, used by jsnum.cpp. */
- const char* thousandsSeparator;
- const char* decimalSeparator;
- const char* numGrouping;
-#endif
-
private:
mozilla::Maybe<js::SharedImmutableStringsCache> sharedImmutableStrings_;
diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp
index c7e7cc863..3e7baccad 100644
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -189,6 +189,22 @@ intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, Value* vp)
return true;
}
+template<typename T>
+static bool
+intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp)
+{
+ CallArgs args = CallArgsFromVp(argc, vp);
+ MOZ_ASSERT(args.length() == 1);
+ MOZ_ASSERT(args[0].isObject());
+
+ if (args[0].toObject().is<T>()) {
+ args.rval().setObject(args[0].toObject());
+ return true;
+ }
+ args.rval().setNull();
+ return true;
+}
+
/**
* Self-hosting intrinsic returning the original constructor for a builtin
* the name of which is the first and only argument.
@@ -2174,11 +2190,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("std_String_trimRight", str_trimRight, 0,0),
JS_FN("std_String_toLocaleLowerCase", str_toLocaleLowerCase, 0,0),
JS_FN("std_String_toLocaleUpperCase", str_toLocaleUpperCase, 0,0),
-#if !EXPOSE_INTL_API
- JS_FN("std_String_localeCompare", str_localeCompare, 1,0),
-#else
JS_FN("std_String_normalize", str_normalize, 0,0),
-#endif
JS_FN("std_String_concat", str_concat, 1,0),
JS_FN("std_TypedArray_buffer", js::TypedArray_bufferGetter, 1,0),
@@ -2265,18 +2277,18 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("_SetCanonicalName", intrinsic_SetCanonicalName, 2,0),
- JS_INLINABLE_FN("IsArrayIterator",
- intrinsic_IsInstanceOfBuiltin<ArrayIteratorObject>, 1,0,
- IntrinsicIsArrayIterator),
- JS_INLINABLE_FN("IsMapIterator",
- intrinsic_IsInstanceOfBuiltin<MapIteratorObject>, 1,0,
- IntrinsicIsMapIterator),
- JS_INLINABLE_FN("IsSetIterator",
- intrinsic_IsInstanceOfBuiltin<SetIteratorObject>, 1,0,
- IntrinsicIsSetIterator),
- JS_INLINABLE_FN("IsStringIterator",
- intrinsic_IsInstanceOfBuiltin<StringIteratorObject>, 1,0,
- IntrinsicIsStringIterator),
+ JS_INLINABLE_FN("GuardToArrayIterator",
+ intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1,0,
+ IntrinsicGuardToArrayIterator),
+ JS_INLINABLE_FN("GuardToMapIterator",
+ intrinsic_GuardToBuiltin<MapIteratorObject>, 1,0,
+ IntrinsicGuardToMapIterator),
+ JS_INLINABLE_FN("GuardToSetIterator",
+ intrinsic_GuardToBuiltin<SetIteratorObject>, 1,0,
+ IntrinsicGuardToSetIterator),
+ JS_INLINABLE_FN("GuardToStringIterator",
+ intrinsic_GuardToBuiltin<StringIteratorObject>, 1,0,
+ IntrinsicGuardToStringIterator),
JS_FN("_CreateMapIterationResultPair", intrinsic_CreateMapIterationResultPair, 0, 0),
JS_INLINABLE_FN("_GetNextMapEntryForIterator", intrinsic_GetNextMapEntryForIterator, 2,0,
@@ -2377,7 +2389,12 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallStarGeneratorMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<StarGeneratorObject>>, 2, 0),
+ JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin<MapObject>, 1, 0,
+ IntrinsicGuardToMapObject),
JS_FN("IsWeakSet", intrinsic_IsInstanceOfBuiltin<WeakSetObject>, 1,0),
+
+ JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin<SetObject>, 1, 0,
+ IntrinsicGuardToSetObject),
JS_FN("CallWeakSetMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
@@ -2438,6 +2455,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/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp
index 3a062c3b8..42e909000 100644
--- a/js/src/vm/StructuredClone.cpp
+++ b/js/src/vm/StructuredClone.cpp
@@ -160,16 +160,16 @@ template<typename T, typename AllocPolicy>
struct BufferIterator {
typedef mozilla::BufferList<AllocPolicy> BufferList;
- explicit BufferIterator(BufferList& buffer)
+ explicit BufferIterator(const BufferList& buffer)
: mBuffer(buffer)
, mIter(buffer.Iter())
{
JS_STATIC_ASSERT(8 % sizeof(T) == 0);
}
- BufferIterator(const BufferIterator& other)
- : mBuffer(other.mBuffer)
- , mIter(other.mIter)
+ explicit BufferIterator(const JSStructuredCloneData& data)
+ : mBuffer(data.bufList_)
+ , mIter(data.Start())
{
}
@@ -228,17 +228,26 @@ struct BufferIterator {
return mIter.HasRoomFor(sizeof(T));
}
- BufferList& mBuffer;
+ const BufferList& mBuffer;
typename BufferList::IterImpl mIter;
};
+// SCOutput provides an interface to write raw data -- eg uint64_ts, doubles,
+// arrays of bytes -- into a structured clone data output stream. It also knows
+// how to free any transferable data within that stream.
+//
+// Note that it contains a full JSStructuredCloneData object, which holds the
+// callbacks necessary to read/write/transfer/free the data. For the purpose of
+// this class, only the freeTransfer callback is relevant; the rest of the callbacks
+// are used by the higher-level JSStructuredCloneWriter interface.
struct SCOutput {
public:
- using Iter = BufferIterator<uint64_t, TempAllocPolicy>;
+ using Iter = BufferIterator<uint64_t, SystemAllocPolicy>;
- explicit SCOutput(JSContext* cx);
+ SCOutput(JSContext* cx, JS::StructuredCloneScope scope);
JSContext* context() const { return cx; }
+ JS::StructuredCloneScope scope() const { return buf.scope(); }
bool write(uint64_t u);
bool writePair(uint32_t tag, uint32_t data);
@@ -251,22 +260,25 @@ struct SCOutput {
template <class T>
bool writeArray(const T* p, size_t nbytes);
- bool extractBuffer(JSStructuredCloneData* data);
- void discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure);
+ void setCallbacks(const JSStructuredCloneCallbacks* callbacks,
+ void* closure,
+ OwnTransferablePolicy policy)
+ {
+ buf.setCallbacks(callbacks, closure, policy);
+ }
+ void extractBuffer(JSStructuredCloneData* data) { *data = Move(buf); }
+ void discardTransferables();
uint64_t tell() const { return buf.Size(); }
uint64_t count() const { return buf.Size() / sizeof(uint64_t); }
- Iter iter() {
- return BufferIterator<uint64_t, TempAllocPolicy>(buf);
- }
+ Iter iter() { return Iter(buf); }
size_t offset(Iter dest) {
return dest - iter();
}
- private:
JSContext* cx;
- mozilla::BufferList<TempAllocPolicy> buf;
+ JSStructuredCloneData buf;
};
class SCInput {
@@ -356,13 +368,6 @@ struct JSStructuredCloneReader {
// be valid cross-process.)
JS::StructuredCloneScope allowedScope;
- // The scope the buffer was generated for (what sort of buffer it is.) The
- // scope is not just a permissions thing; it also affects the storage
- // format (eg a Transferred ArrayBuffer can be stored as a pointer for
- // SameProcessSameThread but must have its contents in the clone buffer for
- // DifferentProcess.)
- JS::StructuredCloneScope storedScope;
-
// Stack of objects with properties remaining to be read.
AutoValueVector objs;
@@ -386,13 +391,15 @@ struct JSStructuredCloneWriter {
const JSStructuredCloneCallbacks* cb,
void* cbClosure,
const Value& tVal)
- : out(cx), scope(scope), objs(out.context()),
+ : out(cx, scope), objs(out.context()),
counts(out.context()), entries(out.context()),
- memory(out.context()), callbacks(cb),
- closure(cbClosure), transferable(out.context(), tVal),
+ memory(out.context()),
+ transferable(out.context(), tVal),
transferableObjects(out.context(), GCHashSet<JSObject*>(cx)),
cloneDataPolicy(cloneDataPolicy)
- {}
+ {
+ out.setCallbacks(cb, cbClosure, OwnTransferablePolicy::NoTransferables);
+ }
~JSStructuredCloneWriter();
@@ -408,17 +415,10 @@ struct JSStructuredCloneWriter {
SCOutput& output() { return out; }
- bool extractBuffer(JSStructuredCloneData* data) {
- bool success = out.extractBuffer(data);
- if (success) {
- data->setOptionalCallbacks(callbacks, closure,
- OwnTransferablePolicy::OwnsTransferablesIfAny);
- }
- return success;
+ void extractBuffer(JSStructuredCloneData* newData) {
+ out.extractBuffer(newData);
}
- JS::StructuredCloneScope cloneScope() const { return scope; }
-
private:
JSStructuredCloneWriter() = delete;
JSStructuredCloneWriter(const JSStructuredCloneWriter&) = delete;
@@ -449,9 +449,6 @@ struct JSStructuredCloneWriter {
SCOutput out;
- // The (address space, thread) scope within which this clone is valid.
- JS::StructuredCloneScope scope;
-
// Vector of objects with properties remaining to be written.
//
// NB: These can span multiple compartments, so the compartment must be
@@ -477,12 +474,6 @@ struct JSStructuredCloneWriter {
SystemAllocPolicy>;
Rooted<CloneMemory> memory;
- // The user defined callbacks that will be used for cloning.
- const JSStructuredCloneCallbacks* callbacks;
-
- // Any value passed to JS_WriteStructuredClone.
- void* closure;
-
// Set of transferable objects
RootedValue transferable;
Rooted<GCHashSet<JSObject*>> transferableObjects;
@@ -542,7 +533,12 @@ WriteStructuredClone(JSContext* cx, HandleValue v, JSStructuredCloneData* bufp,
const Value& transferable)
{
JSStructuredCloneWriter w(cx, scope, cloneDataPolicy, cb, cbClosure, transferable);
- return w.init() && w.write(v) && w.extractBuffer(bufp);
+ if (!w.init())
+ return false;
+ if (!w.write(v))
+ return false;
+ w.extractBuffer(bufp);
+ return true;
}
bool
@@ -555,91 +551,15 @@ ReadStructuredClone(JSContext* cx, JSStructuredCloneData& data,
return r.read(vp);
}
-// If the given buffer contains Transferables, free them. Note that custom
-// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
-// delete their transferables.
-template<typename AllocPolicy>
-static void
-DiscardTransferables(mozilla::BufferList<AllocPolicy>& buffer,
- const JSStructuredCloneCallbacks* cb, void* cbClosure)
-{
- auto point = BufferIterator<uint64_t, AllocPolicy>(buffer);
- if (point.done())
- return; // Empty buffer
-
- uint32_t tag, data;
- MOZ_RELEASE_ASSERT(point.canPeek());
- SCInput::getPair(point.peek(), &tag, &data);
- point.next();
-
- if (tag == SCTAG_HEADER) {
- if (point.done())
- return;
-
- MOZ_RELEASE_ASSERT(point.canPeek());
- SCInput::getPair(point.peek(), &tag, &data);
- point.next();
- }
-
- if (tag != SCTAG_TRANSFER_MAP_HEADER)
- return;
-
- if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
- return;
-
- // freeTransfer should not GC
- JS::AutoSuppressGCAnalysis nogc;
-
- if (point.done())
- return;
-
- uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
- point.next();
- while (numTransferables--) {
- if (!point.canPeek())
- return;
-
- uint32_t ownership;
- SCInput::getPair(point.peek(), &tag, &ownership);
- point.next();
- MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
- if (!point.canPeek())
- return;
-
- void* content;
- SCInput::getPtr(point.peek(), &content);
- point.next();
- if (!point.canPeek())
- return;
-
- uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
- point.next();
-
- if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
- continue;
-
- if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
- js_free(content);
- } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
- JS_ReleaseMappedArrayBufferContents(content, extraData);
- } else if (cb && cb->freeTransfer) {
- cb->freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, cbClosure);
- } else {
- MOZ_ASSERT(false, "unknown ownership");
- }
- }
-}
-
static bool
StructuredCloneHasTransferObjects(const JSStructuredCloneData& data)
{
- auto iter = data.Iter();
-
if (data.Size() < sizeof(uint64_t))
return false;
uint64_t u;
- data.ReadBytes(iter, reinterpret_cast<char*>(&u), sizeof(u));
+ BufferIterator<uint64_t, SystemAllocPolicy> iter(data);
+ MOZ_ALWAYS_TRUE(iter.readBytes(reinterpret_cast<char*>(&u), sizeof(u)));
uint32_t tag = uint32_t(u >> 32);
return (tag == SCTAG_TRANSFER_MAP_HEADER);
}
@@ -650,7 +570,7 @@ SCInput::SCInput(JSContext* cx, JSStructuredCloneData& data)
: cx(cx), point(data)
{
- static_assert(JSStructuredCloneData::kSegmentAlignment % 8 == 0,
+ static_assert(JSStructuredCloneData::BufferList::kSegmentAlignment % 8 == 0,
"structured clone buffer reads should be aligned");
MOZ_ASSERT(data.Size() % 8 == 0);
}
@@ -812,9 +732,8 @@ SCInput::readPtr(void** p)
return true;
}
-SCOutput::SCOutput(JSContext* cx)
- : cx(cx)
- , buf(0, 0, 4096, cx)
+SCOutput::SCOutput(JSContext* cx, JS::StructuredCloneScope scope)
+ : cx(cx), buf(scope)
{
}
@@ -822,7 +741,11 @@ bool
SCOutput::write(uint64_t u)
{
uint64_t v = NativeEndian::swapToLittleEndian(u);
- return buf.WriteBytes(reinterpret_cast<char*>(&v), sizeof(u));
+ if (!buf.AppendBytes(reinterpret_cast<char*>(&v), sizeof(u))) {
+ ReportOutOfMemory(context());
+ return false;
+ }
+ return true;
}
bool
@@ -883,7 +806,7 @@ SCOutput::writeArray(const T* p, size_t nelems)
for (size_t i = 0; i < nelems; i++) {
T value = swapToLittleEndian(p[i]);
- if (!buf.WriteBytes(reinterpret_cast<char*>(&value), sizeof(value)))
+ if (!buf.AppendBytes(reinterpret_cast<char*>(&value), sizeof(value)))
return false;
}
@@ -892,7 +815,7 @@ SCOutput::writeArray(const T* p, size_t nelems)
size_t padbytes = sizeof(uint64_t) * nwords - sizeof(T) * nelems;
char zero = 0;
for (size_t i = 0; i < padbytes; i++) {
- if (!buf.WriteBytes(&zero, sizeof(zero)))
+ if (!buf.AppendBytes(&zero, sizeof(zero)))
return false;
}
@@ -927,34 +850,101 @@ SCOutput::writePtr(const void* p)
return write(reinterpret_cast<uint64_t>(p));
}
-bool
-SCOutput::extractBuffer(JSStructuredCloneData* data)
-{
- bool success;
- mozilla::BufferList<SystemAllocPolicy> out =
- buf.MoveFallible<SystemAllocPolicy>(&success);
- if (!success) {
- ReportOutOfMemory(cx);
- return false;
- }
- *data = JSStructuredCloneData(Move(out));
- return true;
-}
-
void
-SCOutput::discardTransferables(const JSStructuredCloneCallbacks* cb, void* cbClosure)
+SCOutput::discardTransferables()
{
- DiscardTransferables(buf, cb, cbClosure);
+ buf.discardTransferables();
}
} /* namespace js */
-JSStructuredCloneData::~JSStructuredCloneData()
+
+// If the buffer contains Transferables, free them. Note that custom
+// Transferables will use the JSStructuredCloneCallbacks::freeTransfer() to
+// delete their transferables.
+void
+JSStructuredCloneData::discardTransferables()
{
if (!Size())
return;
- if (ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
- DiscardTransferables(*this, callbacks_, closure_);
+
+ if (ownTransferables_ != OwnTransferablePolicy::OwnsTransferablesIfAny)
+ return;
+
+ // DifferentProcess clones cannot contain pointers, so nothing needs to be
+ // released.
+ if (scope_ == JS::StructuredCloneScope::DifferentProcess)
+ return;
+
+ FreeTransferStructuredCloneOp freeTransfer = nullptr;
+ if (callbacks_)
+ freeTransfer = callbacks_->freeTransfer;
+
+ auto point = BufferIterator<uint64_t, SystemAllocPolicy>(*this);
+ if (point.done())
+ return; // Empty buffer
+
+ uint32_t tag, data;
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ SCInput::getPair(point.peek(), &tag, &data);
+ point.next();
+
+ if (tag == SCTAG_HEADER) {
+ if (point.done())
+ return;
+
+ MOZ_RELEASE_ASSERT(point.canPeek());
+ SCInput::getPair(point.peek(), &tag, &data);
+ point.next();
+ }
+
+ if (tag != SCTAG_TRANSFER_MAP_HEADER)
+ return;
+
+ if (TransferableMapHeader(data) == SCTAG_TM_TRANSFERRED)
+ return;
+
+ // freeTransfer should not GC
+ JS::AutoSuppressGCAnalysis nogc;
+
+ if (point.done())
+ return;
+
+ uint64_t numTransferables = NativeEndian::swapFromLittleEndian(point.peek());
+ point.next();
+ while (numTransferables--) {
+ if (!point.canPeek())
+ return;
+
+ uint32_t ownership;
+ SCInput::getPair(point.peek(), &tag, &ownership);
+ point.next();
+ MOZ_ASSERT(tag >= SCTAG_TRANSFER_MAP_PENDING_ENTRY);
+ if (!point.canPeek())
+ return;
+
+ void* content;
+ SCInput::getPtr(point.peek(), &content);
+ point.next();
+ if (!point.canPeek())
+ return;
+
+ uint64_t extraData = NativeEndian::swapFromLittleEndian(point.peek());
+ point.next();
+
+ if (ownership < JS::SCTAG_TMO_FIRST_OWNED)
+ continue;
+
+ if (ownership == JS::SCTAG_TMO_ALLOC_DATA) {
+ js_free(content);
+ } else if (ownership == JS::SCTAG_TMO_MAPPED_DATA) {
+ JS_ReleaseMappedArrayBufferContents(content, extraData);
+ } else if (freeTransfer) {
+ freeTransfer(tag, JS::TransferableOwnership(ownership), content, extraData, closure_);
+ } else {
+ MOZ_ASSERT(false, "unknown ownership");
+ }
+ }
}
JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
@@ -962,9 +952,8 @@ JS_STATIC_ASSERT(JSString::MAX_LENGTH < UINT32_MAX);
JSStructuredCloneWriter::~JSStructuredCloneWriter()
{
// Free any transferable data left lying around in the buffer
- if (out.count()) {
- out.discardTransferables(callbacks, closure);
- }
+ if (out.count())
+ out.discardTransferables();
}
bool
@@ -1038,7 +1027,7 @@ JSStructuredCloneWriter::parseTransferable()
bool
JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId)
{
- ReportDataCloneError(context(), callbacks, errorId);
+ ReportDataCloneError(context(), out.buf.callbacks_, errorId);
return false;
}
@@ -1454,8 +1443,8 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
return traverseSavedFrame(obj);
}
- if (callbacks && callbacks->write)
- return callbacks->write(context(), this, obj, closure);
+ if (out.buf.callbacks_ && out.buf.callbacks_->write)
+ return out.buf.callbacks_->write(context(), this, obj, out.buf.closure_);
/* else fall through */
}
@@ -1465,7 +1454,7 @@ JSStructuredCloneWriter::startWrite(HandleValue v)
bool
JSStructuredCloneWriter::writeHeader()
{
- return out.writePair(SCTAG_HEADER, (uint32_t)scope);
+ return out.writePair(SCTAG_HEADER, (uint32_t)output().scope());
}
bool
@@ -1523,6 +1512,7 @@ JSStructuredCloneWriter::transferOwnership()
JSContext* cx = context();
RootedObject obj(cx);
+ JS::StructuredCloneScope scope = output().scope();
for (auto tr = transferableObjects.all(); !tr.empty(); tr.popFront()) {
obj = tr.front();
@@ -1555,7 +1545,9 @@ JSStructuredCloneWriter::transferOwnership()
return false;
}
- if (scope == JS::StructuredCloneScope::DifferentProcess) {
+ if (scope == JS::StructuredCloneScope::DifferentProcess ||
+ scope == JS::StructuredCloneScope::DifferentProcessForIndexedDB)
+ {
// Write Transferred ArrayBuffers in DifferentProcess scope at
// the end of the clone buffer, and store the offset within the
// buffer to where the ArrayBuffer was written. Note that this
@@ -1592,9 +1584,9 @@ JSStructuredCloneWriter::transferOwnership()
extraData = nbytes;
}
} else {
- if (!callbacks || !callbacks->writeTransfer)
+ if (!out.buf.callbacks_ || !out.buf.callbacks_->writeTransfer)
return reportDataCloneError(JS_SCERR_TRANSFERABLE);
- if (!callbacks->writeTransfer(cx, obj, closure, &tag, &ownership, &content, &extraData))
+ if (!out.buf.callbacks_->writeTransfer(cx, obj, out.buf.closure_, &tag, &ownership, &content, &extraData))
return false;
MOZ_ASSERT(tag > SCTAG_TRANSFER_MAP_PENDING_ENTRY);
}
@@ -2187,25 +2179,33 @@ JSStructuredCloneReader::readHeader()
if (!in.getPair(&tag, &data))
return in.reportTruncated();
- if (tag != SCTAG_HEADER) {
+ JS::StructuredCloneScope storedScope;
+ if (tag == SCTAG_HEADER) {
+ MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
+ storedScope = JS::StructuredCloneScope(data);
+ } else {
// Old structured clone buffer. We must have read it from disk.
- storedScope = JS::StructuredCloneScope::DifferentProcess;
- return true;
+ storedScope = JS::StructuredCloneScope::DifferentProcessForIndexedDB;
}
- MOZ_ALWAYS_TRUE(in.readPair(&tag, &data));
- storedScope = JS::StructuredCloneScope(data);
-
- if (data != uint32_t(JS::StructuredCloneScope::SameProcessSameThread) &&
- data != uint32_t(JS::StructuredCloneScope::SameProcessDifferentThread) &&
- data != uint32_t(JS::StructuredCloneScope::DifferentProcess))
+ if (storedScope < JS::StructuredCloneScope::SameProcessSameThread ||
+ storedScope > JS::StructuredCloneScope::DifferentProcessForIndexedDB)
{
JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
"invalid structured clone scope");
return false;
}
+
+ if (allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB) {
+ // Bug 1434308 and bug 1458320 - the scopes stored in old IndexedDB
+ // clones are incorrect. Treat them as if they were DifferentProcess.
+ allowedScope = JS::StructuredCloneScope::DifferentProcess;
+ return true;
+ }
+
if (storedScope < allowedScope) {
- JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr, JSMSG_SC_BAD_SERIALIZED_DATA,
+ JS_ReportErrorNumberASCII(context(), GetErrorMessage, nullptr,
+ JSMSG_SC_BAD_SERIALIZED_DATA,
"incompatible structured clone scope");
return false;
}
@@ -2249,10 +2249,14 @@ JSStructuredCloneReader::readTransferMap()
return false;
if (tag == SCTAG_TRANSFER_MAP_ARRAY_BUFFER) {
- if (storedScope == JS::StructuredCloneScope::DifferentProcess) {
+ if (allowedScope == JS::StructuredCloneScope::DifferentProcess ||
+ allowedScope == JS::StructuredCloneScope::DifferentProcessForIndexedDB)
+ {
// Transferred ArrayBuffers in a DifferentProcess clone buffer
- // are treated as if they weren't Transferred at all.
- continue;
+ // are treated as if they weren't Transferred at all. We should
+ // only see SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER.
+ ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
+ return false;
}
size_t nbytes = extraData;
@@ -2586,7 +2590,7 @@ JS_StructuredClone(JSContext* cx, HandleValue value, MutableHandleValue vp,
}
JSAutoStructuredCloneBuffer::JSAutoStructuredCloneBuffer(JSAutoStructuredCloneBuffer&& other)
- : scope_(other.scope_)
+ : scope_(other.scope()), data_(other.scope())
{
data_.ownTransferables_ = other.data_.ownTransferables_;
other.steal(&data_, &version_, &data_.callbacks_, &data_.closure_);
@@ -2604,45 +2608,14 @@ JSAutoStructuredCloneBuffer::operator=(JSAutoStructuredCloneBuffer&& other)
}
void
-JSAutoStructuredCloneBuffer::clear(const JSStructuredCloneCallbacks* optionalCallbacks,
- void* optionalClosure)
+JSAutoStructuredCloneBuffer::clear()
{
- if (!data_.Size())
- return;
-
- const JSStructuredCloneCallbacks* callbacks =
- optionalCallbacks ? optionalCallbacks : data_.callbacks_;
- void* closure = optionalClosure ? optionalClosure : data_.closure_;
-
- if (data_.ownTransferables_ == OwnTransferablePolicy::OwnsTransferablesIfAny)
- DiscardTransferables(data_, callbacks, closure);
+ data_.discardTransferables();
data_.ownTransferables_ = OwnTransferablePolicy::NoTransferables;
data_.Clear();
version_ = 0;
}
-bool
-JSAutoStructuredCloneBuffer::copy(const JSStructuredCloneData& srcData, uint32_t version,
- const JSStructuredCloneCallbacks* callbacks,
- void* closure)
-{
- // transferable objects cannot be copied
- if (StructuredCloneHasTransferObjects(srcData))
- return false;
-
- clear();
-
- auto iter = srcData.Iter();
- while (!iter.Done()) {
- data_.WriteBytes(iter.Data(), iter.RemainingInSegment());
- iter.Advance(srcData, iter.RemainingInSegment());
- }
-
- version_ = version;
- data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::NoTransferables);
- return true;
-}
-
void
JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t version,
const JSStructuredCloneCallbacks* callbacks,
@@ -2651,7 +2624,7 @@ JSAutoStructuredCloneBuffer::adopt(JSStructuredCloneData&& data, uint32_t versio
clear();
data_ = Move(data);
version_ = version;
- data_.setOptionalCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
+ data_.setCallbacks(callbacks, closure, OwnTransferablePolicy::OwnsTransferablesIfAny);
}
void
@@ -2668,7 +2641,7 @@ JSAutoStructuredCloneBuffer::steal(JSStructuredCloneData* data, uint32_t* versio
*data = Move(data_);
version_ = 0;
- data_.setOptionalCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
+ data_.setCallbacks(nullptr, nullptr, OwnTransferablePolicy::NoTransferables);
}
bool
@@ -2782,5 +2755,5 @@ JS_ObjectNotWritten(JSStructuredCloneWriter* w, HandleObject obj)
JS_PUBLIC_API(JS::StructuredCloneScope)
JS_GetStructuredCloneScope(JSStructuredCloneWriter* w)
{
- return w->cloneScope();
+ return w->output().scope();
}
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/shell/moz.build b/js/xpconnect/shell/moz.build
index ecc796f7f..d4f5d55af 100644
--- a/js/xpconnect/shell/moz.build
+++ b/js/xpconnect/shell/moz.build
@@ -35,22 +35,6 @@ if CONFIG['_MSC_VER']:
if CONFIG['OS_ARCH'] == 'WINNT':
RCINCLUDE = 'xpcshell.rc'
- if CONFIG['MOZ_SANDBOX']:
- # For sandbox includes and the include dependencies those have
- LOCAL_INCLUDES += [
- '/security/sandbox/chromium',
- '/security/sandbox/chromium-shim',
- ]
-
- USE_LIBS += [
- 'sandbox_s',
- ]
-
- DELAYLOAD_DLLS += [
- 'winmm.dll',
- 'user32.dll',
- ]
-
DELAYLOAD_DLLS += [
'xul.dll',
]
diff --git a/js/xpconnect/shell/xpcshell.cpp b/js/xpconnect/shell/xpcshell.cpp
index ba979bc69..4eef3f6bf 100644
--- a/js/xpconnect/shell/xpcshell.cpp
+++ b/js/xpconnect/shell/xpcshell.cpp
@@ -22,9 +22,6 @@
#define XRE_DONT_PROTECT_DLL_LOAD
#define XRE_WANT_ENVIRON
#include "nsWindowsWMain.cpp"
-#ifdef MOZ_SANDBOX
-#include "mozilla/sandboxing/SandboxInitialization.h"
-#endif
#endif
#ifdef MOZ_WIDGET_GTK
@@ -53,13 +50,7 @@ main(int argc, char** argv, char** envp)
DllBlocklist_Initialize();
#endif
- XREShellData shellData;
-#if defined(XP_WIN) && defined(MOZ_SANDBOX)
- shellData.sandboxBrokerServices =
- mozilla::sandboxing::GetInitializedBrokerServices();
-#endif
-
- int result = XRE_XPCShellMain(argc, argv, envp, &shellData);
+ int result = XRE_XPCShellMain(argc, argv, envp);
#ifdef XP_MACOSX
FinishAutoreleasePool();
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 f5f6a11bb..f352607d4 100644
--- a/js/xpconnect/src/XPCJSContext.cpp
+++ b/js/xpconnect/src/XPCJSContext.cpp
@@ -59,10 +59,6 @@
#include "nsIXULRuntime.h"
#include "nsJSPrincipals.h"
-#if defined(MOZ_JEMALLOC4)
-#include "mozmemory.h"
-#endif
-
#ifdef XP_WIN
#include <windows.h>
#endif
@@ -147,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;
@@ -1544,12 +1528,6 @@ XPCJSContext::~XPCJSContext()
delete mDyingWrappedNativeProtoMap;
mDyingWrappedNativeProtoMap = nullptr;
-#ifdef MOZ_ENABLE_PROFILER_SPS
- // Tell the profiler that the context is gone
- if (PseudoStack* stack = mozilla_get_pseudo_stack())
- stack->sampleContext(nullptr);
-#endif
-
Preferences::UnregisterCallback(ReloadPrefsCallback, JS_OPTIONS_DOT_STR, this);
}
@@ -3398,10 +3376,6 @@ XPCJSContext::Initialize()
JS_AddWeakPointerCompartmentCallback(cx, WeakPointerCompartmentCallback, this);
JS_SetWrapObjectCallbacks(cx, &WrapObjectCallbacks);
js::SetPreserveWrapperCallback(cx, PreserveWrapper);
-#ifdef MOZ_ENABLE_PROFILER_SPS
- if (PseudoStack* stack = mozilla_get_pseudo_stack())
- stack->sampleContext(cx);
-#endif
JS_SetAccumulateTelemetryCallback(cx, AccumulateTelemetryCallback);
js::SetActivityCallback(cx, ActivityCallback, this);
JS_AddInterruptCallback(cx, InterruptCallback);
diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp
index 45d00d390..a6432856d 100644
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -44,9 +44,6 @@
#ifdef XP_WIN
#include "mozilla/widget/AudioSession.h"
#include <windows.h>
-#if defined(MOZ_SANDBOX)
-#include "SandboxBroker.h"
-#endif
#endif
// all this crap is needed to do the interactive shell stuff
@@ -1235,11 +1232,8 @@ GetCurrentWorkingDirectory(nsAString& workingDirectory)
static JSSecurityCallbacks shellSecurityCallbacks;
int
-XRE_XPCShellMain(int argc, char** argv, char** envp,
- const XREShellData* aShellData)
+XRE_XPCShellMain(int argc, char** argv, char** envp)
{
- MOZ_ASSERT(aShellData);
-
JSContext* cx;
int result = 0;
nsresult rv;
@@ -1484,16 +1478,6 @@ XRE_XPCShellMain(int argc, char** argv, char** envp,
// Plugin may require audio session if installed plugin can initialize
// asynchronized.
AutoAudioSession audioSession;
-
-#if defined(MOZ_SANDBOX)
- // Required for sandboxed child processes.
- if (aShellData->sandboxBrokerServices) {
- SandboxBroker::Initialize(aShellData->sandboxBrokerServices);
- } else {
- NS_WARNING("Failed to initialize broker services, sandboxed "
- "processes will fail to start.");
- }
-#endif
#endif
{
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);