summaryrefslogtreecommitdiffstats
path: root/js/src/vm
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/vm')
-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
8 files changed, 221 insertions, 261 deletions
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();
}