diff --git a/dom/base/StructuredCloneHolder.cpp b/dom/base/StructuredCloneHolder.cpp index 7b7dbdf67d..a7afd310cb 100644 --- a/dom/base/StructuredCloneHolder.cpp +++ b/dom/base/StructuredCloneHolder.cpp @@ -138,207 +138,6 @@ StructuredCloneCallbacksError(JSContext* aCx, NS_WARNING("Failed to clone data."); } -struct SameThreadStreamTransferData -{ - SameThreadStreamTransferData(JSContext* aCx, JS::HandleObject aRecord) - : mRecord(aCx, aRecord) - {} - - ~SameThreadStreamTransferData() - { - mRecord.reset(); - } - - JS::PersistentRootedObject mRecord; -}; - -bool -CallStreamTransferHelper(JSContext* aCx, - const char* aHelperName, - JS::HandleValue aArgument, - JS::MutableHandleValue aResult) -{ - JS::Rooted global(aCx, JS::CurrentGlobalOrNull(aCx)); - if (!global) { - return false; - } - - // Resolve the stream extras lazily before looking up the internal helper. - JS::Rooted ignored(aCx); - if (!JS_GetProperty(aCx, global, "WritableStream", &ignored)) { - return false; - } - - JS::Rooted helper(aCx); - if (!JS_GetProperty(aCx, global, aHelperName, &helper)) { - return false; - } - - if (!helper.isObject() || !JS::IsCallable(&helper.toObject())) { - aResult.setUndefined(); - return true; - } - - JS::Rooted argument(aCx, aArgument); - if (!JS_WrapValue(aCx, &argument)) { - return false; - } - - return JS::Call(aCx, JS::UndefinedHandleValue, helper, - JS::HandleValueArray(argument), aResult); -} - -bool -TryWriteSameThreadStreamTransfer(JSContext* aCx, - JS::Handle aObj, - const char* aHelperName, - uint32_t aTransferTag, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData, - bool* aHandled) -{ - *aHandled = false; - - JS::Rooted argument(aCx, JS::ObjectValue(*aObj)); - JS::Rooted transferRecord(aCx); - if (!CallStreamTransferHelper(aCx, aHelperName, argument, &transferRecord)) { - return false; - } - - if (transferRecord.isUndefined()) { - return true; - } - - if (!transferRecord.isObject()) { - return false; - } - - JS::Rooted record(aCx, &transferRecord.toObject()); - SameThreadStreamTransferData* data = - new SameThreadStreamTransferData(aCx, record); - - *aTag = aTransferTag; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = data; - *aExtraData = 0; - *aHandled = true; - return true; -} - -bool -TryWriteReadableStreamPortTransfer(JSContext* aCx, - JS::Handle aObj, - nsTArray& aPortIdentifiers, - uint32_t* aTag, - JS::TransferableOwnership* aOwnership, - void** aContent, - uint64_t* aExtraData, - bool* aHandled) -{ - *aHandled = false; - - JS::Rooted argument(aCx, JS::ObjectValue(*aObj)); - JS::Rooted transferPortValue(aCx); - if (!CallStreamTransferHelper(aCx, "__uxpTransferReadableStreamPort", - argument, &transferPortValue)) { - return false; - } - - if (transferPortValue.isUndefined()) { - return true; - } - - if (!transferPortValue.isObject()) { - return false; - } - - JS::Rooted transferPortObj(aCx, &transferPortValue.toObject()); - MessagePort* port = nullptr; - nsresult rv = UNWRAP_OBJECT(MessagePort, &transferPortObj, port); - if (NS_FAILED(rv) || !port) { - return false; - } - - *aExtraData = aPortIdentifiers.Length(); - MessagePortIdentifier* identifier = aPortIdentifiers.AppendElement(); - port->CloneAndDisentangle(*identifier); - - *aTag = SCTAG_DOM_TRANSFERRED_READABLESTREAM; - *aOwnership = JS::SCTAG_TMO_CUSTOM; - *aContent = nullptr; - *aHandled = true; - return true; -} - -bool -ReadSameThreadStreamTransfer(JSContext* aCx, - void* aContent, - const char* aHelperName, - JS::MutableHandleObject aReturnObject) -{ - MOZ_ASSERT(aContent); - SameThreadStreamTransferData* data = - static_cast(aContent); - - JS::Rooted record(aCx, JS::ObjectValue(*data->mRecord)); - JS::Rooted result(aCx); - if (!CallStreamTransferHelper(aCx, aHelperName, record, &result)) { - return false; - } - - if (!result.isObject()) { - return false; - } - - aReturnObject.set(&result.toObject()); - delete data; - return true; -} - -bool -ReadReadableStreamPortTransfer(JSContext* aCx, - nsISupports* aParent, - nsTArray& aPortIdentifiers, - uint64_t aExtraData, - JS::MutableHandleObject aReturnObject) -{ - if (aExtraData >= aPortIdentifiers.Length()) { - return false; - } - - nsCOMPtr global = do_QueryInterface(aParent); - - ErrorResult rv; - RefPtr port = - MessagePort::Create(global, aPortIdentifiers[aExtraData], rv); - if (NS_WARN_IF(rv.Failed())) { - rv.SuppressException(); - return false; - } - - JS::Rooted portValue(aCx); - if (!GetOrCreateDOMReflector(aCx, port, &portValue)) { - JS_ClearPendingException(aCx); - return false; - } - - JS::Rooted result(aCx); - if (!CallStreamTransferHelper(aCx, - "__uxpReceiveReadableStreamTransferFromPort", - portValue, &result)) { - return false; - } - - if (!result.isObject()) { - return false; - } - - aReturnObject.set(&result.toObject()); - return true; -} - } // anonymous namespace const JSStructuredCloneCallbacks StructuredCloneHolder::sCallbacks = { @@ -1576,35 +1375,6 @@ StructuredCloneHolder::CustomReadTransferHandler(JSContext* aCx, return true; } - if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { - if (aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM) { - return ReadSameThreadStreamTransfer(aCx, aContent, - "__uxpReceiveWritableStreamTransfer", - aReturnObject); - } - - if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) { - return ReadSameThreadStreamTransfer(aCx, aContent, - "__uxpReceiveReadableStreamTransfer", - aReturnObject); - } - - if (aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) { - return ReadSameThreadStreamTransfer(aCx, aContent, - "__uxpReceiveTransformStreamTransfer", - aReturnObject); - } - } - - if ((mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || - mStructuredCloneScope == StructuredCloneScope::DifferentProcess) && - aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM) { - MOZ_ASSERT(!aContent); - return ReadReadableStreamPortTransfer(aCx, mParent, mPortIdentifiers, - aExtraData, - aReturnObject); - } - return false; } @@ -1673,55 +1443,6 @@ StructuredCloneHolder::CustomWriteTransferHandler(JSContext* aCx, } } - if (mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { - bool handled = false; - if (!TryWriteSameThreadStreamTransfer(aCx, obj, - "__uxpTransferWritableStream", - SCTAG_DOM_TRANSFERRED_WRITABLESTREAM, - aTag, aOwnership, aContent, - aExtraData, &handled)) { - return false; - } - if (handled) { - return true; - } - - if (!TryWriteSameThreadStreamTransfer(aCx, obj, - "__uxpTransferReadableStream", - SCTAG_DOM_TRANSFERRED_READABLESTREAM, - aTag, aOwnership, aContent, - aExtraData, &handled)) { - return false; - } - if (handled) { - return true; - } - - if (!TryWriteSameThreadStreamTransfer(aCx, obj, - "__uxpTransferTransformStream", - SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM, - aTag, aOwnership, aContent, - aExtraData, &handled)) { - return false; - } - if (handled) { - return true; - } - } - - if (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || - mStructuredCloneScope == StructuredCloneScope::DifferentProcess) { - bool handled = false; - if (!TryWriteReadableStreamPortTransfer(aCx, obj, mPortIdentifiers, - aTag, aOwnership, aContent, - aExtraData, &handled)) { - return false; - } - if (handled) { - return true; - } - } - return false; } @@ -1759,26 +1480,6 @@ StructuredCloneHolder::CustomFreeTransferHandler(uint32_t aTag, delete data; return; } - - if ((aTag == SCTAG_DOM_TRANSFERRED_WRITABLESTREAM || - aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM || - aTag == SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM) && - mStructuredCloneScope == StructuredCloneScope::SameProcessSameThread) { - MOZ_ASSERT(aContent); - SameThreadStreamTransferData* data = - static_cast(aContent); - delete data; - return; - } - - if (aTag == SCTAG_DOM_TRANSFERRED_READABLESTREAM && - (mStructuredCloneScope == StructuredCloneScope::SameProcessDifferentThread || - mStructuredCloneScope == StructuredCloneScope::DifferentProcess)) { - MOZ_ASSERT(!aContent); - MOZ_ASSERT(aExtraData < mPortIdentifiers.Length()); - MessagePort::ForceClose(mPortIdentifiers[aExtraData]); - return; - } } bool diff --git a/dom/base/StructuredCloneTags.h b/dom/base/StructuredCloneTags.h index 15518104f9..09b91f7afb 100644 --- a/dom/base/StructuredCloneTags.h +++ b/dom/base/StructuredCloneTags.h @@ -68,11 +68,6 @@ enum StructuredCloneTags { // This tag is used by both main thread and workers. SCTAG_DOM_URLSEARCHPARAMS, - // Same-thread transferable stream records. These are not supported by IDB. - SCTAG_DOM_TRANSFERRED_READABLESTREAM, - SCTAG_DOM_TRANSFERRED_WRITABLESTREAM, - SCTAG_DOM_TRANSFERRED_TRANSFORMSTREAM, - // When adding a new tag for IDB, please don't add it to the end of the list! // Tags that are supported by IDB must not ever change. See the static assert // in IDBObjectStore.cpp, method CommonStructuredCloneReadCallback. diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index a80d9164b9..ffb5709e46 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -1929,9 +1929,6 @@ public: { ProcessGlobal* global = ProcessGlobal::Get(); MOZ_ASSERT(!aRunInGlobalScope); - if (NS_WARN_IF(!global)) { - return false; - } global->LoadScript(aURL); return true; } diff --git a/dom/workers/RuntimeService.cpp b/dom/workers/RuntimeService.cpp index 65f778b5f9..f63b1de981 100644 --- a/dom/workers/RuntimeService.cpp +++ b/dom/workers/RuntimeService.cpp @@ -301,7 +301,6 @@ LoadContextOptions(const char* aPrefName, void* /* aClosure */) .setAsyncStack(GetWorkerPref(NS_LITERAL_CSTRING("asyncstack"))) .setWerror(GetWorkerPref(NS_LITERAL_CSTRING("werror"))) .setStreams(GetWorkerPref(NS_LITERAL_CSTRING("streams"))) - .setWeakRefs(GetWorkerPref(NS_LITERAL_CSTRING("weakrefs"))) .setExtraWarnings(GetWorkerPref(NS_LITERAL_CSTRING("strict"))) .setArrayProtoValues(GetWorkerPref( NS_LITERAL_CSTRING("array_prototype_values"))); diff --git a/dom/workers/WorkerPrefs.h b/dom/workers/WorkerPrefs.h index d870ac8e46..87806a6fbc 100644 --- a/dom/workers/WorkerPrefs.h +++ b/dom/workers/WorkerPrefs.h @@ -35,7 +35,6 @@ WORKER_SIMPLE_PREF("dom.serviceWorkers.openWindow.enabled", OpenWindowEnabled, O WORKER_SIMPLE_PREF("dom.storageManager.enabled", StorageManagerEnabled, STORAGEMANAGER_ENABLED) WORKER_SIMPLE_PREF("dom.push.enabled", PushEnabled, PUSH_ENABLED) WORKER_SIMPLE_PREF("dom.streams.enabled", StreamsEnabled, STREAMS_ENABLED) -WORKER_SIMPLE_PREF("javascript.options.weakrefs", WeakRefsEnabled, WEAKREFS_ENABLED) WORKER_SIMPLE_PREF("dom.requestcontext.enabled", RequestContextEnabled, REQUESTCONTEXT_ENABLED) WORKER_SIMPLE_PREF("gfx.offscreencanvas.enabled", OffscreenCanvasEnabled, OFFSCREENCANVAS_ENABLED) WORKER_SIMPLE_PREF("dom.webkitBlink.dirPicker.enabled", WebkitBlinkDirectoryPickerEnabled, DOM_WEBKITBLINK_DIRPICKER_WEBKITBLINK) diff --git a/js/src/builtin/AtomicsObject.cpp b/js/src/builtin/AtomicsObject.cpp index f917db9b21..a4ae0736d4 100644 --- a/js/src/builtin/AtomicsObject.cpp +++ b/js/src/builtin/AtomicsObject.cpp @@ -47,12 +47,10 @@ #include "builtin/AtomicsObject.h" #include "mozilla/Atomics.h" -#include "mozilla/Casting.h" #include "mozilla/FloatingPoint.h" #include "mozilla/Maybe.h" #include "mozilla/Unused.h" -#include "builtin/Promise.h" #include "jsapi.h" #include "jsfriendapi.h" #include "jsnum.h" @@ -60,9 +58,7 @@ #include "jit/AtomicOperations.h" #include "jit/InlinableNatives.h" #include "js/Class.h" -#include "vm/BigIntType.h" #include "vm/GlobalObject.h" -#include "vm/HelperThreads.h" #include "vm/Time.h" #include "vm/TypedArrayObject.h" #include "wasm/WasmInstance.h" @@ -125,68 +121,6 @@ GetTypedArrayIndex(JSContext* cx, HandleValue v, Handle view, return true; } -static bool -IsWaitableTypedArray(Scalar::Type viewType) -{ - return viewType == Scalar::Int32 || viewType == Scalar::BigInt64; -} - -static uint32_t -GetWaiterByteOffset(Handle view, uint32_t offset) -{ - return view->byteOffset() + offset * TypedArrayElemSize(view->type()); -} - -static uint64_t -BigIntToRawBits(Scalar::Type viewType, BigInt* value) -{ - if (viewType == Scalar::BigInt64) - return uint64_t(BigInt::toInt64(value)); - MOZ_ASSERT(viewType == Scalar::BigUint64); - return BigInt::toUint64(value); -} - -static bool -BigIntToRawBits(JSContext* cx, Scalar::Type viewType, HandleValue value, uint64_t* bits) -{ - MOZ_ASSERT(Scalar::isBigIntType(viewType)); - - RootedBigInt bigint(cx, ToBigInt(cx, value)); - if (!bigint) - return false; - - *bits = BigIntToRawBits(viewType, bigint); - return true; -} - -static bool -SetBigIntResult(JSContext* cx, Scalar::Type viewType, uint64_t bits, MutableHandleValue result) -{ - MOZ_ASSERT(Scalar::isBigIntType(viewType)); - - BigInt* bigint = viewType == Scalar::BigInt64 - ? BigInt::createFromInt64(cx, mozilla::BitwiseCast(bits)) - : BigInt::createFromUint64(cx, bits); - if (!bigint) - return false; - - result.setBigInt(bigint); - return true; -} - -static bool -WaitValueMatches(Handle view, uint32_t offset, uint64_t expected) -{ - SharedMem viewData = view->viewDataShared(); - if (view->type() == Scalar::BigInt64) { - return jit::AtomicOperations::loadSafeWhenRacy(viewData.cast() + offset) == - expected; - } - - return uint32_t(jit::AtomicOperations::loadSafeWhenRacy(viewData.cast() + offset)) == - uint32_t(expected); -} - static int32_t CompareExchange(Scalar::Type viewType, int32_t oldCandidate, int32_t newCandidate, SharedMem viewData, uint32_t offset, bool* badArrayType = nullptr) @@ -257,20 +191,6 @@ js::atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp) uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - - if (Scalar::isBigIntType(view->type())) { - uint64_t oldCandidate; - if (!BigIntToRawBits(cx, view->type(), oldv, &oldCandidate)) - return false; - uint64_t newCandidate; - if (!BigIntToRawBits(cx, view->type(), newv, &newCandidate)) - return false; - - uint64_t result = jit::AtomicOperations::compareExchangeSeqCst( - view->viewDataShared().cast() + offset, oldCandidate, newCandidate); - return SetBigIntResult(cx, view->type(), result, r); - } - int32_t oldCandidate; if (!ToInt32(cx, oldv, &oldCandidate)) return false; @@ -339,22 +259,6 @@ js::atomics_load(JSContext* cx, unsigned argc, Value* vp) r.setNumber(v); return true; } - case Scalar::BigInt64: { - int64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast() + offset); - BigInt* bigint = BigInt::createFromInt64(cx, v); - if (!bigint) - return false; - r.setBigInt(bigint); - return true; - } - case Scalar::BigUint64: { - uint64_t v = jit::AtomicOperations::loadSeqCst(viewData.cast() + offset); - BigInt* bigint = BigInt::createFromUint64(cx, v); - if (!bigint) - return false; - r.setBigInt(bigint); - return true; - } default: return ReportBadArrayType(cx); } @@ -433,25 +337,6 @@ ExchangeOrStore(JSContext* cx, unsigned argc, Value* vp) uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - - if (Scalar::isBigIntType(view->type())) { - RootedBigInt bigint(cx, ToBigInt(cx, valv)); - if (!bigint) - return false; - - uint64_t value = BigIntToRawBits(view->type(), bigint); - if (op == DoStore) { - jit::AtomicOperations::storeSeqCst(view->viewDataShared().cast() + offset, - value); - r.setBigInt(bigint); - return true; - } - - uint64_t result = jit::AtomicOperations::exchangeSeqCst( - view->viewDataShared().cast() + offset, value); - return SetBigIntResult(cx, view->type(), result, r); - } - double integerValue; if (!ToInteger(cx, valv, &integerValue)) return false; @@ -495,24 +380,6 @@ AtomicsBinop(JSContext* cx, HandleValue objv, HandleValue idxv, HandleValue valv uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - - if (Scalar::isBigIntType(view->type())) { - uint64_t value; - if (!BigIntToRawBits(cx, view->type(), valv, &value)) - return false; - - SharedMem addr = view->viewDataShared().cast() + offset; - uint64_t old = jit::AtomicOperations::loadSeqCst(addr); - for (;;) { - uint64_t replacement = T::operate64(old, value); - uint64_t observed = jit::AtomicOperations::compareExchangeSeqCst(addr, old, - replacement); - if (observed == old) - return SetBigIntResult(cx, view->type(), old, r); - old = observed; - } - } - int32_t numberValue; if (!ToInt32(cx, valv, &numberValue)) return false; @@ -567,7 +434,6 @@ class PerformAdd public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAddSeqCst) static int32_t perform(int32_t x, int32_t y) { return x + y; } - static uint64_t operate64(uint64_t x, uint64_t y) { return x + y; } }; bool @@ -582,7 +448,6 @@ class PerformSub public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchSubSeqCst) static int32_t perform(int32_t x, int32_t y) { return x - y; } - static uint64_t operate64(uint64_t x, uint64_t y) { return x - y; } }; bool @@ -597,7 +462,6 @@ class PerformAnd public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchAndSeqCst) static int32_t perform(int32_t x, int32_t y) { return x & y; } - static uint64_t operate64(uint64_t x, uint64_t y) { return x & y; } }; bool @@ -612,7 +476,6 @@ class PerformOr public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchOrSeqCst) static int32_t perform(int32_t x, int32_t y) { return x | y; } - static uint64_t operate64(uint64_t x, uint64_t y) { return x | y; } }; bool @@ -627,7 +490,6 @@ class PerformXor public: INTEGRAL_TYPES_FOR_EACH(jit::AtomicOperations::fetchXorSeqCst) static int32_t perform(int32_t x, int32_t y) { return x ^ y; } - static uint64_t operate64(uint64_t x, uint64_t y) { return x ^ y; } }; bool @@ -831,13 +693,11 @@ js::atomics_cmpxchg_asm_callout(wasm::Instance* instance, int32_t vt, int32_t of namespace js { -class AtomicsWaitAsyncTask; - // Represents one waiting worker. // // The type is declared opaque in SharedArrayObject.h. Instances of -// js::FutexWaiter are linked onto a list across a call to FutexRuntime::wait() -// or an async wait task. +// js::FutexWaiter are stack-allocated and linked onto a list across a +// call to FutexRuntime::wait(). // // The 'waiters' field of the SharedArrayRawBuffer points to the highest // priority waiter in the list, and lower priority nodes are linked through @@ -851,34 +711,14 @@ class FutexWaiter public: FutexWaiter(uint32_t offset, JSRuntime* rt) : offset(offset), - kind(Sync), rt(rt), - asyncTask(nullptr), lower_pri(nullptr), back(nullptr) { } - FutexWaiter(uint32_t offset, AtomicsWaitAsyncTask* asyncTask) - : offset(offset), - kind(Async), - rt(nullptr), - asyncTask(asyncTask), - lower_pri(nullptr), - back(nullptr) - { - } - - bool isWaiting() const; - void notify(); - - uint32_t offset; // byte offset within the SharedArrayBuffer - enum WaiterKind { - Sync, - Async - } kind; + uint32_t offset; // int32 element index within the SharedArrayBuffer JSRuntime* rt; // The runtime of the waiter - AtomicsWaitAsyncTask* asyncTask; // The async waiter task, if any FutexWaiter* lower_pri; // Lower priority nodes in circular doubly-linked list of waiters FutexWaiter* back; // Other direction }; @@ -902,195 +742,8 @@ class AutoLockFutexAPI js::UniqueLock& unique() { return *unique_; } }; -static void -AddWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter) -{ - if (FutexWaiter* waiters = sarb->waiters()) { - waiter->lower_pri = waiters; - waiter->back = waiters->back; - waiters->back->lower_pri = waiter; - waiters->back = waiter; - } else { - waiter->lower_pri = waiter->back = waiter; - sarb->setWaiters(waiter); - } -} - -static void -RemoveWaiter(SharedArrayRawBuffer* sarb, FutexWaiter* waiter) -{ - if (waiter->lower_pri == waiter) { - sarb->setWaiters(nullptr); - } else { - waiter->lower_pri->back = waiter->back; - waiter->back->lower_pri = waiter->lower_pri; - if (sarb->waiters() == waiter) - sarb->setWaiters(waiter->lower_pri); - } - waiter->lower_pri = nullptr; - waiter->back = nullptr; -} - -class AtomicsWaitAsyncTask : public PromiseTask -{ - enum class State { - Waiting, - Notified, - TimedOut - }; - - SharedArrayRawBuffer* sarb_; - FutexWaiter waiter_; - mozilla::Maybe timeout_; - ConditionVariable cond_; - State state_; - bool isInWaiterList_; - - public: - AtomicsWaitAsyncTask(JSContext* cx, Handle promise, - SharedArrayRawBuffer* sarb, uint32_t offset, - mozilla::Maybe& timeout) - : PromiseTask(cx, promise), - sarb_(sarb), - waiter_(offset, this), - timeout_(timeout), - state_(State::Waiting), - isInWaiterList_(false) - { - } - - ~AtomicsWaitAsyncTask() { - if (isInWaiterList_) { - AutoLockFutexAPI lock; - if (isInWaiterList_) - removeFromWaiterList(); - } - sarb_->dropReference(); - } - - FutexWaiter* waiter() { - return &waiter_; - } - - void setInWaiterList() { - isInWaiterList_ = true; - } - - bool isWaiting() const { - return state_ == State::Waiting; - } - - void notify() { - MOZ_ASSERT(isWaiting()); - state_ = State::Notified; - cond_.notify_all(); - } - - void execute() override { - AutoLockFutexAPI lock; - - const bool isTimed = timeout_.isSome(); - auto finalEnd = timeout_.map([](mozilla::TimeDuration& timeout) { - return mozilla::TimeStamp::Now() + timeout; - }); - auto maxSlice = mozilla::TimeDuration::FromSeconds(4000.0); - - while (state_ == State::Waiting) { - if (isTimed) { - auto sliceEnd = finalEnd.map([&](mozilla::TimeStamp& finalEnd) { - auto sliceEnd = mozilla::TimeStamp::Now() + maxSlice; - if (finalEnd < sliceEnd) - sliceEnd = finalEnd; - return sliceEnd; - }); - - mozilla::Unused << cond_.wait_until(lock.unique(), *sliceEnd); - if (state_ == State::Waiting && mozilla::TimeStamp::Now() >= *finalEnd) { - state_ = State::TimedOut; - break; - } - } else { - cond_.wait(lock.unique()); - } - } - - if (isInWaiterList_) - removeFromWaiterList(); - } - - private: - void removeFromWaiterList() { - MOZ_ASSERT(isInWaiterList_); - RemoveWaiter(sarb_, &waiter_); - isInWaiterList_ = false; - } - - bool finishPromise(JSContext* cx, Handle promise) override { - RootedValue result(cx); - if (state_ == State::TimedOut) - result.setString(cx->names().futexTimedOut); - else - result.setString(cx->names().futexOK); - return PromiseObject::resolve(cx, promise, result); - } -}; - -bool -FutexWaiter::isWaiting() const -{ - if (kind == Sync) - return rt->fx.isWaiting(); - return asyncTask->isWaiting(); -} - -void -FutexWaiter::notify() -{ - if (kind == Sync) { - rt->fx.notify(FutexRuntime::NotifyExplicit); - return; - } - asyncTask->notify(); -} - } // namespace js -static bool -GetWaitTimeout(JSContext* cx, HandleValue timeoutv, - mozilla::Maybe* timeout) -{ - timeout->reset(); - if (!timeoutv.isUndefined()) { - double timeout_ms; - if (!ToNumber(cx, timeoutv, &timeout_ms)) - return false; - if (!mozilla::IsNaN(timeout_ms)) { - if (timeout_ms < 0) - *timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0)); - else if (!mozilla::IsInfinite(timeout_ms)) - *timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms)); - } - } - return true; -} - -static bool -CreateWaitAsyncResult(JSContext* cx, bool isAsync, HandleValue value, MutableHandleValue rval) -{ - RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); - if (!obj) - return false; - - RootedValue asyncValue(cx, BooleanValue(isAsync)); - if (!NativeDefineDataProperty(cx, obj, cx->names().async, asyncValue, JSPROP_ENUMERATE)) - return false; - if (!NativeDefineDataProperty(cx, obj, cx->names().value, value, JSPROP_ENUMERATE)) - return false; - - rval.setObject(*obj); - return true; -} - bool js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) { @@ -1106,24 +759,26 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) Rooted view(cx, nullptr); if (!GetSharedTypedArray(cx, objv, &view)) return false; - if (!IsWaitableTypedArray(view->type())) + if (view->type() != Scalar::Int32) return ReportBadArrayType(cx); uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - uint64_t value = 0; - if (view->type() == Scalar::BigInt64) { - if (!BigIntToRawBits(cx, view->type(), valv, &value)) - return false; - } else { - int32_t int32Value; - if (!ToInt32(cx, valv, &int32Value)) - return false; - value = uint32_t(int32Value); - } - mozilla::Maybe timeout; - if (!GetWaitTimeout(cx, timeoutv, &timeout)) + int32_t value; + if (!ToInt32(cx, valv, &value)) return false; + mozilla::Maybe timeout; + if (!timeoutv.isUndefined()) { + double timeout_ms; + if (!ToNumber(cx, timeoutv, &timeout_ms)) + return false; + if (!mozilla::IsNaN(timeout_ms)) { + if (timeout_ms < 0) + timeout = mozilla::Some(mozilla::TimeDuration::FromSeconds(0.0)); + else if (!mozilla::IsInfinite(timeout_ms)) + timeout = mozilla::Some(mozilla::TimeDuration::FromMilliseconds(timeout_ms)); + } + } if (!rt->fx.canWait()) return ReportCannotWait(cx); @@ -1132,7 +787,8 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) // and it provides the necessary memory fence. AutoLockFutexAPI lock; - if (!WaitValueMatches(view, offset, value)) { + SharedMem addr = view->viewDataShared().cast() + offset; + if (jit::AtomicOperations::loadSafeWhenRacy(addr) != value) { r.setString(cx->names().futexNotEqual); return true; } @@ -1140,8 +796,16 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) Rooted sab(cx, view->bufferShared()); SharedArrayRawBuffer* sarb = sab->rawBufferObject(); - FutexWaiter w(GetWaiterByteOffset(view, offset), rt); - AddWaiter(sarb, &w); + FutexWaiter w(offset, rt); + if (FutexWaiter* waiters = sarb->waiters()) { + w.lower_pri = waiters; + w.back = waiters->back; + waiters->back->lower_pri = &w; + waiters->back = &w; + } else { + w.lower_pri = w.back = &w; + sarb->setWaiters(&w); + } FutexRuntime::WaitResult result = FutexRuntime::FutexOK; bool retval = rt->fx.wait(cx, lock.unique(), timeout, &result); @@ -1156,96 +820,15 @@ js::atomics_wait(JSContext* cx, unsigned argc, Value* vp) } } - RemoveWaiter(sarb, &w); - return retval; -} - -bool -js::atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - HandleValue objv = args.get(0); - HandleValue idxv = args.get(1); - HandleValue valv = args.get(2); - HandleValue timeoutv = args.get(3); - MutableHandleValue r = args.rval(); - - Rooted view(cx, nullptr); - if (!GetSharedTypedArray(cx, objv, &view)) - return false; - if (!IsWaitableTypedArray(view->type())) - return ReportBadArrayType(cx); - uint32_t offset; - if (!GetTypedArrayIndex(cx, idxv, view, &offset)) - return false; - uint64_t value = 0; - if (view->type() == Scalar::BigInt64) { - if (!BigIntToRawBits(cx, view->type(), valv, &value)) - return false; + if (w.lower_pri == &w) { + sarb->setWaiters(nullptr); } else { - int32_t int32Value; - if (!ToInt32(cx, valv, &int32Value)) - return false; - value = uint32_t(int32Value); + w.lower_pri->back = w.back; + w.back->lower_pri = w.lower_pri; + if (sarb->waiters() == &w) + sarb->setWaiters(w.lower_pri); } - mozilla::Maybe timeout; - if (!GetWaitTimeout(cx, timeoutv, &timeout)) - return false; - - Rooted promise(cx, PromiseObject::createSkippingExecutor(cx)); - if (!promise) - return false; - - RootedValue promiseValue(cx, ObjectValue(*promise)); - RootedValue result(cx); - if (!CreateWaitAsyncResult(cx, true, promiseValue, &result)) - return false; - - Rooted sab(cx, view->bufferShared()); - SharedArrayRawBuffer* sarb = sab->rawBufferObject(); - if (!sarb->addReference()) { - JS_ReportErrorASCII(cx, "Reference count overflow on SharedArrayBuffer"); - return false; - } - - auto task = cx->make_unique(cx, promise, sarb, offset, timeout); - if (!task) { - sarb->dropReference(); - return false; - } - - bool isAsync = false; - RootedValue immediateResult(cx); - { - AutoLockFutexAPI lock; - - if (!WaitValueMatches(view, offset, value)) { - immediateResult.setString(cx->names().futexNotEqual); - } else if (timeout.isSome() && timeout->ToMilliseconds() == 0.0) { - immediateResult.setString(cx->names().futexTimedOut); - } else { - if (!cx->startAsyncTaskCallback || !cx->finishAsyncTaskCallback || - !CanUseExtraThreads()) - { - JS_ReportErrorASCII(cx, "Atomics.waitAsync not supported in this runtime."); - return false; - } - - task->waiter()->offset = GetWaiterByteOffset(view, offset); - AddWaiter(sarb, task->waiter()); - task->setInWaiterList(); - isAsync = true; - } - } - - if (!isAsync) - return CreateWaitAsyncResult(cx, false, immediateResult, r); - - if (!StartPromiseTask(cx, Move(task))) - return false; - - r.set(result); - return true; + return retval; } bool @@ -1260,12 +843,11 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) Rooted view(cx, nullptr); if (!GetSharedTypedArray(cx, objv, &view)) return false; - if (!IsWaitableTypedArray(view->type())) + if (view->type() != Scalar::Int32) return ReportBadArrayType(cx); uint32_t offset; if (!GetTypedArrayIndex(cx, idxv, view, &offset)) return false; - offset = GetWaiterByteOffset(view, offset); double count; if (countv.isUndefined()) { count = mozilla::PositiveInfinity(); @@ -1288,9 +870,9 @@ js::atomics_notify(JSContext* cx, unsigned argc, Value* vp) do { FutexWaiter* c = iter; iter = iter->lower_pri; - if (c->offset != offset || !c->isWaiting()) + if (c->offset != offset || !c->rt->fx.isWaiting()) continue; - c->notify(); + c->rt->fx.notify(FutexRuntime::NotifyExplicit); ++woken; --count; } while (count > 0 && iter != waiters); @@ -1524,7 +1106,6 @@ const JSFunctionSpec AtomicsMethods[] = { JS_INLINABLE_FN("xor", atomics_xor, 3,0, AtomicsXor), JS_INLINABLE_FN("isLockFree", atomics_isLockFree, 1,0, AtomicsIsLockFree), JS_FN("wait", atomics_wait, 4,0), - JS_FN("waitAsync", atomics_waitAsync, 4,0), JS_FN("notify", atomics_notify, 3,0), JS_FN("wake", atomics_notify, 3,0), //Legacy name JS_FS_END diff --git a/js/src/builtin/AtomicsObject.h b/js/src/builtin/AtomicsObject.h index 309c97ae91..18f00dad16 100644 --- a/js/src/builtin/AtomicsObject.h +++ b/js/src/builtin/AtomicsObject.h @@ -24,19 +24,18 @@ class AtomicsObject : public JSObject static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp); }; -[[nodiscard]] bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_load(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_store(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_add(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_sub(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_and(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_or(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_waitAsync(JSContext* cx, unsigned argc, Value* vp); -[[nodiscard]] bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp); +MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp); /* asm.js callouts */ namespace wasm { class Instance; } diff --git a/js/src/builtin/Map.js b/js/src/builtin/Map.js index bcf0ded02e..434cd6529b 100644 --- a/js/src/builtin/Map.js +++ b/js/src/builtin/Map.js @@ -55,49 +55,6 @@ function MapForEach(callbackfn, thisArg = undefined) { } } -// ES2024 -// Map.groupBy ( items, callbackfn ) -function MapGroupBy(items, callbackfn) { - // Step 1. - RequireObjectCoercible(items); - - // Step 2. - if (!IsCallable(callbackfn)) - ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(1, callbackfn)); - - // Step 3. - var groups = std_Map_create(); - - // Step 4. - var k = 0; - - // Steps 5-8. - for (var value of allowContentIter(items)) { - // Step 6.a. - if (k >= MAX_NUMERIC_INDEX) - ThrowTypeError(JSMSG_TOO_LONG_ARRAY); - - // Step 6.b. - var key = callContentFunction(callbackfn, undefined, value, k); - - // Steps 6.c-d. - var elements; - if (callFunction(std_Map_has, groups, key)) { - elements = callFunction(std_Map_get, groups, key); - callFunction(std_Array_push, elements, value); - } else { - elements = [value]; - callFunction(std_Map_set, groups, key, elements); - } - - // Step 6.e. - k++; - } - - // Step 9. - return groups; -} - var iteratorTemp = { mapIterationResultPair : null }; function MapIteratorNext() { diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index daeb930c86..fe748a6bde 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -332,15 +332,9 @@ const JSPropertySpec MapObject::staticProperties[] = { JS_PS_END }; -const JSFunctionSpec MapObject::staticMethods[] = { - JS_SELF_HOSTED_FN("groupBy", "MapGroupBy", 2, 0), - JS_FS_END -}; - static JSObject* InitClass(JSContext* cx, Handle global, const Class* clasp, JSProtoKey key, Native construct, const JSPropertySpec* properties, const JSFunctionSpec* methods, - const JSFunctionSpec* staticMethods, const JSPropertySpec* staticProperties) { RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); @@ -349,13 +343,8 @@ InitClass(JSContext* cx, Handle global, const Class* clasp, JSPro Rooted ctor(cx, global->createConstructor(cx, construct, ClassName(key, cx), 0)); if (!ctor || - !JS_DefineProperties(cx, ctor, staticProperties)) - { - return nullptr; - } - if (staticMethods && !JS_DefineFunctions(cx, ctor, staticMethods)) - return nullptr; - if (!LinkConstructorAndPrototype(cx, ctor, proto) || + !JS_DefineProperties(cx, ctor, staticProperties) || + !LinkConstructorAndPrototype(cx, ctor, proto) || !DefinePropertiesAndFunctions(cx, proto, properties, methods) || !GlobalObject::initBuiltinConstructor(cx, global, key, ctor, proto)) { @@ -370,7 +359,7 @@ MapObject::initClass(JSContext* cx, JSObject* obj) Rooted global(cx, &obj->as()); RootedObject proto(cx, InitClass(cx, global, &class_, JSProto_Map, construct, properties, methods, - staticMethods, staticProperties)); + staticProperties)); if (proto) { // Define the "entries" method. JSFunction* fun = JS_DefineFunction(cx, proto, "entries", entries, 0, 0); @@ -1095,7 +1084,7 @@ SetObject::initClass(JSContext* cx, JSObject* obj) Rooted global(cx, &obj->as()); RootedObject proto(cx, InitClass(cx, global, &class_, JSProto_Set, construct, properties, methods, - nullptr, staticProperties)); + staticProperties)); if (proto) { // Define the "values" method. JSFunction* fun = JS_DefineFunction(cx, proto, "values", values, 0, 0); diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 2b46fec2c9..a9f685ea00 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -109,10 +109,8 @@ class MapObject : public NativeObject { static MOZ_MUST_USE bool getKeysAndValuesInterleaved(JSContext* cx, HandleObject obj, JS::MutableHandle> entries); - [[nodiscard]] static bool entries(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool get(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool has(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool set(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool entries(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool has(JSContext* cx, unsigned argc, Value* vp); static MapObject* create(JSContext* cx, HandleObject proto = nullptr); // Publicly exposed Map calls for JSAPI access (webidl maplike/setlike @@ -139,7 +137,6 @@ class MapObject : public NativeObject { static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; - static const JSFunctionSpec staticMethods[]; static const JSPropertySpec staticProperties[]; ValueMap* getData() { return static_cast(getPrivate()); } static ValueMap& extract(HandleObject o); @@ -153,20 +150,22 @@ class MapObject : public NativeObject { static MOZ_MUST_USE bool iterator_impl(JSContext* cx, const CallArgs& args, IteratorKind kind); - [[nodiscard]] static bool size_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool size(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool get_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool has_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool set_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool delete_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool delete_(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool keys_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool keys(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool values_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool values(JSContext* cx, unsigned argc, Value* vp); - [[nodiscard]] static bool entries_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool clear_impl(JSContext* cx, const CallArgs& args); - [[nodiscard]] static bool clear(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool size_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool size(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool get_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool get(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool has_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool set_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool set(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool delete_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool delete_(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool keys_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool keys(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool values_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool values(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool entries_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool clear_impl(JSContext* cx, const CallArgs& args); + static MOZ_MUST_USE bool clear(JSContext* cx, unsigned argc, Value* vp); }; class MapIteratorObject : public NativeObject diff --git a/js/src/builtin/Object.js b/js/src/builtin/Object.js index 01442144cc..6627aea593 100644 --- a/js/src/builtin/Object.js +++ b/js/src/builtin/Object.js @@ -240,16 +240,12 @@ function ObjectGroupBy(items, callbackfn) { // Steps 5-8. for (var value of allowContentIter(items)) { // Step 6.a. - if (k >= MAX_NUMERIC_INDEX) - ThrowTypeError(JSMSG_TOO_LONG_ARRAY); - - // Step 6.b. var key = callContentFunction(callbackfn, undefined, value, k); - // Step 6.c. + // Step 6.b. key = ToPropertyKey(key); - // Steps 6.d-e. + // Steps 6.c-d. var elements = groups[key]; if (elements === undefined) { _DefineDataProperty(groups, key, [value]); @@ -257,7 +253,7 @@ function ObjectGroupBy(items, callbackfn) { callFunction(std_Array_push, elements, value); } - // Step 6.f. + // Step 6.e. k++; } diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index 56803b5b91..9660a758a1 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -3673,48 +3673,6 @@ Promise_static_resolve(JSContext* cx, unsigned argc, Value* vp) return true; } -// ES2024 -// Promise.withResolvers ( ) -static bool -Promise_static_withResolvers(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - // Step 1. - if (!args.thisv().isObject()) { - ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, -1, args.thisv(), nullptr); - return false; - } - RootedObject C(cx, &args.thisv().toObject()); - - // Step 2. - Rooted capability(cx); - if (!NewPromiseCapability(cx, C, &capability, false)) - return false; - - // Step 3. - RootedPlainObject obj(cx, NewBuiltinClassInstance(cx)); - if (!obj) - return false; - - // Steps 4-7. - RootedValue promise(cx, ObjectValue(*capability.promise())); - if (!::JS_DefineProperty(cx, obj, "promise", promise, JSPROP_ENUMERATE)) - return false; - - RootedValue resolve(cx, ObjectValue(*capability.resolve())); - if (!::JS_DefineProperty(cx, obj, "resolve", resolve, JSPROP_ENUMERATE)) - return false; - - RootedValue reject(cx, ObjectValue(*capability.reject())); - if (!::JS_DefineProperty(cx, obj, "reject", reject, JSPROP_ENUMERATE)) - return false; - - // Step 8. - args.rval().setObject(*obj); - return true; -} - /** * Unforgeable version of ES2016, 25.4.4.5, Promise.resolve. */ @@ -5222,7 +5180,6 @@ static const JSFunctionSpec promise_static_methods[] = { JS_FN("race", Promise_static_race, 1, 0), JS_FN("reject", Promise_reject, 1, 0), JS_FN("resolve", Promise_static_resolve, 1, 0), - JS_FN("withResolvers", Promise_static_withResolvers, 0, 0), JS_FS_END }; diff --git a/js/src/builtin/Stream.cpp b/js/src/builtin/Stream.cpp index 0d5d0b2701..26457709d8 100644 --- a/js/src/builtin/Stream.cpp +++ b/js/src/builtin/Stream.cpp @@ -5,7 +5,6 @@ #include "builtin/Stream.h" -#include "js/CompilationAndEvaluation.h" #include "js/Stream.h" #include "jscntxt.h" @@ -17,10 +16,6 @@ #include "vm/NativeObject-inl.h" -#include "zlib.h" - -#include - using namespace js; enum StreamSlots { @@ -101,72 +96,14 @@ Is(const HandleValue v) return v.isObject() && v.toObject().is(); } -template -MOZ_ALWAYS_INLINE bool -IsMaybeWrapped(const HandleValue v) -{ - if (!v.isObject()) - return false; - - JSObject* obj = &v.toObject(); - if (obj->is()) - return true; - - JSObject* unwrapped = CheckedUnwrap(obj); - return unwrapped && unwrapped->is(); -} - -template -MOZ_ALWAYS_INLINE T* -UnwrapInternalSlotObject(JSObject* obj) -{ - JSObject* unwrapped = UncheckedUnwrap(obj); - MOZ_ASSERT(unwrapped); - MOZ_ASSERT(unwrapped->is()); - return &unwrapped->as(); -} - -template -MOZ_ALWAYS_INLINE T* -UnwrapMaybeWrappedArg(const HandleValue v) -{ - if (!v.isObject()) - return nullptr; - - JSObject* obj = &v.toObject(); - if (obj->is()) - return &obj->as(); - - JSObject* unwrapped = CheckedUnwrap(obj); - if (!unwrapped || !unwrapped->is()) - return nullptr; - - return &unwrapped->as(); -} - +#ifdef DEBUG static bool IsReadableStreamController(const JSObject* controller) { return controller->is() || controller->is(); } - -[[nodiscard]] static NativeObject* -UnwrapMaybeWrappedReadableStreamController(const HandleValue v) -{ - if (!v.isObject()) - return nullptr; - - JSObject* obj = &v.toObject(); - if (IsReadableStreamController(obj)) - return &obj->as(); - - JSObject* unwrapped = CheckedUnwrap(obj); - if (!unwrapped || !IsReadableStreamController(unwrapped)) - return nullptr; - - return &unwrapped->as(); -} +#endif // DEBUG static inline uint32_t ControllerFlags(const NativeObject* controller) @@ -246,8 +183,7 @@ inline static MOZ_MUST_USE ReadableStream* StreamFromController(const NativeObject* controller) { MOZ_ASSERT(IsReadableStreamController(controller)); - return UnwrapInternalSlotObject( - &controller->getFixedSlot(ControllerSlot_Stream).toObject()); + return &controller->getFixedSlot(ControllerSlot_Stream).toObject().as(); } inline static MOZ_MUST_USE NativeObject* @@ -279,17 +215,15 @@ inline static MOZ_MUST_USE ReadableStream* StreamFromReader(const NativeObject* reader) { MOZ_ASSERT(ReaderHasStream(reader)); - return UnwrapInternalSlotObject( - &reader->getFixedSlot(ReaderSlot_Stream).toObject()); + return &reader->getFixedSlot(ReaderSlot_Stream).toObject().as(); } inline static MOZ_MUST_USE NativeObject* ReaderFromStream(const NativeObject* stream) { Value readerVal = stream->getFixedSlot(StreamSlot_Reader); - NativeObject* reader = UnwrapInternalSlotObject(&readerVal.toObject()); - MOZ_ASSERT(JS::IsReadableStreamReader(reader)); - return reader; + MOZ_ASSERT(JS::IsReadableStreamReader(&readerVal.toObject())); + return &readerVal.toObject().as(); } inline static bool @@ -371,55 +305,26 @@ RejectNonGenericMethod(JSContext* cx, const CallArgs& args, return ReturnPromiseRejectedWithPendingError(cx, args); } -[[nodiscard]] static bool -ResolveMaybeWrappedPromise(JSContext* cx, HandleObject promise, HandleValue value) -{ - RootedObject wrappedPromise(cx, promise); - RootedValue wrappedValue(cx, value); - if (!JS_WrapObject(cx, &wrappedPromise) || !JS_WrapValue(cx, &wrappedValue)) - return false; - return ResolvePromise(cx, wrappedPromise, wrappedValue); -} - -[[nodiscard]] static bool -RejectMaybeWrappedPromise(JSContext* cx, HandleObject promise, HandleValue reason) -{ - RootedObject wrappedPromise(cx, promise); - RootedValue wrappedReason(cx, reason); - if (!JS_WrapObject(cx, &wrappedPromise) || !JS_WrapValue(cx, &wrappedReason)) - return false; - return RejectPromise(cx, wrappedPromise, wrappedReason); -} - -[[nodiscard]] inline static NativeObject* +inline static MOZ_MUST_USE NativeObject* SetNewList(JSContext* cx, HandleNativeObject container, uint32_t slot) { - RootedNativeObject list(cx); - { - JSAutoCompartment ac(cx, container); - list = NewObjectWithNullTaggedProto(cx); - if (!list) - return nullptr; - container->setFixedSlot(slot, ObjectValue(*list)); - } + NativeObject* list = NewObjectWithNullTaggedProto(cx); + if (!list) + return nullptr; + container->setFixedSlot(slot, ObjectValue(*list)); return list; } inline static MOZ_MUST_USE bool AppendToList(JSContext* cx, HandleNativeObject list, HandleValue value) { - JSAutoCompartment ac(cx, list); - RootedValue wrappedValue(cx, value); - if (!JS_WrapValue(cx, &wrappedValue)) - return false; - uint32_t length = list->getDenseInitializedLength(); if (!list->ensureElements(cx, length + 1)) return false; list->ensureDenseInitializedLength(cx, length, 1); - list->setDenseElement(length, wrappedValue); + list->setDenseElement(length, value); return true; } @@ -436,7 +341,6 @@ template inline static MOZ_MUST_USE T* ShiftFromList(JSContext* cx, HandleNativeObject list) { - JSAutoCompartment ac(cx, list); uint32_t length = list->getDenseInitializedLength(); MOZ_ASSERT(length > 0); @@ -1011,79 +915,30 @@ ReadableStream_getReader(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod, ReadableStream_getReader_impl>(cx, args); } -[[nodiscard]] static bool -CallStreamExtra(JSContext* cx, const char* name, HandleValue streamVal, - HandleValue arg0, HandleValue arg1, MutableHandleValue rval) -{ - RootedObject global(cx, JS::CurrentGlobalOrNull(cx)); - if (!global) - return false; - - RootedValue fun(cx); - if (!JS_GetProperty(cx, global, name, &fun)) - return false; - - if (!fun.isObject() || !IsCallable(fun)) { - if (!InitStreamExtras(cx, global)) - return false; - if (!JS_GetProperty(cx, global, name, &fun)) - return false; - } - - if (!fun.isObject() || !IsCallable(fun)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, name); - return false; - } - - FixedInvokeArgs<3> invokeArgs(cx); - invokeArgs[0].set(streamVal); - invokeArgs[1].set(arg0); - invokeArgs[2].set(arg1); - return Call(cx, fun, UndefinedHandleValue, invokeArgs, rval); -} - // Streams spec, 3.2.4.4. pipeThrough({ writable, readable }, options) -[[nodiscard]] static bool +static MOZ_MUST_USE bool ReadableStream_pipeThrough(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - if (!Is(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "pipeThrough", ""); - return false; - } + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, "pipeThrough"); + return false; + // // Step 1: Perform ? Invoke(this, "pipeTo", « writable, options »). - RootedValue rval(cx); - if (!CallStreamExtra(cx, "__uxpStreamsPipeThrough", args.thisv(), - args.get(0), args.get(1), &rval)) - return false; - - args.rval().set(rval); - return true; + // // Step 2: Return readable. + // return readable; } // Streams spec, 3.2.4.5. pipeTo(dest, { preventClose, preventAbort, preventCancel } = {}) -[[nodiscard]] static bool +// TODO: Unimplemented since spec is not complete yet. +static MOZ_MUST_USE bool ReadableStream_pipeTo(JSContext* cx, unsigned argc, Value* vp) { - CallArgs args = CallArgsFromVp(argc, vp); - if (!Is(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "pipeTo", ""); - return false; - } - - RootedValue rval(cx); - if (!CallStreamExtra(cx, "__uxpStreamsPipeTo", args.thisv(), - args.get(0), args.get(1), &rval)) - return false; - - args.rval().set(rval); - return true; + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_READABLESTREAM_METHOD_NOT_IMPLEMENTED, "pipeTo"); + return false; } -[[nodiscard]] static bool +static MOZ_MUST_USE bool ReadableStreamTee(JSContext* cx, Handle stream, bool cloneForBranch2, MutableHandle branch1, MutableHandle branch2); @@ -1458,8 +1313,7 @@ ReadableStreamAddReadIntoRequest(JSContext* cx, Handle stream) { // Step 1: MOZ_ASSERT: ! IsReadableStreamBYOBReader(stream.[[reader]]) is true. RootedValue val(cx, stream->getFixedSlot(StreamSlot_Reader)); - RootedNativeObject reader(cx, ReaderFromStream(stream)); - MOZ_ASSERT(reader->is()); + RootedNativeObject reader(cx, &val.toObject().as()); // Step 2: MOZ_ASSERT: stream.[[state]] is "readable" or "closed". MOZ_ASSERT(stream->readable() || stream->closed()); @@ -1472,8 +1326,7 @@ ReadableStreamAddReadIntoRequest(JSContext* cx, Handle stream) // Step 4: Let readIntoRequest be Record {[[promise]]: promise}. // Step 5: Append readIntoRequest as the last element of stream.[[reader]].[[readIntoRequests]]. val = reader->getFixedSlot(ReaderSlot_Requests); - RootedNativeObject readIntoRequests(cx); - readIntoRequests = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject readIntoRequests(cx, &val.toObject().as()); // Since [[promise]] is the Record's only field, we store it directly. val = ObjectValue(*promise); if (!AppendToList(cx, readIntoRequests, val)) @@ -1503,8 +1356,7 @@ ReadableStreamAddReadRequest(JSContext* cx, Handle stream) // Step 4: Let readRequest be Record {[[promise]]: promise}. // Step 5: Append readRequest as the last element of stream.[[reader]].[[readRequests]]. RootedValue val(cx, reader->getFixedSlot(ReaderSlot_Requests)); - RootedNativeObject readRequests(cx); - readRequests = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject readRequests(cx, &val.toObject().as()); // Since [[promise]] is the Record's only field, we store it directly. val = ObjectValue(*promise); @@ -1548,8 +1400,6 @@ ReadableStream::cancel(JSContext* cx, Handle stream, HandleValu // with stream.[[storedError]]. if (stream->errored()) { RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); - if (!JS_WrapValue(cx, &storedError)) - return nullptr; return PromiseObject::unforgeableReject(cx, storedError); } @@ -1593,14 +1443,13 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) return true; // Step 5: If ! IsReadableStreamDefaultReader(reader) is true, - RootedNativeObject reader(cx, ReaderFromStream(stream)); + RootedNativeObject reader(cx, &val.toObject().as()); if (reader->is()) { // Step a: Repeat for each readRequest that is an element of // reader.[[readRequests]], val = reader->getFixedSlot(ReaderSlot_Requests); if (!val.isUndefined()) { - RootedNativeObject readRequests(cx); - readRequests = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject readRequests(cx, &val.toObject().as()); uint32_t len = readRequests->getDenseInitializedLength(); RootedObject readRequest(cx); RootedObject resultObj(cx); @@ -1613,7 +1462,7 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) if (!resultObj) return false; resultVal = ObjectValue(*resultObj); - if (!ResolveMaybeWrappedPromise(cx, readRequest, resultVal)) + if (!ResolvePromise(cx, readRequest, resultVal)) return false; } @@ -1625,7 +1474,7 @@ ReadableStreamCloseInternal(JSContext* cx, Handle stream) // Step 6: Resolve reader.[[closedPromise]] with undefined. // Step 7: Return (implicit). RootedObject closedPromise(cx, &reader->getFixedSlot(ReaderSlot_ClosedPromise).toObject()); - if (!ResolveMaybeWrappedPromise(cx, closedPromise, UndefinedHandleValue)) + if (!ResolvePromise(cx, closedPromise, UndefinedHandleValue)) return false; if (stream->mode() == JS::ReadableStreamMode::ExternalSource && @@ -1653,13 +1502,7 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl SetStreamState(stream, (state & ReadableStream::Disturbed) | ReadableStream::Errored); // Step 4: Set stream.[[storedError]] to e. - RootedValue storedError(cx, e); - { - JSAutoCompartment ac(cx, stream); - if (!JS_WrapValue(cx, &storedError)) - return false; - stream->setFixedSlot(StreamSlot_StoredError, storedError); - } + stream->setFixedSlot(StreamSlot_StoredError, e); // Step 5: Let reader be stream.[[reader]]. RootedValue val(cx, stream->getFixedSlot(StreamSlot_Reader)); @@ -1667,21 +1510,20 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl // Step 6: If reader is undefined, return. if (val.isUndefined()) return true; - RootedNativeObject reader(cx, ReaderFromStream(stream)); + RootedNativeObject reader(cx, &val.toObject().as()); // Steps 7,8: (Identical in our implementation.) // Step a: Repeat for each readRequest that is an element of // reader.[[readRequests]], val = reader->getFixedSlot(ReaderSlot_Requests); - RootedNativeObject readRequests(cx); - readRequests = UnwrapInternalSlotObject(&val.toObject()); - RootedObject readRequest(cx); + RootedNativeObject readRequests(cx, &val.toObject().as()); + Rooted readRequest(cx); uint32_t len = readRequests->getDenseInitializedLength(); for (uint32_t i = 0; i < len; i++) { // Step i: Reject readRequest.[[promise]] with e. val = readRequests->getDenseElement(i); - readRequest = &val.toObject(); - if (!RejectMaybeWrappedPromise(cx, readRequest, e)) + readRequest = &val.toObject().as(); + if (!PromiseObject::reject(cx, readRequest, e)) return false; } @@ -1691,8 +1533,8 @@ ReadableStreamErrorInternal(JSContext* cx, Handle stream, Handl // Step 9: Reject reader.[[closedPromise]] with e. val = reader->getFixedSlot(ReaderSlot_ClosedPromise); - RootedObject closedPromise(cx, &val.toObject()); - if (!RejectMaybeWrappedPromise(cx, closedPromise, e)) + Rooted closedPromise(cx, &val.toObject().as()); + if (!PromiseObject::reject(cx, closedPromise, e)) return false; if (stream->mode() == JS::ReadableStreamMode::ExternalSource && @@ -1716,7 +1558,7 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(StreamSlot_Reader)); - RootedNativeObject reader(cx, ReaderFromStream(stream)); + RootedNativeObject reader(cx, &val.toObject().as()); // Step 2: Let readIntoRequest be the first element of // reader.[[readIntoRequests]]. @@ -1724,8 +1566,7 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(ReaderSlot_Requests); - RootedNativeObject readIntoRequests(cx); - readIntoRequests = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject readIntoRequests(cx, &val.toObject().as()); Rooted readIntoRequest(cx); readIntoRequest = ShiftFromList(cx, readIntoRequests); MOZ_ASSERT(readIntoRequest); @@ -1736,8 +1577,7 @@ ReadableStreamFulfillReadOrReadIntoRequest(JSContext* cx, HandlegetFixedSlot(ReaderSlot_Requests); - NativeObject* requests = UnwrapInternalSlotObject(&readRequests.toObject()); - return requests->getDenseInitializedLength(); + return readRequests.toObject().as().getDenseInitializedLength(); } // Stream spec 3.4.10. ReadableStreamHasBYOBReader ( stream ) @@ -1765,10 +1604,7 @@ ReadableStreamHasBYOBReader(ReadableStream* stream) // Step 3: If ! IsReadableStreamBYOBReader(reader) is false, return false. // Step 4: Return true. Value reader = stream->getFixedSlot(StreamSlot_Reader); - if (!reader.isObject()) - return false; - JSObject* unwrapped = UncheckedUnwrap(&reader.toObject()); - return unwrapped && unwrapped->is(); + return reader.isObject() && reader.toObject().is(); } // Streap spec 3.4.11. ReadableStreamHasDefaultReader ( stream ) @@ -1780,10 +1616,7 @@ ReadableStreamHasDefaultReader(ReadableStream* stream) // Step 3: If ! ReadableStreamDefaultReader(reader) is false, return false. // Step 4: Return true. Value reader = stream->getFixedSlot(StreamSlot_Reader); - if (!reader.isObject()) - return false; - JSObject* unwrapped = UncheckedUnwrap(&reader.toObject()); - return unwrapped && unwrapped->is(); + return reader.isObject() && reader.toObject().is(); } static MOZ_MUST_USE bool @@ -1830,13 +1663,14 @@ ReadableStreamDefaultReader::constructor(JSContext* cx, unsigned argc, Value* vp return false; // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - Rooted stream(cx, UnwrapMaybeWrappedArg(args.get(0))); - if (!stream) { + if (!Is(args.get(0))) { ReportArgTypeError(cx, "ReadableStreamDefaultReader", "ReadableStream", args.get(0)); return false; } + Rooted stream(cx, &args.get(0).toObject().as()); + RootedObject reader(cx, CreateReadableStreamDefaultReader(cx, stream)); if (!reader) return false; @@ -1846,40 +1680,36 @@ ReadableStreamDefaultReader::constructor(JSContext* cx, unsigned argc, Value* vp } // Streams spec, 3.5.4.1 get closed -[[nodiscard]] static bool -ReadableStreamDefaultReader_closed_impl(JSContext* cx, const CallArgs& args) -{ - // Step 2: Return this.[[closedPromise]]. - NativeObject* reader = &args.thisv().toObject().as(); - args.rval().set(reader->getFixedSlot(ReaderSlot_ClosedPromise)); - return true; -} - -static bool +static MOZ_MUST_USE bool ReadableStreamDefaultReader_closed(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise // rejected with a TypeError exception. - if (!Is(args.thisv())) { - if (IsMaybeWrapped(args.thisv())) { - return CallNonGenericMethod, - ReadableStreamDefaultReader_closed_impl>(cx, args); - } + if (!Is(args.thisv())) return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "get closed"); - } - return ReadableStreamDefaultReader_closed_impl(cx, args); + // Step 2: Return this.[[closedPromise]]. + NativeObject* reader = &args.thisv().toObject().as(); + args.rval().set(reader->getFixedSlot(ReaderSlot_ClosedPromise)); + return true; } static MOZ_MUST_USE JSObject* ReadableStreamReaderGenericCancel(JSContext* cx, HandleNativeObject reader, HandleValue reason); // Streams spec, 3.5.4.2. cancel ( reason ) -[[nodiscard]] static bool -ReadableStreamDefaultReader_cancel_impl(JSContext* cx, const CallArgs& args) +static MOZ_MUST_USE bool +ReadableStreamDefaultReader_cancel(JSContext* cx, unsigned argc, Value* vp) { + CallArgs args = CallArgsFromVp(argc, vp); + + // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise + // rejected with a TypeError exception. + if (!Is(args.thisv())) + return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "cancel"); + // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise // rejected with a TypeError exception. RootedNativeObject reader(cx, &args.thisv().toObject().as()); @@ -1897,28 +1727,17 @@ ReadableStreamDefaultReader_cancel_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -ReadableStreamDefaultReader_cancel(JSContext* cx, unsigned argc, Value* vp) +// Streams spec, 3.5.4.3 read ( ) +static MOZ_MUST_USE bool +ReadableStreamDefaultReader_read(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise // rejected with a TypeError exception. - if (!Is(args.thisv())) { - if (IsMaybeWrapped(args.thisv())) { - return CallNonGenericMethod, - ReadableStreamDefaultReader_cancel_impl>(cx, args); - } - return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "cancel"); - } + if (!Is(args.thisv())) + return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "read"); - return ReadableStreamDefaultReader_cancel_impl(cx, args); -} - -// Streams spec, 3.5.4.3 read ( ) -[[nodiscard]] static bool -ReadableStreamDefaultReader_read_impl(JSContext* cx, const CallArgs& args) -{ // Step 2: If this.[[ownerReadableStream]] is undefined, return a promise // rejected with a TypeError exception. Rooted reader(cx); @@ -1937,25 +1756,7 @@ ReadableStreamDefaultReader_read_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -ReadableStreamDefaultReader_read(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - // Step 1: If ! IsReadableStreamDefaultReader(this) is false, return a promise - // rejected with a TypeError exception. - if (!Is(args.thisv())) { - if (IsMaybeWrapped(args.thisv())) { - return CallNonGenericMethod, - ReadableStreamDefaultReader_read_impl>(cx, args); - } - return RejectNonGenericMethod(cx, args, "ReadableStreamDefaultReader", "read"); - } - - return ReadableStreamDefaultReader_read_impl(cx, args); -} - -[[nodiscard]] static bool +static MOZ_MUST_USE bool ReadableStreamReaderGenericRelease(JSContext* cx, HandleNativeObject reader); // Streams spec, 3.5.4.4. releaseLock ( ) @@ -2010,7 +1811,8 @@ static const JSPropertySpec ReadableStreamDefaultReader_properties[] = { JS_PS_END }; -CLASS_SPEC(ReadableStreamDefaultReader, 1, ReaderSlotCount, 0, 0, JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamDefaultReader, 1, ReaderSlotCount, ClassSpec::DontDefineConstructor, 0, + JS_NULL_CLASS_OPS); // Streams spec, 3.6.3 new ReadableStreamBYOBReader ( stream ) @@ -2060,12 +1862,12 @@ ReadableStreamBYOBReader::constructor(JSContext* cx, unsigned argc, Value* vp) return false; // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. - Rooted stream(cx, UnwrapMaybeWrappedArg(args.get(0))); - if (!stream) { + if (!Is(args.get(0))) { ReportArgTypeError(cx, "ReadableStreamBYOBReader", "ReadableStream", args.get(0)); return false; } + Rooted stream(cx, &args.get(0).toObject().as()); RootedObject reader(cx, CreateReadableStreamBYOBReader(cx, stream)); if (!reader) return false; @@ -2224,7 +2026,7 @@ static const JSFunctionSpec ReadableStreamBYOBReader_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamBYOBReader, 1, 3, 0, 0, JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamBYOBReader, 1, 3, ClassSpec::DontDefineConstructor, 0, JS_NULL_CLASS_OPS); inline static MOZ_MUST_USE bool ReadableStreamControllerCallPullIfNeeded(JSContext* cx, HandleNativeObject controller); @@ -2245,21 +2047,7 @@ ReadableStreamReaderGenericCancel(JSContext* cx, HandleNativeObject reader, Hand // Step 2: Assert: stream is not undefined (implicit). // Step 3: Return ! ReadableStreamCancel(stream, reason). - RootedObject cancelPromise(cx); - { - JSAutoCompartment ac(cx, stream); - RootedValue wrappedReason(cx, reason); - if (!JS_WrapValue(cx, &wrappedReason)) - return nullptr; - - cancelPromise = ReadableStreamCancel(cx, stream, wrappedReason); - if (!cancelPromise) - return nullptr; - } - - if (!JS_WrapObject(cx, &cancelPromise)) - return nullptr; - return cancelPromise; + return &ReadableStreamCancel(cx, stream, reason)->as(); } // Streams spec, 3.7.4. ReadableStreamReaderGenericInitialize ( reader, stream ) @@ -2268,19 +2056,10 @@ ReadableStreamReaderGenericInitialize(JSContext* cx, HandleNativeObject reader, Handle stream) { // Step 1: Set reader.[[ownerReadableStream]] to stream. - RootedValue streamVal(cx, ObjectValue(*stream)); - if (!JS_WrapValue(cx, &streamVal)) - return false; - reader->setFixedSlot(ReaderSlot_Stream, streamVal); + reader->setFixedSlot(ReaderSlot_Stream, ObjectValue(*stream)); // Step 2: Set stream.[[reader]] to reader. - RootedValue readerVal(cx, ObjectValue(*reader)); - { - JSAutoCompartment ac(cx, stream); - if (!JS_WrapValue(cx, &readerVal)) - return false; - stream->setFixedSlot(StreamSlot_Reader, readerVal); - } + stream->setFixedSlot(StreamSlot_Reader, ObjectValue(*reader)); // Step 3: If stream.[[state]] is "readable", RootedObject promise(cx); @@ -2301,8 +2080,6 @@ ReadableStreamReaderGenericInitialize(JSContext* cx, HandleNativeObject reader, // Step ii: Set reader.[[closedPromise]] to a new promise rejected with // stream.[[storedError]]. RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); - if (!JS_WrapValue(cx, &storedError)) - return false; promise = PromiseObject::unforgeableReject(cx, storedError); } @@ -2321,7 +2098,7 @@ ReadableStreamReaderGenericRelease(JSContext* cx, HandleNativeObject reader) Rooted stream(cx, StreamFromReader(reader)); // Step 2: Assert: reader.[[ownerReadableStream]].[[reader]] is reader. - MOZ_ASSERT(ReaderFromStream(stream) == reader); + MOZ_ASSERT(&stream->getFixedSlot(StreamSlot_Reader).toObject() == reader); // Create an exception to reject promises with below. We don't have a // clean way to do this, unfortunately. @@ -2379,8 +2156,6 @@ ReadableStreamBYOBReader::read(JSContext* cx, Handle // stream.[[storedError]]. if (stream->errored()) { RootedValue storedError(cx, stream->getFixedSlot(StreamSlot_StoredError)); - if (!JS_WrapValue(cx, &storedError)) - return nullptr; return PromiseObject::unforgeableReject(cx, storedError); } @@ -2572,12 +2347,40 @@ CreateReadableStreamDefaultController(JSContext* cx, Handle str bool ReadableStreamDefaultController::constructor(JSContext* cx, unsigned argc, Value* vp) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, - "ReadableStreamDefaultController"); - return false; + CallArgs args = CallArgsFromVp(argc, vp); + + if (!ThrowIfNotConstructing(cx, args, "ReadableStreamDefaultController")) + return false; + + // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. + HandleValue streamVal = args.get(0); + if (!Is(streamVal)) { + ReportArgTypeError(cx, "ReadableStreamDefaultController", "ReadableStream", + args.get(0)); + return false; + } + + Rooted stream(cx, &streamVal.toObject().as()); + + // Step 2: If stream.[[readableStreamController]] is not undefined, throw a + // TypeError exception. + if (HasController(stream)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_READABLESTREAM_CONTROLLER_SET); + return false; + } + + // Steps 3-11. + RootedObject controller(cx, CreateReadableStreamDefaultController(cx, stream, args.get(1), + args.get(2), args.get(3))); + if (!controller) + return false; + + args.rval().setObject(*controller); + return true; } -[[nodiscard]] static double +static MOZ_MUST_USE double ReadableStreamControllerGetDesiredSizeUnchecked(NativeObject* controller); // Streams spec, 3.8.4.1. get desiredSize @@ -2587,8 +2390,7 @@ static MOZ_MUST_USE bool ReadableStreamController_desiredSize_impl(JSContext* cx, const CallArgs& args) { RootedNativeObject controller(cx); - controller = UnwrapMaybeWrappedReadableStreamController(args.thisv()); - MOZ_ASSERT(controller); + controller = &args.thisv().toObject().as(); // Streams spec, 3.9.8. steps 1-4. // 3.9.8. Step 1: Let stream be controller.[[controlledReadableStream]]. @@ -2618,12 +2420,8 @@ ReadableStreamDefaultController_desiredSize(JSContext* cx, unsigned argc, Value* // Step 1: If ! IsReadableStreamDefaultController(this) is false, throw a // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - if (!IsMaybeWrapped(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "ReadableStreamDefaultController", "get desiredSize"); - return false; - } - return ReadableStreamController_desiredSize_impl(cx, args); + return CallNonGenericMethod, + ReadableStreamController_desiredSize_impl>(cx, args); } static MOZ_MUST_USE bool @@ -2658,8 +2456,7 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_close_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = UnwrapMaybeWrappedArg(args.thisv()); - MOZ_ASSERT(controller); + controller = &args.thisv().toObject().as(); // Steps 2-3. if (!VerifyControllerStateForClosing(cx, controller)) @@ -2679,12 +2476,8 @@ ReadableStreamDefaultController_close(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - if (!IsMaybeWrapped(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "ReadableStreamDefaultController", "close"); - return false; - } - return ReadableStreamDefaultController_close_impl(cx, args); + return CallNonGenericMethod, + ReadableStreamDefaultController_close_impl>(cx, args); } static MOZ_MUST_USE bool @@ -2697,8 +2490,7 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_enqueue_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = UnwrapMaybeWrappedArg(args.thisv()); - MOZ_ASSERT(controller); + controller = &args.thisv().toObject().as(); // Step 2: If this.[[closeRequested]] is true, throw a TypeError exception. if (ControllerFlags(controller) & ControllerFlag_CloseRequested) { @@ -2730,12 +2522,8 @@ ReadableStreamDefaultController_enqueue(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - if (!IsMaybeWrapped(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "ReadableStreamDefaultController", "enqueue"); - return false; - } - return ReadableStreamDefaultController_enqueue_impl(cx, args); + return CallNonGenericMethod, + ReadableStreamDefaultController_enqueue_impl>(cx, args); } // Streams spec, 3.8.4.4. error ( e ) @@ -2743,8 +2531,7 @@ static MOZ_MUST_USE bool ReadableStreamDefaultController_error_impl(JSContext* cx, const CallArgs& args) { Rooted controller(cx); - controller = UnwrapMaybeWrappedArg(args.thisv()); - MOZ_ASSERT(controller); + controller = &args.thisv().toObject().as(); // Step 2: Let stream be this.[[controlledReadableStream]]. // Step 3: If stream.[[state]] is not "readable", throw a TypeError exception. @@ -2768,12 +2555,8 @@ ReadableStreamDefaultController_error(JSContext* cx, unsigned argc, Value* vp) // TypeError exception. CallArgs args = CallArgsFromVp(argc, vp); - if (!IsMaybeWrapped(args.thisv())) { - ReportValueError3(cx, JSMSG_INCOMPATIBLE_PROTO, JSDVG_SEARCH_STACK, args.thisv(), - nullptr, "ReadableStreamDefaultController", "error"); - return false; - } - return ReadableStreamDefaultController_error_impl(cx, args); + return CallNonGenericMethod, + ReadableStreamDefaultController_error_impl>(cx, args); } static const JSPropertySpec ReadableStreamDefaultController_properties[] = { @@ -2788,7 +2571,8 @@ static const JSFunctionSpec ReadableStreamDefaultController_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamDefaultController, 4, 7, 0, 0, JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamDefaultController, 4, 7, ClassSpec::DontDefineConstructor, 0, + JS_NULL_CLASS_OPS); /** * Unified implementation of ReadableStream controllers' [[CancelSteps]] internal @@ -3332,9 +3116,36 @@ ReadableByteStreamController::hasExternalSource() { bool ReadableByteStreamController::constructor(JSContext* cx, unsigned argc, Value* vp) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR, - "ReadableByteStreamController"); - return false; + CallArgs args = CallArgsFromVp(argc, vp); + + if (!ThrowIfNotConstructing(cx, args, "ReadableByteStreamController")) + return false; + + // Step 1: If ! IsReadableStream(stream) is false, throw a TypeError exception. + HandleValue streamVal = args.get(0); + if (!Is(streamVal)) { + ReportArgTypeError(cx, "ReadableStreamDefaultController", "ReadableStream", + args.get(0)); + return false; + } + + Rooted stream(cx, &streamVal.toObject().as()); + + // Step 2: If stream.[[readableStreamController]] is not undefined, throw a + // TypeError exception. + if (HasController(stream)) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, + JSMSG_READABLESTREAM_CONTROLLER_SET); + return false; + } + + RootedObject controller(cx, CreateReadableByteStreamController(cx, stream, args.get(1), + args.get(2))); + if (!controller) + return false; + + args.rval().setObject(*controller); + return true; } // Version of the ReadableByteStreamConstructor that's specialized for @@ -3640,8 +3451,8 @@ static const ClassOps ReadableByteStreamControllerClassOps = { nullptr, /* trace */ }; -CLASS_SPEC(ReadableByteStreamController, 3, 9, 0, JSCLASS_BACKGROUND_FINALIZE, - &ReadableByteStreamControllerClassOps); +CLASS_SPEC(ReadableByteStreamController, 3, 9, ClassSpec::DontDefineConstructor, + JSCLASS_BACKGROUND_FINALIZE, &ReadableByteStreamControllerClassOps); // Streams spec, 3.10.5.1. [[PullSteps]] () // Unified with 3.8.5.1 above. @@ -3827,9 +3638,38 @@ CreateReadableStreamBYOBRequest(JSContext* cx, Handle(controllerVal)) { + ReportArgTypeError(cx, "ReadableStreamBYOBRequest", + "ReadableByteStreamController", args.get(0)); + return false; + } + + Rooted controller(cx); + controller = &controllerVal.toObject().as(); + + if (!viewVal.isObject() || !JS_IsArrayBufferViewObject(&viewVal.toObject())) { + ReportArgTypeError(cx, "ReadableStreamBYOBRequest", "ArrayBuffer view", + args.get(1)); + return false; + } + + RootedArrayBufferObject view(cx, &viewVal.toObject().as()); + + RootedObject request(cx, CreateReadableStreamBYOBRequest(cx, controller, view)); + if (!request) + return false; + + args.rval().setObject(*request); + return true; } // Streams spec, 3.11.4.1 get view @@ -3964,7 +3804,8 @@ static const JSFunctionSpec ReadableStreamBYOBRequest_methods[] = { JS_FS_END }; -CLASS_SPEC(ReadableStreamBYOBRequest, 3, 2, 0, 0, JS_NULL_CLASS_OPS); +CLASS_SPEC(ReadableStreamBYOBRequest, 3, 2, ClassSpec::DontDefineConstructor, 0, + JS_NULL_CLASS_OPS); // Streams spec, 3.12.1. IsReadableStreamBYOBRequest ( x ) // Implemented via is() @@ -5058,15 +4899,7 @@ js::ByteLengthQueuingStrategy::constructor(JSContext* cx, unsigned argc, Value* { CallArgs args = CallArgsFromVp(argc, vp); - if (!ThrowIfNotConstructing(cx, args, "ByteLengthQueuingStrategy")) - return false; - - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - RootedObject strategy(cx, NewObjectWithClassProto(cx, proto)); + RootedObject strategy(cx, NewBuiltinClassInstance(cx)); if (!strategy) return false; @@ -5112,16 +4945,7 @@ js::CountQueuingStrategy::constructor(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - if (!ThrowIfNotConstructing(cx, args, "CountQueuingStrategy")) - return false; - - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted strategy(cx); - strategy = NewObjectWithClassProto(cx, proto); + Rooted strategy(cx, NewBuiltinClassInstance(cx)); if (!strategy) return false; @@ -5174,8 +4998,7 @@ DequeueValue(JSContext* cx, HandleNativeObject container, MutableHandleValue chu // Step 2: Assert: queue is not empty. RootedValue val(cx, container->getFixedSlot(QueueContainerSlot_Queue)); - RootedNativeObject queue(cx); - queue = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject queue(cx, &val.toObject().as()); MOZ_ASSERT(queue->getDenseInitializedLength() > 0); // Step 3. Let pair be the first element of queue. @@ -5197,10 +5020,7 @@ DequeueValue(JSContext* cx, HandleNativeObject container, MutableHandleValue chu container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize)); // Step 7: Return pair.[[value]]. - RootedValue chunkVal(cx, pair->value()); - if (!JS_WrapValue(cx, &chunkVal)) - return false; - chunk.set(chunkVal); + chunk.set(pair->value()); return true; } @@ -5229,27 +5049,19 @@ EnqueueValueWithSize(JSContext* cx, HandleNativeObject container, HandleValue va // Step 4: Append Record {[[value]]: value, [[size]]: size} as the last element // of container.[[queue]]. RootedValue val(cx, container->getFixedSlot(QueueContainerSlot_Queue)); - RootedNativeObject queue(cx); - queue = UnwrapInternalSlotObject(&val.toObject()); + RootedNativeObject queue(cx, &val.toObject().as()); - { - JSAutoCompartment ac(cx, queue); - RootedValue wrappedValue(cx, value); - if (!JS_WrapValue(cx, &wrappedValue)) - return false; + QueueEntry* entry = QueueEntry::create(cx, value, size); + if (!entry) + return false; + val = ObjectValue(*entry); + if (!AppendToList(cx, queue, val)) + return false; - QueueEntry* entry = QueueEntry::create(cx, wrappedValue, size); - if (!entry) - return false; - val = ObjectValue(*entry); - if (!AppendToList(cx, queue, val)) - return false; - - // Step 5: Set container.[[queueTotalSize]] to - // container.[[queueTotalSize]] + size. - double totalSize = container->getFixedSlot(QueueContainerSlot_TotalSize).toNumber(); - container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize + size)); - } + // Step 5: Set container.[[queueTotalSize]] to + // container.[[queueTotalSize]] + size. + double totalSize = container->getFixedSlot(QueueContainerSlot_TotalSize).toNumber(); + container->setFixedSlot(QueueContainerSlot_TotalSize, NumberValue(totalSize + size)); return true; } @@ -5674,2285 +5486,3 @@ js::UnwrapReadableStream(JSObject* obj) return unwrapped->is() ? unwrapped : nullptr; return nullptr; } - -namespace { - -enum class StreamCompressionFormat { - Deflate, - DeflateRaw, - Gzip -}; - -struct StreamCompressionContext -{ - z_stream mStream; - StreamCompressionFormat mFormat; - bool mCompress; - bool mFinished; - bool mInitialized; - - StreamCompressionContext(StreamCompressionFormat format, bool compress) - : mFormat(format), - mCompress(compress), - mFinished(false), - mInitialized(false) - { - memset(&mStream, 0, sizeof(mStream)); - } - - ~StreamCompressionContext() - { - if (!mInitialized) - return; - if (mCompress) - deflateEnd(&mStream); - else - inflateEnd(&mStream); - } -}; - -static int -WindowBitsForFormat(StreamCompressionFormat format) -{ - switch (format) { - case StreamCompressionFormat::Deflate: - return MAX_WBITS; - case StreamCompressionFormat::DeflateRaw: - return -MAX_WBITS; - case StreamCompressionFormat::Gzip: - return MAX_WBITS + 16; - } - MOZ_CRASH("Unknown compression stream format"); -} - -static bool -ParseCompressionFormat(JSContext* cx, HandleValue value, - StreamCompressionFormat* format) -{ - RootedString str(cx, ToString(cx, value)); - if (!str) - return false; - - bool match = false; - if (!JS_StringEqualsAscii(cx, str, "deflate", &match)) - return false; - if (match) { - *format = StreamCompressionFormat::Deflate; - return true; - } - - if (!JS_StringEqualsAscii(cx, str, "deflate-raw", &match)) - return false; - if (match) { - *format = StreamCompressionFormat::DeflateRaw; - return true; - } - - if (!JS_StringEqualsAscii(cx, str, "gzip", &match)) - return false; - if (match) { - *format = StreamCompressionFormat::Gzip; - return true; - } - - if (!JS_StringEqualsAscii(cx, str, "brotli", &match)) - return false; - - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_NOT_EXPECTED_TYPE, - "CompressionStream", "supported format", - match ? "unsupported brotli format" : "unknown format"); - return false; -} - -static void -StreamCompressionContextFinalize(FreeOp* fop, JSObject* obj) -{ - auto* context = static_cast(JS_GetPrivate(obj)); - if (context) - js_delete(context); -} - -static const ClassOps StreamCompressionContextClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - StreamCompressionContextFinalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr /* trace */ -}; - -static const Class StreamCompressionContextClass = { - "StreamCompressionContext", - JSCLASS_HAS_PRIVATE, - &StreamCompressionContextClassOps -}; - -static bool -CreateStreamCompressionContext(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (args.length() < 2) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_MORE_ARGS_NEEDED, - "__uxpCreateCompressionContext", "1", "s"); - return false; - } - - StreamCompressionFormat format; - if (!ParseCompressionFormat(cx, args.get(0), &format)) - return false; - - bool compress = ToBoolean(args.get(1)); - auto* context = js_new(format, compress); - if (!context) { - ReportOutOfMemory(cx); - return false; - } - - int windowBits = WindowBitsForFormat(format); - int zerr = compress - ? deflateInit2(&context->mStream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, - windowBits, 8, Z_DEFAULT_STRATEGY) - : inflateInit2(&context->mStream, windowBits); - if (zerr != Z_OK) { - js_delete(context); - JS_ReportErrorASCII(cx, "Failed to initialize compression stream"); - return false; - } - context->mInitialized = true; - - RootedObject obj(cx, NewObjectWithGivenProto(cx, &StreamCompressionContextClass, nullptr)); - if (!obj) { - js_delete(context); - return false; - } - - JS_SetPrivate(obj, context); - args.rval().setObject(*obj); - return true; -} - -static bool -GetBufferSourceBytes(JSContext* cx, HandleValue value, Vector* bytes) -{ - if (!value.isObject()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_NOT_EXPECTED_TYPE, - "CompressionStream", "BufferSource", - InformalValueTypeName(value)); - return false; - } - - RootedObject obj(cx, &value.toObject()); - if (JS_IsArrayBufferViewObject(obj)) { - uint32_t length = JS_GetArrayBufferViewByteLength(obj); - if (length == 0) - return true; - - JS::AutoCheckCannotGC nogc(cx); - bool isShared; - uint8_t* data = static_cast(JS_GetArrayBufferViewData(obj, &isShared, nogc)); - return bytes->append(data, length); - } - - if (JS_IsArrayBufferObject(obj)) { - uint32_t length = JS_GetArrayBufferByteLength(obj); - if (length == 0) - return true; - - JS::AutoCheckCannotGC nogc(cx); - bool isShared; - uint8_t* data = JS_GetArrayBufferData(obj, &isShared, nogc); - return bytes->append(data, length); - } - - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_NOT_EXPECTED_TYPE, - "CompressionStream", "BufferSource", - obj->getClass()->name); - return false; -} - -static bool -AppendUint8Array(JSContext* cx, HandleObject array, uint32_t* index, - const uint8_t* data, size_t length) -{ - if (length == 0) - return true; - - if (length > UINT32_MAX) { - ReportAllocationOverflow(cx); - return false; - } - - RootedObject view(cx, JS_NewUint8Array(cx, length)); - if (!view) - return false; - - { - JS::AutoCheckCannotGC nogc(cx); - bool isShared; - uint8_t* viewData = static_cast(JS_GetArrayBufferViewData(view, &isShared, nogc)); - memcpy(viewData, data, length); - } - - RootedValue viewVal(cx, ObjectValue(*view)); - return JS_SetElement(cx, array, (*index)++, viewVal); -} - -static bool -StreamCompressionProcess(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (args.length() < 3 || !args[0].isObject() || - !args[0].toObject().hasClass(&StreamCompressionContextClass)) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, - JSMSG_NOT_EXPECTED_TYPE, - "__uxpCompressionProcess", - "StreamCompressionContext", "other"); - return false; - } - - auto* context = - static_cast(JS_GetPrivate(&args[0].toObject())); - if (!context) { - JS_ReportErrorASCII(cx, "Compression stream is already finished"); - return false; - } - - bool finish = ToBoolean(args.get(2)); - - if (context->mFinished) { - if (finish && args.get(1).isUndefined()) { - RootedObject emptyChunks(cx, JS_NewArrayObject(cx, 0)); - if (!emptyChunks) - return false; - args.rval().setObject(*emptyChunks); - return true; - } - JS_ReportErrorASCII(cx, "Compression stream is already finished"); - return false; - } - - Vector input(cx); - if (!args.get(1).isUndefined() && !GetBufferSourceBytes(cx, args.get(1), &input)) - return false; - - RootedObject chunks(cx, JS_NewArrayObject(cx, 0)); - if (!chunks) - return false; - - z_stream& stream = context->mStream; - stream.next_in = input.empty() ? nullptr : input.begin(); - stream.avail_in = input.length(); - - uint32_t chunkIndex = 0; - const int flush = finish ? Z_FINISH : Z_NO_FLUSH; - bool madeProgress; - - do { - uint8_t output[16384]; - stream.next_out = output; - stream.avail_out = sizeof(output); - - uint32_t beforeIn = stream.avail_in; - uint32_t beforeOut = stream.avail_out; - int zerr = context->mCompress ? deflate(&stream, flush) : inflate(&stream, flush); - - size_t produced = sizeof(output) - stream.avail_out; - if (!AppendUint8Array(cx, chunks, &chunkIndex, output, produced)) - return false; - - madeProgress = produced > 0 || stream.avail_in != beforeIn || - stream.avail_out != beforeOut; - - if (zerr == Z_STREAM_END) { - context->mFinished = true; - if (!context->mCompress && stream.avail_in != 0) { - JS_ReportErrorASCII(cx, "Compressed input has trailing data"); - return false; - } - break; - } - - if (zerr == Z_BUF_ERROR && !madeProgress) - break; - - if (zerr != Z_OK && zerr != Z_BUF_ERROR) { - JS_ReportErrorASCII(cx, stream.msg ? stream.msg : "Compression stream error"); - return false; - } - } while (stream.avail_out == 0 || stream.avail_in != 0 || - (finish && !context->mFinished && madeProgress)); - - if (finish && !context->mFinished) { - JS_ReportErrorASCII(cx, "Compressed input ended before the end of stream"); - return false; - } - - args.rval().setObject(*chunks); - return true; -} - -bool -ReleaseReadableStreamReaderSilently(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().setBoolean(true); - - if (!args.get(0).isObject()) - return true; - - RootedObject readerObj(cx, &args[0].toObject()); - if (!readerObj->is() && - !readerObj->is()) - return true; - - RootedNativeObject reader(cx, &readerObj->as()); - if (!ReaderHasStream(reader)) - return true; - - Value requestsVal = reader->getFixedSlot(ReaderSlot_Requests); - if (!requestsVal.isUndefined()) { - NativeObject* requests = &requestsVal.toObject().as(); - if (requests->getDenseInitializedLength() != 0) { - args.rval().setBoolean(false); - return true; - } - } - - Rooted stream(cx, StreamFromReader(reader)); - MOZ_ASSERT(&stream->getFixedSlot(StreamSlot_Reader).toObject() == reader); - - RootedObject closedPromise(cx, PromiseObject::unforgeableResolve(cx, UndefinedHandleValue)); - if (!closedPromise) - return false; - reader->setFixedSlot(ReaderSlot_ClosedPromise, ObjectValue(*closedPromise)); - - stream->setFixedSlot(StreamSlot_Reader, UndefinedValue()); - reader->setFixedSlot(ReaderSlot_Stream, UndefinedValue()); - return true; -} - -} // anonymous namespace - -bool -js::InitStreamExtras(JSContext* cx, HandleObject global) -{ - if (!JS_DefineFunction(cx, global, "__uxpCreateCompressionContext", - CreateStreamCompressionContext, 2, 0)) - return false; - - if (!JS_DefineFunction(cx, global, "__uxpCompressionProcess", - StreamCompressionProcess, 3, 0)) - return false; - - if (!JS_DefineFunction(cx, global, "__uxpReleaseReadableStreamReaderSilently", - ReleaseReadableStreamReaderSilently, 1, 0)) - return false; - - static const char source[] = - R"JS( -(function(global) { - "use strict"; - - if (global.__uxpStreamsInitialized) - return; - Object.defineProperty(global, "__uxpStreamsInitialized", - { value: true, configurable: true }); - - var objectToString = Object.prototype.toString; - var hasOwn = Object.prototype.hasOwnProperty; - - function isObject(value) { - return (typeof value === "object" && value !== null) || - typeof value === "function"; - } - - function requiredObject(value, name) { - if (!isObject(value)) - throw new TypeError(name + " is not an object"); - return value; - } - - function newPromiseCapability() { - var resolve, reject; - var promise = new Promise(function(res, rej) { - resolve = res; - reject = rej; - }); - return { promise: promise, resolve: resolve, reject: reject }; - } - - function promiseCall(fn, receiver, args) { - try { - return Promise.resolve(fn.apply(receiver, args || [])); - } catch (e) { - return Promise.reject(e); - } - } - - function getMethod(value, name) { - var method = value[name]; - if (method === undefined || method === null) - return undefined; - if (typeof method !== "function") - throw new TypeError(name + " is not callable"); - return method; - } - - function makeDOMException(message, name) { - if (typeof global.DOMException === "function") - return new global.DOMException(message, name); - var error = new Error(message); - error.name = name; - return error; - } - - function define(name, value) { - if (hasOwn.call(global, name) && global[name] !== undefined) - return; - Object.defineProperty(global, name, { - value: value, - writable: true, - configurable: true - }); - } - - var writableState = new WeakMap(); - var writerState = new WeakMap(); - var writableControllerState = new WeakMap(); - - function isWritableStream(stream) { - return writableState.has(stream); - } - - function isWritableStreamDefaultWriter(writer) { - return writerState.has(writer); - } - - function rejectPromise(error) { - return Promise.reject(error); - } - - function silenceRejection(promise) { - try { - if (promise && typeof promise.catch === "function") - promise.catch(function() {}); - } catch (e) {} - } - - function releaseReaderLock(reader) { - try { - if (global.__uxpReleaseReadableStreamReaderSilently(reader)) - return; - } catch (e) {} - Promise.resolve().then(function() { - try { - if (global.__uxpReleaseReadableStreamReaderSilently(reader)) - return; - } catch (e) {} - try { silenceRejection(reader.closed); } catch (e) {} - try { reader.releaseLock(); } catch (e) {} - }); - } - - function releaseWriterLock(writer) { - try { silenceRejection(writer.closed); } catch (e) {} - try { silenceRejection(writer.ready); } catch (e) {} - try { writer.releaseLock(); } catch (e) {} - } - - function syncWritableWriterWithStream(writer, state) { - var ws = writerState.get(writer); - if (!ws || ws.stream === undefined) - return; - - ws.readyPromise = state.readyPromise; - if (state.state === "closed") { - ws.closedPromise = Promise.resolve(undefined); - } else if (state.state === "errored") { - ws.closedPromise = Promise.reject(state.storedError); - ws.closedPromise.catch(function() {}); - } else { - ws.closedPromise = state.closedPromise; - } - } - - function writableError(stream, error) { - var state = writableState.get(stream); - if (!state || state.state === "closed" || state.state === "errored") - return; - state.state = "errored"; - state.storedError = error; - state.ready.reject(error); - state.closed.reject(error); - state.readyPromise.catch(function() {}); - state.closedPromise.catch(function() {}); - if (state.writer) - syncWritableWriterWithStream(state.writer, state); - } - - function writableClose(stream) { - var state = writableState.get(stream); - if (!state || state.state === "closed") - return; - state.state = "closed"; - state.ready.resolve(undefined); - state.closed.resolve(undefined); - if (state.writer) - syncWritableWriterWithStream(state.writer, state); - } - - function writableStreamWrite(stream, chunk) { - var state = writableState.get(stream); - if (!state) - return rejectPromise(new TypeError("WritableStream expected")); - if (state.state === "closed") - return rejectPromise(new TypeError("WritableStream is closed")); - if (state.state === "errored") - return rejectPromise(state.storedError); - if (state.state === "closing") - return rejectPromise(new TypeError("WritableStream is closing")); - - var size = 1; - try { - size = state.sizeAlgorithm(chunk); - if (!Number.isFinite(size) || size < 0) - throw new RangeError("Invalid chunk size"); - } catch (e) { - writableError(stream, e); - return rejectPromise(e); - } - - state.queueTotalSize += size; - if (state.queueTotalSize > state.highWaterMark && state.backpressure === false) { - state.backpressure = true; - state.ready = newPromiseCapability(); - state.readyPromise = state.ready.promise; - if (state.writer) - syncWritableWriterWithStream(state.writer, state); - } - - var write = state.sink.write; - var controller = state.controller; - var writePromise = state.writeChain.then(function() { - if (state.state === "errored") - throw state.storedError; - if (write) - return write.call(state.sink, chunk, controller); - return undefined; - }); - state.writeChain = writePromise.then(function(value) { - state.queueTotalSize -= size; - if (state.queueTotalSize <= state.highWaterMark && state.backpressure) { - state.backpressure = false; - state.ready.resolve(undefined); - state.ready = newPromiseCapability(); - state.ready.resolve(undefined); - state.readyPromise = state.ready.promise; - if (state.writer) - syncWritableWriterWithStream(state.writer, state); - } - return value; - }, function(error) { - writableError(stream, error); - throw error; - }); - state.writeChain.catch(function() {}); - return writePromise; - } - - function writableStreamClose(stream) { - var state = writableState.get(stream); - if (!state) - return rejectPromise(new TypeError("WritableStream expected")); - if (state.state === "closed") - return rejectPromise(new TypeError("WritableStream is already closed")); - if (state.state === "errored") - return rejectPromise(state.storedError); - if (state.state === "closing") - return rejectPromise(new TypeError("WritableStream is already closing")); - - state.state = "closing"; - var close = state.sink.close; - var closePromise = state.writeChain.then(function() { - if (close) - return close.call(state.sink); - return undefined; - }).then(function(value) { - writableClose(stream); - return value; - }, function(error) { - writableError(stream, error); - throw error; - }); - state.writeChain = closePromise.catch(function() {}); - return closePromise; - } - - function writableStreamAbort(stream, reason) { - var state = writableState.get(stream); - if (!state) - return rejectPromise(new TypeError("WritableStream expected")); - if (state.state === "closed") - return Promise.resolve(undefined); - if (state.state === "errored") - return rejectPromise(state.storedError); - - var abort = state.sink.abort; - state.state = "errored"; - state.storedError = reason; - if (state.abortController) { - try { state.abortController.abort(); } catch (e) {} - } - state.ready.reject(reason); - state.closed.reject(reason); - state.readyPromise.catch(function() {}); - state.closedPromise.catch(function() {}); - if (state.writer) - syncWritableWriterWithStream(state.writer, state); - - var abortPromise = abort ? promiseCall(abort, state.sink, [reason]) - : Promise.resolve(undefined); - return abortPromise; - } - - function WritableStreamDefaultController() { - throw new TypeError("Illegal constructor"); - } - - WritableStreamDefaultController.prototype.error = function(error) { - var state = writableControllerState.get(this); - if (!state) - throw new TypeError("WritableStreamDefaultController expected"); - writableError(state.stream, error); - }; - - try { - Object.defineProperty(WritableStreamDefaultController.prototype, "signal", { - configurable: true, - get: function() { - var state = writableControllerState.get(this); - if (!state) - throw new TypeError("WritableStreamDefaultController expected"); - return state.abortController ? state.abortController.signal : undefined; - } - }); - } catch (e) {} - - Object.defineProperty(WritableStreamDefaultController.prototype, - Symbol.toStringTag, - { value: "WritableStreamDefaultController", - configurable: true }); - - function WritableStream(underlyingSink, strategy) { - if (!(this instanceof WritableStream)) - throw new TypeError("WritableStream must be constructed with new"); - - underlyingSink = underlyingSink === undefined ? {} : requiredObject(underlyingSink, "underlyingSink"); - strategy = strategy === undefined ? {} : requiredObject(strategy, "strategy"); - - if (underlyingSink.type !== undefined) - throw new RangeError("Invalid writable stream type"); - - var highWaterMark = strategy.highWaterMark === undefined ? 1 : Number(strategy.highWaterMark); - if (Number.isNaN(highWaterMark) || highWaterMark < 0) - throw new RangeError("Invalid highWaterMark"); - - var sizeAlgorithm = strategy.size; - if (sizeAlgorithm === undefined) - sizeAlgorithm = function() { return 1; }; - if (typeof sizeAlgorithm !== "function") - throw new TypeError("strategy.size is not callable"); - - var controller = Object.create(WritableStreamDefaultController.prototype); - var abortController = typeof global.AbortController === "function" - ? new global.AbortController() - : undefined; - var ready = newPromiseCapability(); - ready.resolve(undefined); - var closed = newPromiseCapability(); - var state = { - sink: underlyingSink, - controller: controller, - signal: undefined, - state: "writable", - storedError: undefined, - writer: undefined, - abortController: abortController, - writeChain: Promise.resolve(undefined), - ready: ready, - readyPromise: ready.promise, - closed: closed, - closedPromise: closed.promise, - highWaterMark: highWaterMark, - sizeAlgorithm: sizeAlgorithm, - queueTotalSize: 0, - backpressure: false - }; - writableState.set(this, state); - writableControllerState.set(controller, { - stream: this, - abortController: abortController - }); - - var start = underlyingSink.start; - if (start !== undefined) { - if (typeof start !== "function") - throw new TypeError("underlyingSink.start is not callable"); - state.writeChain = promiseCall(start, underlyingSink, [controller]).catch(function(error) { - writableError(this, error); - throw error; - }.bind(this)); - state.writeChain.catch(function() {}); - } - } - - Object.defineProperty(WritableStream.prototype, "locked", { - configurable: true, - get: function() { - var state = writableState.get(this); - if (!state) - throw new TypeError("WritableStream expected"); - return state.writer !== undefined; - } - }); - - WritableStream.prototype.abort = function(reason) { - if (!isWritableStream(this)) - return rejectPromise(new TypeError("WritableStream expected")); - if (writableState.get(this).writer !== undefined) - return rejectPromise(new TypeError("WritableStream is locked")); - return writableStreamAbort(this, reason); - }; - - WritableStream.prototype.close = function() { - if (!isWritableStream(this)) - return rejectPromise(new TypeError("WritableStream expected")); - if (writableState.get(this).writer !== undefined) - return rejectPromise(new TypeError("WritableStream is locked")); - return writableStreamClose(this); - }; - - WritableStream.prototype.getWriter = function() { - if (!isWritableStream(this)) - throw new TypeError("WritableStream expected"); - return new WritableStreamDefaultWriter(this); - }; - - Object.defineProperty(WritableStream.prototype, Symbol.toStringTag, - { value: "WritableStream", configurable: true }); - - function WritableStreamDefaultWriter(stream) { - if (!(this instanceof WritableStreamDefaultWriter)) - throw new TypeError("WritableStreamDefaultWriter must be constructed with new"); - if (!isWritableStream(stream)) - throw new TypeError("WritableStream expected"); - - var state = writableState.get(stream); - if (state.writer !== undefined) - throw new TypeError("WritableStream is locked"); - - state.writer = this; - writerState.set(this, { - stream: stream, - readyPromise: state.readyPromise, - closedPromise: state.closedPromise - }); - } - - Object.defineProperty(WritableStreamDefaultWriter.prototype, "closed", { - configurable: true, - get: function() { - var state = writerState.get(this); - if (!state) - return rejectPromise(new TypeError("WritableStreamDefaultWriter expected")); - return state.closedPromise; - } - }); - - Object.defineProperty(WritableStreamDefaultWriter.prototype, "desiredSize", { - configurable: true, - get: function() { - var state = writerState.get(this); - if (!state) - throw new TypeError("WritableStreamDefaultWriter expected"); - if (state.stream === undefined) - throw new TypeError("Writer lock is released"); - var streamState = writableState.get(state.stream); - if (streamState.state === "errored") - return null; - if (streamState.state === "closed") - return 0; - return streamState.highWaterMark - streamState.queueTotalSize; - } - }); - - Object.defineProperty(WritableStreamDefaultWriter.prototype, "ready", { - configurable: true, - get: function() { - var state = writerState.get(this); - if (!state) - return rejectPromise(new TypeError("WritableStreamDefaultWriter expected")); - return state.readyPromise; - } - }); - - WritableStreamDefaultWriter.prototype.abort = function(reason) { - var state = writerState.get(this); - if (!state || state.stream === undefined) - return rejectPromise(new TypeError("Writer lock is released")); - return writableStreamAbort(state.stream, reason); - }; - - WritableStreamDefaultWriter.prototype.close = function() { - var state = writerState.get(this); - if (!state || state.stream === undefined) - return rejectPromise(new TypeError("Writer lock is released")); - return writableStreamClose(state.stream); - }; - - WritableStreamDefaultWriter.prototype.releaseLock = function() { - var state = writerState.get(this); - if (!state) - throw new TypeError("WritableStreamDefaultWriter expected"); - if (state.stream === undefined) - return; - var streamState = writableState.get(state.stream); - if (streamState.writer === this) - streamState.writer = undefined; - state.stream = undefined; - state.readyPromise = rejectPromise(new TypeError("Writer lock is released")); - state.closedPromise = rejectPromise(new TypeError("Writer lock is released")); - state.readyPromise.catch(function() {}); - state.closedPromise.catch(function() {}); - }; - - WritableStreamDefaultWriter.prototype.write = function(chunk) { - var state = writerState.get(this); - if (!state || state.stream === undefined) - return rejectPromise(new TypeError("Writer lock is released")); - return writableStreamWrite(state.stream, chunk); - }; - -)JS" -R"JS( - - Object.defineProperty(WritableStreamDefaultWriter.prototype, Symbol.toStringTag, - { value: "WritableStreamDefaultWriter", - configurable: true }); - - var transformState = new WeakMap(); - var transformControllerState = new WeakMap(); - - function TransformStreamDefaultController() { - throw new TypeError("Illegal constructor"); - } - - Object.defineProperty(TransformStreamDefaultController.prototype, "desiredSize", { - configurable: true, - get: function() { - var state = transformControllerState.get(this); - if (!state) - throw new TypeError("TransformStreamDefaultController expected"); - return state.readableController.desiredSize; - } - }); - - TransformStreamDefaultController.prototype.enqueue = function(chunk) { - var state = transformControllerState.get(this); - if (!state) - throw new TypeError("TransformStreamDefaultController expected"); - state.readableController.enqueue(chunk); - }; - - TransformStreamDefaultController.prototype.error = function(reason) { - var state = transformControllerState.get(this); - if (!state) - throw new TypeError("TransformStreamDefaultController expected"); - state.readableController.error(reason); - writableError(state.stream.writable, reason); - }; - - TransformStreamDefaultController.prototype.terminate = function() { - var state = transformControllerState.get(this); - if (!state) - throw new TypeError("TransformStreamDefaultController expected"); - try { - state.readableController.close(); - } catch (e) {} - writableError(state.stream.writable, new TypeError("TransformStream terminated")); - }; - - Object.defineProperty(TransformStreamDefaultController.prototype, - Symbol.toStringTag, - { value: "TransformStreamDefaultController", - configurable: true }); - - function errorReadableController(controller, error) { - try { - controller.error(error); - } catch (e) {} - } - - function TransformStream(transformer, writableStrategy, readableStrategy) { - if (!(this instanceof TransformStream)) - throw new TypeError("TransformStream must be constructed with new"); - - transformer = transformer === undefined ? {} : requiredObject(transformer, "transformer"); - writableStrategy = writableStrategy === undefined ? {} : requiredObject(writableStrategy, "writableStrategy"); - readableStrategy = readableStrategy === undefined ? {} : requiredObject(readableStrategy, "readableStrategy"); - - if (transformer.readableType !== undefined) - throw new RangeError("Invalid readableType"); - if (transformer.writableType !== undefined) - throw new RangeError("Invalid writableType"); - - var controller = Object.create(TransformStreamDefaultController.prototype); - var readableController; - var stream = this; - var startAlgorithm = getMethod(transformer, "start"); - var transformAlgorithm = getMethod(transformer, "transform"); - var flushAlgorithm = getMethod(transformer, "flush"); - var cancelAlgorithm = getMethod(transformer, "cancel"); - - var readable = new ReadableStream({ - start: function(c) { - readableController = c; - transformControllerState.set(controller, { - stream: stream, - readableController: c - }); - }, - cancel: function(reason) { - if (cancelAlgorithm) - return cancelAlgorithm.call(transformer, reason); - return undefined; - } - }, readableStrategy); - - var startPromise = startAlgorithm - ? promiseCall(startAlgorithm, transformer, [controller]) - : Promise.resolve(undefined); - startPromise = startPromise.then(undefined, function(error) { - if (readableController) - errorReadableController(readableController, error); - throw error; - }); - - var writable = new WritableStream({ - start: function() { - return startPromise; - }, - write: function(chunk) { - var result; - try { - if (transformAlgorithm) { - result = transformAlgorithm.call(transformer, chunk, controller); - } else { - controller.enqueue(chunk); - result = undefined; - } - } catch (error) { - errorReadableController(readableController, error); - throw error; - } - return Promise.resolve(result).then(undefined, function(error) { - errorReadableController(readableController, error); - throw error; - }); - }, - close: function() { - var result = flushAlgorithm - ? promiseCall(flushAlgorithm, transformer, [controller]) - : Promise.resolve(undefined); - return result.then(function() { - readableController.close(); - }, function(error) { - errorReadableController(readableController, error); - throw error; - }); - }, - abort: function(reason) { - readableController.error(reason); - } - }, writableStrategy); - - transformState.set(this, { - readable: readable, - writable: writable, - controller: controller - }); - } - - Object.defineProperty(TransformStream.prototype, "readable", { - configurable: true, - get: function() { - var state = transformState.get(this); - if (!state) - throw new TypeError("TransformStream expected"); - return state.readable; - } - }); - - Object.defineProperty(TransformStream.prototype, "writable", { - configurable: true, - get: function() { - var state = transformState.get(this); - if (!state) - throw new TypeError("TransformStream expected"); - return state.writable; - } - }); - - Object.defineProperty(TransformStream.prototype, Symbol.toStringTag, - { value: "TransformStream", configurable: true }); - - function isReadableStreamObject(value) { - if (!isObject(value) || !global.ReadableStream) - return false; - try { - return value instanceof global.ReadableStream; - } catch (e) { - return false; - } - } - - function isUncloneableStreamChunk(value) { - return isObject(value) && - (isWritableStream(value) || - isReadableStreamObject(value) || - transformState.has(value)); - } - - function makeDataCloneError() { - return makeDOMException("The object could not be cloned.", "DataCloneError"); - } - - function cloneTransferReasonError(value) { - var constructors = [ - global.EvalError, - global.RangeError, - global.ReferenceError, - global.SyntaxError, - global.TypeError, - global.URIError, - global.Error - ]; - - for (var i = 0; i < constructors.length; ++i) { - var C = constructors[i]; - if (typeof C !== "function") - continue; - try { - if (!(value instanceof C)) - continue; - } catch (e) { - continue; - } - - var message = ""; - var descriptor; - try { - descriptor = Object.getOwnPropertyDescriptor(value, "message"); - } catch (e) { - descriptor = undefined; - } - if (descriptor && hasOwn.call(descriptor, "value")) - message = String(descriptor.value); - return new C(message); - } - - return undefined; - } - - function cloneTransferReasonValue(value, memory) { - if (typeof value === "function" || typeof value === "symbol") - throw makeDataCloneError(); - if (!isObject(value)) - return value; - if (isUncloneableStreamChunk(value)) - throw makeDataCloneError(); - - memory = memory || new WeakMap(); - if (memory.has(value)) - return memory.get(value); - - if (typeof global.DOMException === "function") { - try { - if (value instanceof global.DOMException) { - return new global.DOMException(String(value.message), - String(value.name)); - } - } catch (e) {} - } - - var errorClone = cloneTransferReasonError(value); - if (errorClone !== undefined) - return errorClone; - - if (typeof global.ArrayBuffer === "function") { - try { - if (value instanceof global.ArrayBuffer) { - var bufferClone = value.slice(0); - memory.set(value, bufferClone); - return bufferClone; - } - } catch (e) {} - } - - if (global.ArrayBuffer && global.ArrayBuffer.isView && - global.ArrayBuffer.isView(value)) { - var clonedBuffer = cloneTransferReasonValue(value.buffer, memory); - var viewClone; - if (objectToString.call(value) === "[object DataView]") { - viewClone = new global.DataView(clonedBuffer, value.byteOffset, - value.byteLength); - } else { - viewClone = new value.constructor(clonedBuffer, value.byteOffset, - value.length); - } - memory.set(value, viewClone); - return viewClone; - } - - if (typeof global.Date === "function") { - try { - if (value instanceof global.Date) { - var dateClone = new global.Date(value.getTime()); - memory.set(value, dateClone); - return dateClone; - } - } catch (e) {} - } - - if (typeof global.RegExp === "function") { - try { - if (value instanceof global.RegExp) { - var flags = ""; - flags += value.global ? "g" : ""; - flags += value.ignoreCase ? "i" : ""; - flags += value.multiline ? "m" : ""; - flags += value.unicode ? "u" : ""; - flags += value.sticky ? "y" : ""; - var regexpClone = new global.RegExp(value.source, flags); - regexpClone.lastIndex = value.lastIndex; - memory.set(value, regexpClone); - return regexpClone; - } - } catch (e) {} - } - - if (typeof global.Map === "function") { - try { - if (value instanceof global.Map) { - var mapClone = new global.Map(); - memory.set(value, mapClone); - value.forEach(function(v, k) { - mapClone.set(cloneTransferReasonValue(k, memory), - cloneTransferReasonValue(v, memory)); - }); - return mapClone; - } - } catch (e) { - throw e; - } - } - - if (typeof global.Set === "function") { - try { - if (value instanceof global.Set) { - var setClone = new global.Set(); - memory.set(value, setClone); - value.forEach(function(v) { - setClone.add(cloneTransferReasonValue(v, memory)); - }); - return setClone; - } - } catch (e) { - throw e; - } - } - - var clone = Array.isArray(value) ? [] : {}; - memory.set(value, clone); - - var keys = Object.keys(value); - for (var i = 0; i < keys.length; ++i) { - var key = keys[i]; - clone[key] = cloneTransferReasonValue(value[key], memory); - } - - return clone; - } - - function abortTransferredWritable(record, reason) { - try { - return record.writer.abort(reason); - } catch (e) { - return Promise.reject(e); - } - } - - function rejectTransferredWritableWrite(record, error) { - var abortPromise = abortTransferredWritable(record, error); - silenceRejection(abortPromise); - return Promise.reject(error); - } - - function forwardTransferredWritableWrite(record, chunk) { - if (isUncloneableStreamChunk(chunk)) - return rejectTransferredWritableWrite(record, makeDataCloneError()); - - var prior = record.tail || Promise.resolve(undefined); - var firstWrite = !record.started; - record.started = true; - - var forwarding = prior.then(function() { - var writePromise; - try { - writePromise = Promise.resolve(record.writer.write(chunk)); - } catch (e) { - writePromise = Promise.reject(e); - } - record.inFlight = writePromise; - silenceRejection(writePromise); - return writePromise; - }); - - record.tail = forwarding; - silenceRejection(forwarding); - - if (firstWrite) - return undefined; - - return prior.then(function() { return undefined; }); - } - - function closeTransferredWritable(record) { - var tail = record.tail || Promise.resolve(undefined); - var closePromise = tail.then(function() { - return record.writer.close(); - }); - record.tail = closePromise; - silenceRejection(closePromise); - return closePromise; - } - -)JS" -R"JS( - - function __uxpTransferWritableStream(stream) { - if (!isWritableStream(stream)) - return undefined; - if (stream.locked) - return null; - try { - return { - writer: stream.getWriter(), - started: false, - inFlight: undefined, - tail: undefined - }; - } catch (e) { - return null; - } - } - - function __uxpReceiveWritableStreamTransfer(record) { - return new WritableStream({ - write: function(chunk) { - return forwardTransferredWritableWrite(record, chunk); - }, - close: function() { - return closeTransferredWritable(record); - }, - abort: function(reason) { - return abortTransferredWritable(record, reason); - } - }); - } - - function __uxpTransferReadableStream(stream) { - if (!isReadableStreamObject(stream)) - return undefined; - if (stream.locked) - return null; - try { - var record = { - reader: stream.getReader(), - pendingRead: undefined, - pumping: undefined, - closed: false, - errored: false, - canceled: false - }; - ensureReadableTransferRead(record); - return record; - } catch (e) { - return null; - } - } - - function ensureReadableTransferRead(record) { - if (!record.pendingRead && !record.closed && !record.errored && - !record.canceled) { - try { - record.pendingRead = Promise.resolve(record.reader.read()); - } catch (e) { - record.pendingRead = Promise.reject(e); - } - silenceRejection(record.pendingRead); - } - return record.pendingRead; - } - - function errorReadableTransfer(record, controller, error) { - if (record.canceled || record.closed || record.errored) - return; - record.errored = true; - try { controller.error(error); } catch (e) {} - } - - function pumpReadableTransfer(record, controller) { - if (record.pumping || record.closed || record.errored || record.canceled) - return; - - var pendingRead = ensureReadableTransferRead(record); - if (!pendingRead) - return; - - record.pumping = pendingRead.then(function(result) { - record.pendingRead = undefined; - record.pumping = undefined; - - if (record.canceled || record.errored || record.closed) - return; - - if (result.done) { - record.closed = true; - try { controller.close(); } catch (e) {} - return; - } - - if (isUncloneableStreamChunk(result.value)) { - var cloneError = makeDataCloneError(); - silenceRejection(record.reader.cancel(cloneError)); - errorReadableTransfer(record, controller, cloneError); - return; - } - - try { - controller.enqueue(result.value); - } catch (e) { - silenceRejection(record.reader.cancel(e)); - errorReadableTransfer(record, controller, e); - return; - } - - if (controller.desiredSize > 0) - pumpReadableTransfer(record, controller); - }, function(error) { - record.pendingRead = undefined; - record.pumping = undefined; - errorReadableTransfer(record, controller, error); - }); - silenceRejection(record.pumping); - } - - function cancelReadableTransfer(record, reason) { - record.canceled = true; - var clonedReason; - try { - clonedReason = cloneTransferReasonValue(reason); - } catch (e) { - return Promise.reject(e); - } - - Promise.resolve().then(function() { - try { - silenceRejection(record.reader.cancel(clonedReason)); - } catch (e) {} - }); - return undefined; - } - - function closeReadableTransferPort(port) { - try { port.close(); } catch (e) {} - } - - function startReadableTransferPort(port) { - try { - if (port.start) - port.start(); - } catch (e) {} - } - - function tryPostReadableTransferPort(port, message) { - try { - port.postMessage(message); - return true; - } catch (e) { - return false; - } - } - -)JS" -R"JS( - - function postReadableTransferPortError(record, error) { - var posted = tryPostReadableTransferPort(record.port, - { type: "error", value: error }); - if (!posted) { - posted = tryPostReadableTransferPort(record.port, { - type: "error", - name: error && error.name, - message: error && error.message - }); - } - record.closed = true; - if (!posted) - closeReadableTransferPort(record.port); - } - -)JS" -R"JS( - - function requestReadableTransferPortChunk(state) { - if (state.closed || state.errored || state.canceled) - return; - if (!tryPostReadableTransferPort(state.port, { type: "pull" })) { - state.errored = true; - if (state.controller) - try { state.controller.error(makeDataCloneError()); } catch (e) {} - closeReadableTransferPort(state.port); - } - } - - function errorReadableTransferPortState(state, error) { - if (state.errored) - return; - state.errored = true; - try { - if (state.controller) - state.controller.error(error); - } catch (e) {} - closeReadableTransferPort(state.port); - } - - function pumpReadableTransferPort(record) { - if (record.reading || record.closed || record.canceled || - record.credits <= 0) - return; - - --record.credits; - record.reading = true; - - var readPromise; - try { - readPromise = Promise.resolve(record.reader.read()); - } catch (e) { - readPromise = Promise.reject(e); - } - silenceRejection(readPromise); - - readPromise.then(function(result) { - record.reading = false; - - if (record.canceled || record.closed) - return; - - if (result.done) { - record.closed = true; - if (!tryPostReadableTransferPort(record.port, { type: "close" })) - closeReadableTransferPort(record.port); - return; - } - - if (isUncloneableStreamChunk(result.value)) { - var cloneError = makeDataCloneError(); - silenceRejection(record.reader.cancel(cloneError)); - postReadableTransferPortError(record, cloneError); - return; - } - - if (!tryPostReadableTransferPort(record.port, - { type: "chunk", value: result.value })) { - record.closed = true; - closeReadableTransferPort(record.port); - return; - } - - pumpReadableTransferPort(record); - }, function(error) { - record.reading = false; - if (record.canceled || record.closed) - return; - postReadableTransferPortError(record, error); - }); - } - - function __uxpTransferReadableStreamPort(stream) { - -)JS" -R"JS( - if (!isReadableStreamObject(stream)) - return undefined; - if (stream.locked || typeof global.MessageChannel !== "function") - return null; - - var channel; - try { - channel = new global.MessageChannel(); - var record = { - reader: stream.getReader(), - port: channel.port1, - reading: false, - credits: 1, - closed: false, - canceled: false - }; - - record.port.onmessage = function(event) { - var message = event.data; - if (!message || record.canceled) - return; - - if (message.type === "closed") { - record.closed = true; - closeReadableTransferPort(record.port); - return; - } - - if (record.closed) - return; - - if (message.type === "pull") { - ++record.credits; - pumpReadableTransferPort(record); - return; - } - - if (message.type === "cancel") { - record.canceled = true; - Promise.resolve().then(function() { - try { - silenceRejection(record.reader.cancel(message.reason)); - } catch (e) {} - }); - closeReadableTransferPort(record.port); - } - }; - - startReadableTransferPort(record.port); - pumpReadableTransferPort(record); - return channel.port2; - } catch (e) { - if (channel) { - closeReadableTransferPort(channel.port1); - closeReadableTransferPort(channel.port2); - } - return null; - } - } - - function errorFromReadableTransferPortMessage(message) { - if ("value" in message) - return message.value; - return makeDOMException(message.message || "ReadableStream transfer failed", - message.name || "DataCloneError"); - } - - function __uxpReceiveReadableStreamTransferFromPort(port) { - var state = { - port: port, - controller: undefined, - closed: false, - errored: false, - canceled: false - }; - - port.onmessage = function(event) { - var message = event.data; - if (!message || state.closed || state.errored || state.canceled) - return; - - if (message.type === "chunk") { - if (isUncloneableStreamChunk(message.value)) { - errorReadableTransferPortState(state, makeDataCloneError()); - return; - } - - try { - state.controller.enqueue(message.value); - } catch (e) { - errorReadableTransferPortState(state, e); - return; - } - - if (state.controller.desiredSize > 0) - requestReadableTransferPortChunk(state); - return; - } - - if (message.type === "close") { - state.closed = true; - try { state.controller.close(); } catch (e) {} - tryPostReadableTransferPort(port, { type: "closed" }); - closeReadableTransferPort(port); - return; - } - - if (message.type === "error") { - if (!state.errored) { - state.errored = true; - try { - if (state.controller) - state.controller.error( - errorFromReadableTransferPortMessage(message)); - } catch (e) {} - } - tryPostReadableTransferPort(port, { type: "closed" }); - closeReadableTransferPort(port); - } - }; - - return new ReadableStream({ - start: function(controller) { - state.controller = controller; - startReadableTransferPort(port); - requestReadableTransferPortChunk(state); - }, - pull: function() { - requestReadableTransferPortChunk(state); - }, - cancel: function(reason) { - state.canceled = true; - try { - port.postMessage({ type: "cancel", reason: reason }); - } catch (e) { - closeReadableTransferPort(port); - return Promise.reject(e); - } - closeReadableTransferPort(port); - return undefined; - } - }); - } - - function __uxpTransferTransformStream(stream) { - if (!isObject(stream) || !transformState.has(stream)) - return undefined; - - var state = transformState.get(stream); - if (state.readable.locked || state.writable.locked) - return null; - - var readableRecord = __uxpTransferReadableStream(state.readable); - if (!readableRecord) - return null; - - var writableRecord = __uxpTransferWritableStream(state.writable); - if (!writableRecord) - return null; - - return { - readable: readableRecord, - writable: writableRecord - }; - } - - function __uxpReceiveTransformStreamTransfer(record) { - var stream = Object.create(global.TransformStream.prototype); - transformState.set(stream, { - readable: __uxpReceiveReadableStreamTransfer(record.readable), - writable: __uxpReceiveWritableStreamTransfer(record.writable), - controller: undefined - }); - return stream; - } - - function __uxpReceiveReadableStreamTransfer(record) { - return new ReadableStream({ - start: function(controller) { - pumpReadableTransfer(record, controller); - }, - pull: function(controller) { - pumpReadableTransfer(record, controller); - }, - cancel: function(reason) { - return cancelReadableTransfer(record, reason); - } - }); - } - - function pipeTo(readable, destination, options) { - options = options === undefined ? {} : requiredObject(options, "options"); - var signal = options.signal; - var preventClose = Boolean(options.preventClose); - var preventAbort = Boolean(options.preventAbort); - var preventCancel = Boolean(options.preventCancel); - var reader; - var writer; - - try { - destination = requiredObject(destination, "destination"); - reader = readable.getReader(); - writer = destination.getWriter(); - } catch (e) { - return rejectPromise(e); - } - - var closed = false; - function cleanup() { - if (closed) - return; - closed = true; - releaseReaderLock(reader); - releaseWriterLock(writer); - if (signal && signal.removeEventListener) - signal.removeEventListener("abort", onAbort); - } - - function abortReason() { - return signal && "reason" in signal - ? signal.reason - : makeDOMException("The operation was aborted.", "AbortError"); - } - - function shutdownWithAction(action, originalError) { - return action().then(function() { - cleanup(); - throw originalError; - }, function(actionError) { - cleanup(); - throw actionError; - }); - } - - function onAbort() {} - - var pipePromise = new Promise(function(resolve, reject) { - onAbort = function() { - var reason = abortReason(); - var actions = []; - if (!preventAbort) - actions.push(writer.abort(reason)); - if (!preventCancel) - actions.push(reader.cancel(reason)); - Promise.all(actions).then(function() { - cleanup(); - reject(reason); - }, function(error) { - cleanup(); - reject(error); - }); - }; - - if (signal && signal.aborted) { - onAbort(); - return; - } - if (signal && signal.addEventListener) - signal.addEventListener("abort", onAbort); - - function pump() { - if (closed) - return; - reader.read().then(function(result) { - if (closed) - return; - if (result.done) { - var closePromise = preventClose ? Promise.resolve(undefined) - : writer.close(); - closePromise.then(function() { - cleanup(); - resolve(undefined); - }, function(error) { - cleanup(); - reject(error); - }); - return; - } - - writer.write(result.value).then(pump, function(error) { - if (closed) - return; - var cancel = preventCancel - ? Promise.resolve(undefined) - : reader.cancel(error); - cancel.then(function() { - cleanup(); - reject(error); - }, function(cancelError) { - cleanup(); - reject(cancelError); - }); - }); - }, function(error) { - if (closed) - return; - var abort = preventAbort - ? Promise.resolve(undefined) - : writer.abort(error); - abort.then(function() { - cleanup(); - reject(error); - }, function(abortError) { - cleanup(); - reject(abortError); - }); - }); - } - - pump(); - }); - - return pipePromise; - } - - function pipeThrough(readable, pair, options) { - pair = requiredObject(pair, "transform"); - var writable = pair.writable; - var output = pair.readable; - if (readable.locked) - throw new TypeError("ReadableStream is locked"); - if (!isWritableStream(writable)) - throw new TypeError("transform.writable must be a WritableStream"); - if (!(output instanceof global.ReadableStream)) - throw new TypeError("transform.readable must be a ReadableStream"); - if (writable.locked) - throw new TypeError("WritableStream is locked"); - readable.pipeTo(writable, options).catch(function() {}); - return output; - } - - Object.defineProperty(global, "__uxpStreamsPipeTo", - { value: pipeTo, configurable: true }); - Object.defineProperty(global, "__uxpStreamsPipeThrough", - { value: pipeThrough, configurable: true }); - Object.defineProperty(global, "__uxpTransferWritableStream", - { value: __uxpTransferWritableStream, - configurable: true }); - Object.defineProperty(global, "__uxpReceiveWritableStreamTransfer", - { value: __uxpReceiveWritableStreamTransfer, - configurable: true }); - Object.defineProperty(global, "__uxpTransferReadableStream", - { value: __uxpTransferReadableStream, - configurable: true }); - Object.defineProperty(global, "__uxpReceiveReadableStreamTransfer", - { value: __uxpReceiveReadableStreamTransfer, - configurable: true }); - Object.defineProperty(global, "__uxpTransferReadableStreamPort", - { value: __uxpTransferReadableStreamPort, - configurable: true }); - Object.defineProperty(global, "__uxpReceiveReadableStreamTransferFromPort", - { value: __uxpReceiveReadableStreamTransferFromPort, - configurable: true }); - Object.defineProperty(global, "__uxpTransferTransformStream", - { value: __uxpTransferTransformStream, - configurable: true }); - Object.defineProperty(global, "__uxpReceiveTransformStreamTransfer", - { value: __uxpReceiveTransformStreamTransfer, - configurable: true }); - - if (global.ReadableStream && !global.ReadableStream.from) { - Object.defineProperty(global.ReadableStream, "from", { - value: function from(asyncIterable) { - if (asyncIterable == null) - throw new TypeError("ReadableStream.from requires an iterable"); - var method = asyncIterable[Symbol.asyncIterator] || - asyncIterable[Symbol.iterator]; - if (typeof method !== "function") - throw new TypeError("ReadableStream.from requires an iterable"); - var iterator = method.call(asyncIterable); - return new ReadableStream({ - pull: function(controller) { - return Promise.resolve(iterator.next()).then(function(result) { - if (!isObject(result)) - throw new TypeError("Iterator result is not an object"); - if (result.done) { - controller.close(); - } else { - controller.enqueue(result.value); - } - }); - }, - cancel: function(reason) { - var returnMethod = iterator.return; - if (returnMethod) - return returnMethod.call(iterator, reason); - return undefined; - } - }); - }, - writable: true, - configurable: true - }); - } - - if (global.ReadableStream && typeof Symbol === "function" && - Symbol.asyncIterator && !global.ReadableStream.prototype.values) { - function ReadableStreamAsyncIterator(stream, preventCancel) { - this._reader = stream.getReader(); - this._preventCancel = preventCancel; - this._done = false; - } - - ReadableStreamAsyncIterator.prototype.next = function() { - if (this._done) - return Promise.resolve({ value: undefined, done: true }); - var self = this; - return this._reader.read().then(function(result) { - if (result.done) { - self._done = true; - releaseReaderLock(self._reader); - } - return result; - }, function(error) { - self._done = true; - releaseReaderLock(self._reader); - throw error; - }); - }; - - ReadableStreamAsyncIterator.prototype.return = function(value) { - if (this._done) - return Promise.resolve({ value: value, done: true }); - this._done = true; - var reader = this._reader; - if (this._preventCancel) { - releaseReaderLock(reader); - return Promise.resolve({ value: value, done: true }); - } - return reader.cancel(value).then(function() { - releaseReaderLock(reader); - return { value: value, done: true }; - }, function(error) { - releaseReaderLock(reader); - throw error; - }); - }; - - ReadableStreamAsyncIterator.prototype[Symbol.asyncIterator] = function() { - return this; - }; - - Object.defineProperty(global.ReadableStream.prototype, "values", { - value: function values(options) { - var preventCancel = Boolean(options && options.preventCancel); - return new ReadableStreamAsyncIterator(this, preventCancel); - }, - writable: true, - configurable: true - }); - - Object.defineProperty(global.ReadableStream.prototype, Symbol.asyncIterator, { - value: global.ReadableStream.prototype.values, - writable: true, - configurable: true - }); - } - - )JS" - R"JS( - - var textEncoderStreamState = new WeakMap(); - var textDecoderStreamState = new WeakMap(); - - function enqueueEncoded(controller, encoder, string) { - if (string.length === 0) - return; - var chunk = encoder.encode(string); - if (chunk.byteLength) - controller.enqueue(chunk); - } - - function TextEncoderStream() { - if (!(this instanceof TextEncoderStream)) - throw new TypeError("TextEncoderStream must be constructed with new"); - - var encoder = new TextEncoder(); - var leadingSurrogate = null; - var transform = new TransformStream({ - transform: function(chunk, controller) { - var input = String(chunk); - var output = ""; - var i = 0; - - if (leadingSurrogate !== null) { - if (input.length > 0) { - var first = input.charCodeAt(0); - if (first >= 0xDC00 && first <= 0xDFFF) { - output += String.fromCharCode(leadingSurrogate) + input.charAt(0); - i = 1; - } else { - output += "\uFFFD"; - } - } else { - return; - } - leadingSurrogate = null; - } - - for (; i < input.length; ++i) { - var code = input.charCodeAt(i); - if (code >= 0xD800 && code <= 0xDBFF) { - if (i + 1 < input.length) { - var next = input.charCodeAt(i + 1); - if (next >= 0xDC00 && next <= 0xDFFF) { - output += input.charAt(i) + input.charAt(i + 1); - ++i; - } else { - output += "\uFFFD"; - } - } else { - leadingSurrogate = code; - break; - } - } else if (code >= 0xDC00 && code <= 0xDFFF) { - output += "\uFFFD"; - } else { - output += input.charAt(i); - } - } - - enqueueEncoded(controller, encoder, output); - }, - flush: function(controller) { - if (leadingSurrogate !== null) { - leadingSurrogate = null; - enqueueEncoded(controller, encoder, "\uFFFD"); - } - } - }); - - textEncoderStreamState.set(this, { transform: transform }); - } - - Object.defineProperty(TextEncoderStream.prototype, "encoding", { - configurable: true, - get: function() { - if (!textEncoderStreamState.has(this)) - throw new TypeError("TextEncoderStream expected"); - return "utf-8"; - } - }); - - Object.defineProperty(TextEncoderStream.prototype, "readable", { - configurable: true, - get: function() { - var state = textEncoderStreamState.get(this); - if (!state) - throw new TypeError("TextEncoderStream expected"); - return state.transform.readable; - } - }); - - Object.defineProperty(TextEncoderStream.prototype, "writable", { - configurable: true, - get: function() { - var state = textEncoderStreamState.get(this); - if (!state) - throw new TypeError("TextEncoderStream expected"); - return state.transform.writable; - } - }); - - Object.defineProperty(TextEncoderStream.prototype, Symbol.toStringTag, - { value: "TextEncoderStream", configurable: true }); - - function TextDecoderStream(label, options) { - if (!(this instanceof TextDecoderStream)) - throw new TypeError("TextDecoderStream must be constructed with new"); - label = label === undefined ? "utf-8" : label; - options = options === undefined ? {} : options; - - var decoder = new TextDecoder(label, options); - var transform = new TransformStream({ - transform: function(chunk, controller) { - var output = decoder.decode(chunk, { stream: true }); - if (output.length) - controller.enqueue(output); - }, - flush: function(controller) { - var output = decoder.decode(); - if (output.length) - controller.enqueue(output); - } - }); - - textDecoderStreamState.set(this, { - transform: transform, - encoding: decoder.encoding, - fatal: decoder.fatal, - ignoreBOM: Boolean(options && options.ignoreBOM) - }); - } - - Object.defineProperty(TextDecoderStream.prototype, "encoding", { - configurable: true, - get: function() { - var state = textDecoderStreamState.get(this); - if (!state) - throw new TypeError("TextDecoderStream expected"); - return state.encoding; - } - }); - - Object.defineProperty(TextDecoderStream.prototype, "fatal", { - configurable: true, - get: function() { - var state = textDecoderStreamState.get(this); - if (!state) - throw new TypeError("TextDecoderStream expected"); - return state.fatal; - } - }); - - Object.defineProperty(TextDecoderStream.prototype, "ignoreBOM", { - configurable: true, - get: function() { - var state = textDecoderStreamState.get(this); - if (!state) - throw new TypeError("TextDecoderStream expected"); - return state.ignoreBOM; - } - }); - - Object.defineProperty(TextDecoderStream.prototype, "readable", { - configurable: true, - get: function() { - var state = textDecoderStreamState.get(this); - if (!state) - throw new TypeError("TextDecoderStream expected"); - return state.transform.readable; - } - }); - - Object.defineProperty(TextDecoderStream.prototype, "writable", { - configurable: true, - get: function() { - var state = textDecoderStreamState.get(this); - if (!state) - throw new TypeError("TextDecoderStream expected"); - return state.transform.writable; - } - }); - - Object.defineProperty(TextDecoderStream.prototype, Symbol.toStringTag, - { value: "TextDecoderStream", configurable: true }); - - var compressionStreamState = new WeakMap(); - var decompressionStreamState = new WeakMap(); - - function enqueueCompressionChunks(nativeContext, chunk, finish, controller) { - var chunks = global.__uxpCompressionProcess(nativeContext, chunk, finish); - for (var i = 0; i < chunks.length; ++i) - controller.enqueue(chunks[i]); - } - - function CompressionStream(format) { - if (!(this instanceof CompressionStream)) - throw new TypeError("CompressionStream must be constructed with new"); - var nativeContext = global.__uxpCreateCompressionContext(format, true); - var transform = new TransformStream({ - transform: function(chunk, controller) { - enqueueCompressionChunks(nativeContext, chunk, false, controller); - }, - flush: function(controller) { - enqueueCompressionChunks(nativeContext, undefined, true, controller); - } - }); - compressionStreamState.set(this, { transform: transform }); - } - - Object.defineProperty(CompressionStream.prototype, "readable", { - configurable: true, - get: function() { - var state = compressionStreamState.get(this); - if (!state) - throw new TypeError("CompressionStream expected"); - return state.transform.readable; - } - }); - - Object.defineProperty(CompressionStream.prototype, "writable", { - configurable: true, - get: function() { - var state = compressionStreamState.get(this); - if (!state) - throw new TypeError("CompressionStream expected"); - return state.transform.writable; - } - }); - - Object.defineProperty(CompressionStream.prototype, Symbol.toStringTag, - { value: "CompressionStream", configurable: true }); - - function DecompressionStream(format) { - if (!(this instanceof DecompressionStream)) - throw new TypeError("DecompressionStream must be constructed with new"); - var nativeContext = global.__uxpCreateCompressionContext(format, false); - var transform = new TransformStream({ - transform: function(chunk, controller) { - enqueueCompressionChunks(nativeContext, chunk, false, controller); - }, - flush: function(controller) { - enqueueCompressionChunks(nativeContext, undefined, true, controller); - } - }); - decompressionStreamState.set(this, { transform: transform }); - } - - Object.defineProperty(DecompressionStream.prototype, "readable", { - configurable: true, - get: function() { - var state = decompressionStreamState.get(this); - if (!state) - throw new TypeError("DecompressionStream expected"); - return state.transform.readable; - } - }); - - Object.defineProperty(DecompressionStream.prototype, "writable", { - configurable: true, - get: function() { - var state = decompressionStreamState.get(this); - if (!state) - throw new TypeError("DecompressionStream expected"); - return state.transform.writable; - } - }); - - Object.defineProperty(DecompressionStream.prototype, Symbol.toStringTag, - { value: "DecompressionStream", configurable: true }); - - define("WritableStream", WritableStream); - define("WritableStreamDefaultWriter", WritableStreamDefaultWriter); - define("WritableStreamDefaultController", WritableStreamDefaultController); - define("TransformStream", TransformStream); - define("TransformStreamDefaultController", TransformStreamDefaultController); - define("TextEncoderStream", TextEncoderStream); - define("TextDecoderStream", TextDecoderStream); - define("CompressionStream", CompressionStream); - define("DecompressionStream", DecompressionStream); -})(this); -)JS"; - - RootedValue rval(cx); - JS::CompileOptions options(cx); - options.setFileAndLine("builtin/StreamExtras.js", 1); - options.setNoScriptRval(true); - return JS::Evaluate(cx, options, source, strlen(source), &rval); -} diff --git a/js/src/builtin/Stream.h b/js/src/builtin/Stream.h index 50bd7a52a1..0726e78361 100644 --- a/js/src/builtin/Stream.h +++ b/js/src/builtin/Stream.h @@ -165,8 +165,6 @@ class CountQueuingStrategy : public NativeObject static const Class protoClass_; }; -[[nodiscard]] bool InitStreamExtras(JSContext* cx, HandleObject global); - } // namespace js #endif /* builtin_Stream_h */ diff --git a/js/src/builtin/String.js b/js/src/builtin/String.js index a83a06ad2b..e1c32482ae 100644 --- a/js/src/builtin/String.js +++ b/js/src/builtin/String.js @@ -654,82 +654,6 @@ function String_repeat(count) { return T; } -// ES2024 -// String.prototype.isWellFormed ( ) -function String_isWellFormed() { - // Steps 1-2. - RequireObjectCoercible(this); - var S = ToString(this); - - // Step 3. - var length = S.length; - for (var k = 0; k < length; k++) { - var c = callFunction(std_String_charCodeAt, S, k); - if (c >= 0xD800 && c <= 0xDBFF) { - if (k + 1 >= length) - return false; - - var d = callFunction(std_String_charCodeAt, S, k + 1); - if (d < 0xDC00 || d > 0xDFFF) - return false; - - k++; - } else if (c >= 0xDC00 && c <= 0xDFFF) { - return false; - } - } - - // Step 4. - return true; -} - -// ES2024 -// String.prototype.toWellFormed ( ) -function String_toWellFormed() { - // Steps 1-2. - RequireObjectCoercible(this); - var S = ToString(this); - - // Step 3. - var length = S.length; - var result = ""; - var copied = 0; - - for (var k = 0; k < length; k++) { - var c = callFunction(std_String_charCodeAt, S, k); - var isUnpairedSurrogate = false; - - if (c >= 0xD800 && c <= 0xDBFF) { - if (k + 1 < length) { - var d = callFunction(std_String_charCodeAt, S, k + 1); - if (d >= 0xDC00 && d <= 0xDFFF) { - k++; - continue; - } - } - isUnpairedSurrogate = true; - } else if (c >= 0xDC00 && c <= 0xDFFF) { - isUnpairedSurrogate = true; - } - - if (isUnpairedSurrogate) { - if (copied < k) - result += callFunction(String_substring, S, copied, k); - result += "\uFFFD"; - copied = k + 1; - } - } - - if (copied === 0) - return S; - - if (copied < length) - result += callFunction(String_substring, S, copied, length); - - // Step 4. - return result; -} - // ES6 draft specification, section 21.1.3.27, version 2013-09-27. function String_iterator() { RequireObjectCoercible(this); diff --git a/js/src/builtin/TypedArray.js b/js/src/builtin/TypedArray.js index 4311f27079..c831b74614 100644 --- a/js/src/builtin/TypedArray.js +++ b/js/src/builtin/TypedArray.js @@ -37,25 +37,10 @@ function TypedArrayLengthMethod() { return TypedArrayLength(this); } -function TypedArrayContentTypeIsBigIntMethod() { - return IsBigInt64TypedArray(this) || IsBigUint64TypedArray(this); -} - -function ThrowIfTypedArrayOutOfBounds(tarray) { - if (TypedArrayIsOutOfBounds(tarray)) - ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); -} - -function ThrowIfPossiblyWrappedTypedArrayOutOfBounds(tarray) { - if (PossiblyWrappedTypedArrayIsOutOfBounds(tarray)) - ThrowTypeError(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); -} - function GetAttachedArrayBuffer(tarray) { var buffer = ViewedArrayBufferIfReified(tarray); if (IsDetachedBuffer(buffer)) ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - ThrowIfTypedArrayOutOfBounds(tarray); return buffer; } @@ -75,13 +60,6 @@ function IsTypedArrayEnsuringArrayBuffer(arg) { return true; } - if (IsObject(arg) && IsPossiblyWrappedTypedArray(arg)) { - if (PossiblyWrappedTypedArrayHasDetachedBuffer(arg)) - ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - ThrowIfPossiblyWrappedTypedArrayOutOfBounds(arg); - return false; - } - callFunction(CallTypedArrayMethodIfWrapped, arg, "GetAttachedArrayBufferMethod"); return false; } @@ -101,7 +79,6 @@ function ValidateTypedArray(obj, error) { if (IsPossiblyWrappedTypedArray(obj)) { if (PossiblyWrappedTypedArrayHasDetachedBuffer(obj)) ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - ThrowIfPossiblyWrappedTypedArrayOutOfBounds(obj); return false; } } @@ -1047,18 +1024,12 @@ function TypedArraySet(overloaded, offset = 0) { // Steps 9-10. var targetBuffer = GetAttachedArrayBuffer(target); - ThrowIfTypedArrayOutOfBounds(target); - // Step 11. var targetLength = TypedArrayLength(target); // Steps 12 et seq. - if (IsPossiblyWrappedTypedArray(overloaded)) { - if (PossiblyWrappedTypedArrayHasDetachedBuffer(overloaded)) - ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); - ThrowIfPossiblyWrappedTypedArrayOutOfBounds(overloaded); + if (IsPossiblyWrappedTypedArray(overloaded)) return SetFromTypedArray(target, overloaded, targetOffset, targetLength); - } return SetFromNonTypedArray(target, overloaded, targetOffset, targetLength, targetBuffer); } @@ -1395,8 +1366,6 @@ function TypedArraySubarray(begin, end) { "TypedArraySubarray"); } - GetAttachedArrayBuffer(obj); - // Steps 4-6. var buffer = TypedArrayBuffer(obj); var srcLength = TypedArrayLength(obj); @@ -1877,10 +1846,7 @@ function ArrayBufferSlice(start, end) { ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED); // Steps 19-21. - var currentLen = ArrayBufferByteLength(O); - var copyLen = first >= currentLen ? 0 : std_Math_min(newLen, currentLen - first); - if (copyLen > 0) - ArrayBufferCopyData(new_, 0, O, first | 0, copyLen | 0, isWrapped); + ArrayBufferCopyData(new_, 0, O, first | 0, newLen | 0, isWrapped); // Step 22. return new_; diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index d68b9e05fd..82b6ef1a7c 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -8,7 +8,6 @@ #include "jsapi.h" #include "jscntxt.h" -#include "builtin/WeakRefObject.h" #include "vm/SelfHosting.h" #include "vm/Interpreter-inl.h" @@ -22,80 +21,21 @@ IsWeakMap(HandleValue v) return v.isObject() && v.toObject().is(); } -struct WeakMapObject::Data -{ - ObjectValueMap objectMap; - SymbolValueMap symbolMap; - - Data(JSContext* cx, JSObject* owner) - : objectMap(cx, owner), - symbolMap(cx, owner) - {} - - bool init() { - return objectMap.init() && symbolMap.init(); - } -}; - -ObjectValueMap* -WeakMapObject::getMap() -{ - Data* data = getData(); - return data ? &data->objectMap : nullptr; -} - -SymbolValueMap* -WeakMapObject::getSymbolMap() -{ - Data* data = getData(); - return data ? &data->symbolMap : nullptr; -} - -static bool -EnsureWeakMapData(JSContext* cx, Handle mapObj) -{ - if (mapObj->getData()) - return true; - - auto data = cx->make_unique(cx, mapObj.get()); - if (!data) - return false; - - if (!data->init()) { - JS_ReportOutOfMemory(cx); - return false; - } - - mapObj->setPrivate(data.release()); - return true; -} - MOZ_ALWAYS_INLINE bool WeakMap_has_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!CanBeHeldWeakly(args.get(0))) { + if (!args.get(0).isObject()) { args.rval().setBoolean(false); return true; } - WeakMapObject& weakMap = args.thisv().toObject().as(); - if (args.get(0).isObject()) { - if (ObjectValueMap* map = weakMap.getMap()) { - JSObject* key = &args[0].toObject(); - if (map->has(key)) { - args.rval().setBoolean(true); - return true; - } - } - } else { - if (SymbolValueMap* map = weakMap.getSymbolMap()) { - JS::Symbol* key = args[0].toSymbol(); - if (map->has(key)) { - args.rval().setBoolean(true); - return true; - } + if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { + JSObject* key = &args[0].toObject(); + if (map->has(key)) { + args.rval().setBoolean(true); + return true; } } @@ -115,27 +55,16 @@ WeakMap_get_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!CanBeHeldWeakly(args.get(0))) { + if (!args.get(0).isObject()) { args.rval().setUndefined(); return true; } - WeakMapObject& weakMap = args.thisv().toObject().as(); - if (args.get(0).isObject()) { - if (ObjectValueMap* map = weakMap.getMap()) { - JSObject* key = &args[0].toObject(); - if (ObjectValueMap::Ptr ptr = map->lookup(key)) { - args.rval().set(ptr->value()); - return true; - } - } - } else { - if (SymbolValueMap* map = weakMap.getSymbolMap()) { - JS::Symbol* key = args[0].toSymbol(); - if (SymbolValueMap::Ptr ptr = map->lookup(key)) { - args.rval().set(ptr->value()); - return true; - } + if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { + JSObject* key = &args[0].toObject(); + if (ObjectValueMap::Ptr ptr = map->lookup(key)) { + args.rval().set(ptr->value()); + return true; } } @@ -155,29 +84,17 @@ WeakMap_delete_impl(JSContext* cx, const CallArgs& args) { MOZ_ASSERT(IsWeakMap(args.thisv())); - if (!CanBeHeldWeakly(args.get(0))) { + if (!args.get(0).isObject()) { args.rval().setBoolean(false); return true; } - WeakMapObject& weakMap = args.thisv().toObject().as(); - if (args.get(0).isObject()) { - if (ObjectValueMap* map = weakMap.getMap()) { - JSObject* key = &args[0].toObject(); - if (ObjectValueMap::Ptr ptr = map->lookup(key)) { - map->remove(ptr); - args.rval().setBoolean(true); - return true; - } - } - } else { - if (SymbolValueMap* map = weakMap.getSymbolMap()) { - JS::Symbol* key = args[0].toSymbol(); - if (SymbolValueMap::Ptr ptr = map->lookup(key)) { - map->remove(ptr); - args.rval().setBoolean(true); - return true; - } + if (ObjectValueMap* map = args.thisv().toObject().as().getMap()) { + JSObject* key = &args[0].toObject(); + if (ObjectValueMap::Ptr ptr = map->lookup(key)) { + map->remove(ptr); + args.rval().setBoolean(true); + return true; } } @@ -209,13 +126,22 @@ TryPreserveReflector(JSContext* cx, HandleObject obj) return true; } -static bool -SetWeakMapObjectEntryInternal(JSContext* cx, Handle mapObj, - HandleObject key, HandleValue value) +static MOZ_ALWAYS_INLINE bool +SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, + HandleObject key, HandleValue value) { - if (!EnsureWeakMapData(cx, mapObj)) - return false; ObjectValueMap* map = mapObj->getMap(); + if (!map) { + auto newMap = cx->make_unique(cx, mapObj.get()); + if (!newMap) + return false; + if (!newMap->init()) { + JS_ReportOutOfMemory(cx); + return false; + } + map = newMap.release(); + mapObj->setPrivate(map); + } // Preserve wrapped native keys to prevent wrapper optimization. if (!TryPreserveReflector(cx, key)) @@ -236,28 +162,13 @@ SetWeakMapObjectEntryInternal(JSContext* cx, Handle mapObj, return true; } -static bool -SetWeakMapSymbolEntryInternal(JSContext* cx, Handle mapObj, - Handle key, HandleValue value) +MOZ_ALWAYS_INLINE bool +WeakMap_set_impl(JSContext* cx, const CallArgs& args) { - if (!EnsureWeakMapData(cx, mapObj)) - return false; - SymbolValueMap* map = mapObj->getSymbolMap(); + MOZ_ASSERT(IsWeakMap(args.thisv())); - MOZ_ASSERT_IF(value.isObject(), value.toObject().compartment() == mapObj->compartment()); - if (!map->put(key, value)) { - JS_ReportOutOfMemory(cx); - return false; - } - return true; -} - -static MOZ_ALWAYS_INLINE bool -SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, - HandleValue key, HandleValue value) -{ - if (!CanBeHeldWeakly(key)) { - UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, key, nullptr); + if (!args.get(0).isObject()) { + UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr); if (!bytes) return false; JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, @@ -265,24 +176,11 @@ SetWeakMapEntryInternal(JSContext* cx, Handle mapObj, return false; } - if (key.isObject()) { - RootedObject objectKey(cx, &key.toObject()); - return SetWeakMapObjectEntryInternal(cx, mapObj, objectKey, value); - } - - Rooted symbolKey(cx, key.toSymbol()); - return SetWeakMapSymbolEntryInternal(cx, mapObj, symbolKey, value); -} - -MOZ_ALWAYS_INLINE bool -WeakMap_set_impl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsWeakMap(args.thisv())); - + RootedObject key(cx, &args[0].toObject()); Rooted thisObj(cx, &args.thisv().toObject()); Rooted map(cx, &thisObj->as()); - if (!SetWeakMapEntryInternal(cx, map, args.get(0), args.get(1))) + if (!SetWeakMapEntryInternal(cx, map, key, args.get(1))) return false; args.rval().set(args.thisv()); return true; @@ -295,13 +193,6 @@ js::WeakMap_set(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } -bool -js::SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val) -{ - Rooted rootedMap(cx, &mapObj->as()); - return SetWeakMapEntryInternal(cx, rootedMap, key, val); -} - JS_FRIEND_API(bool) JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHandleObject ret) { @@ -314,11 +205,11 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan RootedObject arr(cx, NewDenseEmptyArray(cx)); if (!arr) return false; - WeakMapObject::Data* data = obj->as().getData(); - if (data) { + ObjectValueMap* map = obj->as().getMap(); + if (map) { // Prevent GC from mutating the weakmap while iterating. AutoSuppressGC suppress(cx); - for (ObjectValueMap::Base::Range r = data->objectMap.all(); !r.empty(); r.popFront()) { + for (ObjectValueMap::Base::Range r = map->all(); !r.empty(); r.popFront()) { JS::ExposeObjectToActiveJS(r.front().key()); RootedObject key(cx, r.front().key()); if (!cx->compartment()->wrap(cx, &key)) @@ -326,14 +217,6 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan if (!NewbornArrayPush(cx, arr, ObjectValue(*key))) return false; } - for (SymbolValueMap::Base::Range r = data->symbolMap.all(); !r.empty(); r.popFront()) { - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(r.front().key().get())); - RootedValue key(cx, SymbolValue(r.front().key())); - if (!cx->compartment()->wrap(cx, &key)) - return false; - if (!NewbornArrayPush(cx, arr, key)) - return false; - } } ret.set(arr); return true; @@ -342,23 +225,21 @@ JS_NondeterministicGetWeakMapKeys(JSContext* cx, HandleObject objArg, MutableHan static void WeakMap_mark(JSTracer* trc, JSObject* obj) { - if (WeakMapObject::Data* data = obj->as().getData()) { - data->objectMap.trace(trc); - data->symbolMap.trace(trc); - } + if (ObjectValueMap* map = obj->as().getMap()) + map->trace(trc); } static void WeakMap_finalize(FreeOp* fop, JSObject* obj) { MOZ_ASSERT(fop->maybeOffMainThread()); - if (WeakMapObject::Data* data = obj->as().getData()) { + if (ObjectValueMap* map = obj->as().getMap()) { #ifdef DEBUG - data->~Data(); - memset(static_cast(data), 0xdc, sizeof(*data)); - fop->free_(data); + map->~ObjectValueMap(); + memset(static_cast(map), 0xdc, sizeof(*map)); + fop->free_(map); #else - fop->delete_(data); + fop->delete_(map); #endif } } @@ -401,8 +282,7 @@ JS::SetWeakMapEntry(JSContext* cx, HandleObject mapObj, HandleObject key, CHECK_REQUEST(cx); assertSameCompartment(cx, key, val); Rooted rootedMap(cx, &mapObj->as()); - RootedValue keyValue(cx, ObjectValue(*key)); - return SetWeakMapEntryInternal(cx, rootedMap, keyValue, val); + return SetWeakMapEntryInternal(cx, rootedMap, key, val); } static bool @@ -506,3 +386,4 @@ js::InitBareWeakMapCtor(JSContext* cx, HandleObject obj) { return InitWeakMapClass(cx, obj, false); } + diff --git a/js/src/builtin/WeakMapObject.h b/js/src/builtin/WeakMapObject.h index f19ad1d4df..507758d2fa 100644 --- a/js/src/builtin/WeakMapObject.h +++ b/js/src/builtin/WeakMapObject.h @@ -16,11 +16,7 @@ class WeakMapObject : public NativeObject public: static const Class class_; - struct Data; - - Data* getData() { return static_cast(getPrivate()); } - ObjectValueMap* getMap(); - SymbolValueMap* getSymbolMap(); + ObjectValueMap* getMap() { return static_cast(getPrivate()); } }; } // namespace js diff --git a/js/src/builtin/WeakRefObject.cpp b/js/src/builtin/WeakRefObject.cpp deleted file mode 100644 index 8e8feb3f3d..0000000000 --- a/js/src/builtin/WeakRefObject.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/. */ - -#include "builtin/WeakRefObject.h" - -#include "jsapi.h" -#include "jscntxt.h" - -#include "gc/Nursery.h" -#include "gc/Tracer.h" -#include "vm/GlobalObject.h" - -#include "jsobjinlines.h" - -#include "vm/Interpreter-inl.h" -#include "vm/NativeObject-inl.h" - -using namespace js; - -static WeakRefObject::Referent* -GetReferent(JSObject* obj) -{ - return obj->as().getData(); -} - -static MOZ_ALWAYS_INLINE bool -IsWeakRef(HandleValue v) -{ - return v.isObject() && v.toObject().is(); -} - -static bool -WeakRef_deref_impl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsWeakRef(args.thisv())); - - WeakRefObject::Referent* data = GetReferent(&args.thisv().toObject()); - JSObject* target = data ? data->target.get() : nullptr; - if (target) - args.rval().setObject(*target); - else - args.rval().setUndefined(); - return true; -} - -const JSPropertySpec WeakRefObject::properties[] = { - JS_PS_END -}; - -const JSFunctionSpec WeakRefObject::methods[] = { - JS_FN("deref", WeakRefObject::deref, 0, 0), - JS_FS_END -}; - -static JSObject* -InitWeakRefClass(JSContext* cx, HandleObject obj, bool defineMembers) -{ - Handle global = obj.as(); - RootedPlainObject proto(cx, NewBuiltinClassInstance(cx)); - if (!proto) - return nullptr; - - RootedFunction ctor(cx, GlobalObject::createConstructor(cx, WeakRefObject::construct, - ClassName(JSProto_WeakRef, cx), 1)); - if (!ctor) - return nullptr; - - if (!LinkConstructorAndPrototype(cx, ctor, proto)) - return nullptr; - - if (defineMembers) { - if (!DefinePropertiesAndFunctions(cx, proto, WeakRefObject::properties, WeakRefObject::methods)) - return nullptr; - if (!DefineToStringTag(cx, proto, cx->names().WeakRef)) - return nullptr; - } - - if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_WeakRef, ctor, proto)) - return nullptr; - return proto; -} - -/* static */ WeakRefObject* -WeakRefObject::create(JSContext* cx, HandleObject target, HandleObject proto /* = nullptr */) -{ - Rooted obj(cx, NewObjectWithClassProto(cx, proto)); - if (!obj) - return nullptr; - - Referent* data = cx->new_(target, cx->options().weakRefs()); - if (!data) - return nullptr; - - obj->setPrivate(data); - return obj; -} - -/* static */ bool -WeakRefObject::construct(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - - if (!ThrowIfNotConstructing(cx, args, "WeakRef")) - return false; - - if (!args.get(0).isObject()) { - UniqueChars bytes = - DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, args.get(0), nullptr); - if (!bytes) - return false; - - JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, - bytes.get()); - return false; - } - - RootedObject target(cx, &args[0].toObject()); - - RootedObject proto(cx); - RootedObject newTarget(cx, &args.newTarget().toObject()); - if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) - return false; - - Rooted obj(cx, WeakRefObject::create(cx, target, proto)); - if (!obj) - return false; - - args.rval().setObject(*obj); - return true; -} - -/* static */ bool -WeakRefObject::deref(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -/* static */ void -WeakRefObject::trace(JSTracer* trc, JSObject* obj) -{ - if (Referent* data = GetReferent(obj)) { - JSObject* target = data->target.unbarrieredGet(); - if (!target) - return; - - // When pref-disabled, keep referent alive via strong trace so deref() - // stays usable as a stub without touching GC internals. - if (!data->enabled) { - TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef stub referent"); - } else if (IsInsideNursery(target)) { - // Weak edges must be tenured; trace strongly while referent is in the nursery. - TraceManuallyBarrieredEdge(trc, data->target.unsafeGet(), "WeakRef nursery referent"); - } else { - TraceWeakEdge(trc, &data->target, "WeakRef referent"); - } - } -} - -/* static */ void -WeakRefObject::finalize(FreeOp* fop, JSObject* obj) -{ - if (Referent* data = GetReferent(obj)) - fop->delete_(data); -} - -static const ClassOps WeakRefObjectClassOps = { - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - WeakRefObject::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - WeakRefObject::trace -}; - -const Class WeakRefObject::class_ = { - "WeakRef", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_WeakRef) | - JSCLASS_BACKGROUND_FINALIZE, - &WeakRefObjectClassOps -}; - -/* static */ JSObject* -WeakRefObject::initClass(JSContext* cx, HandleObject obj) -{ - return ::InitWeakRefClass(cx, obj, true); -} - -JSObject* -js::InitWeakRefClass(JSContext* cx, HandleObject obj) -{ - return WeakRefObject::initClass(cx, obj); -} - -JSObject* -js::InitBareWeakRefCtor(JSContext* cx, HandleObject obj) -{ - return ::InitWeakRefClass(cx, obj, false); -} diff --git a/js/src/builtin/WeakRefObject.h b/js/src/builtin/WeakRefObject.h deleted file mode 100644 index 6f2a2b4590..0000000000 --- a/js/src/builtin/WeakRefObject.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- - * 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/. */ - -#ifndef builtin_WeakRefObject_h -#define builtin_WeakRefObject_h - -#include "gc/Barrier.h" -#include "vm/NativeObject.h" - -namespace js { - -class WeakRefObject : public NativeObject -{ - public: - struct Referent { - explicit Referent(JSObject* obj, bool enabled) - : target(obj), enabled(enabled) {} - WeakRef target; - bool enabled; - }; - - static const Class class_; - - static JSObject* initClass(JSContext* cx, HandleObject obj); - static WeakRefObject* create(JSContext* cx, HandleObject target, HandleObject proto = nullptr); - - static void trace(JSTracer* trc, JSObject* obj); - static void finalize(FreeOp* fop, JSObject* obj); - [[nodiscard]] static bool construct(JSContext* cx, unsigned argc, Value* vp); - static bool deref(JSContext* cx, unsigned argc, Value* vp); - - Referent* getData() const { - return static_cast(getPrivate()); - } - - WeakRef& target() { - MOZ_ASSERT(getData()); - return getData()->target; - } - - static const JSPropertySpec properties[]; - static const JSFunctionSpec methods[]; - - private: -}; - -extern JSObject* -InitWeakRefClass(JSContext* cx, HandleObject obj); - -extern JSObject* -InitBareWeakRefCtor(JSContext* cx, HandleObject obj); - -static inline bool -CanBeHeldWeakly(const Value& value) -{ - return value.isObject() || value.isSymbol(); -} - -} // namespace js - -#endif /* builtin_WeakRefObject_h */ diff --git a/js/src/builtin/WeakSet.js b/js/src/builtin/WeakSet.js index 88f7929c72..b16b4634dd 100644 --- a/js/src/builtin/WeakSet.js +++ b/js/src/builtin/WeakSet.js @@ -32,7 +32,7 @@ function WeakSet_add(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "add", typeof S); // Step 5. - if (!CanBeHeldWeakly(value)) + if (!IsObject(value)) ThrowTypeError(JSMSG_NOT_NONNULL_OBJECT, DecompileArg(0, value)); // Steps 7-8. @@ -55,7 +55,7 @@ function WeakSet_delete(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "delete", typeof S); // Step 5. - if (!CanBeHeldWeakly(value)) + if (!IsObject(value)) return false; // Steps 7-8. @@ -75,7 +75,7 @@ function WeakSet_has(value) { ThrowTypeError(JSMSG_INCOMPATIBLE_PROTO, "WeakSet", "has", typeof S); // Step 6. - if (!CanBeHeldWeakly(value)) + if (!IsObject(value)) return false; // Steps 7-8. diff --git a/js/src/builtin/WeakSetObject.cpp b/js/src/builtin/WeakSetObject.cpp index 055f6b1abd..bb9708f6f9 100644 --- a/js/src/builtin/WeakSetObject.cpp +++ b/js/src/builtin/WeakSetObject.cpp @@ -12,7 +12,6 @@ #include "builtin/MapObject.h" #include "builtin/SelfHostingDefines.h" #include "builtin/WeakMapObject.h" -#include "builtin/WeakRefObject.h" #include "vm/GlobalObject.h" #include "vm/SelfHosting.h" @@ -109,6 +108,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) if (optimized) { RootedValue keyVal(cx); + RootedObject keyObject(cx); RootedValue placeholder(cx, BooleanValue(true)); RootedObject map(cx, &obj->getReservedSlot(WEAKSET_MAP_SLOT).toObject()); RootedArrayObject array(cx, &iterable.toObject().as()); @@ -116,7 +116,7 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) keyVal.set(array->getDenseElement(index)); MOZ_ASSERT(!keyVal.isMagic(JS_ELEMENTS_HOLE)); - if (!CanBeHeldWeakly(keyVal)) { + if (keyVal.isPrimitive()) { UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, keyVal, nullptr); if (!bytes) @@ -126,7 +126,8 @@ WeakSetObject::construct(JSContext* cx, unsigned argc, Value* vp) return false; } - if (!SetWeakMapEntryValue(cx, map, keyVal, placeholder)) + keyObject = &keyVal.toObject(); + if (!SetWeakMapEntry(cx, map, keyObject, placeholder)) return false; } } else { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 4fc540e626..adef1f46f9 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -1470,12 +1470,6 @@ TryAttachGetElemStub(JSContext* cx, JSScript* script, jsbytecode* pc, ICGetElem_ res.isNumber() && !TypedArrayGetElemStubExists(stub, obj)) { - if (obj->is() && - obj->as().hasResizableOrGrowableBuffer()) - { - return true; - } - if (!cx->runtime()->jitSupportsFloatingPoint && (TypedThingRequiresFloatingPoint(obj) || rhs.isDouble())) { @@ -2166,8 +2160,6 @@ ICGetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm) Register obj = masm.extractObject(R0, ExtractTemp0); masm.loadPtr(Address(ICStubReg, ICGetElem_TypedArray::offsetOfShape()), scratchReg); masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure); - if (layout_ == Layout_TypedArray) - GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure); // Ensure the index is an integer. if (cx->runtime()->jitSupportsFloatingPoint) { @@ -2639,9 +2631,6 @@ DoSetElemFallback(JSContext* cx, BaselineFrame* frame, ICSetElem_Fallback* stub_ bool expectOutOfBounds; double idx = index.toNumber(); if (obj->is()) { - if (obj->as().hasResizableOrGrowableBuffer()) - return true; - expectOutOfBounds = (idx < 0 || idx >= double(obj->as().length())); } else { // Typed objects throw on out of bounds accesses. Don't attach @@ -3232,8 +3221,6 @@ ICSetElem_TypedArray::Compiler::generateStubCode(MacroAssembler& masm) Register obj = masm.extractObject(R0, ExtractTemp0); masm.loadPtr(Address(ICStubReg, ICSetElem_TypedArray::offsetOfShape()), scratchReg); masm.branchTestObjShape(Assembler::NotEqual, obj, scratchReg, &failure); - if (layout_ == Layout_TypedArray) - GuardResizableOrGrowableTypedArray(masm, obj, scratchReg, &failure); // Ensure the index is an integer. if (cx->runtime()->jitSupportsFloatingPoint) { diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 1ef6e607e8..a37c3079ef 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8889,17 +8889,9 @@ CodeGenerator::branchIfNotEmptyObjectElements(Register obj, Label* target) Address(obj, NativeObject::offsetOfElements()), ImmPtr(js::emptyObjectElements), &emptyObj); - masm.branchPtr(Assembler::Equal, - Address(obj, NativeObject::offsetOfElements()), - ImmPtr(js::emptyObjectElementsShared), - &emptyObj); - masm.branchPtr(Assembler::Equal, - Address(obj, NativeObject::offsetOfElements()), - ImmPtr(js::emptyObjectElementsResizableOrGrowable), - &emptyObj); masm.branchPtr(Assembler::NotEqual, Address(obj, NativeObject::offsetOfElements()), - ImmPtr(js::emptyObjectElementsSharedResizableOrGrowable), + ImmPtr(js::emptyObjectElementsShared), target); masm.bind(&emptyObj); } diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 0e554c17af..02fda9d577 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -537,7 +537,8 @@ class CodeGenerator final : public CodeGeneratorSpecific Label* ifDoesntEmulateUndefined, Register scratch, OutOfLineTestObject* ool); - // Branch to target unless obj has one of the empty elements pointers. + // Branch to target unless obj has an emptyObjectElements or emptyObjectElementsShared + // elements pointer. void branchIfNotEmptyObjectElements(Register obj, Label* target); void emitStoreElementTyped(const LAllocation* value, MIRType valueType, MIRType elementType, diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 095dc14175..5a7e437285 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -1245,7 +1245,6 @@ GenerateTypedArrayLength(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta masm.branchPtr(Assembler::AboveOrEqual, tmpReg, ImmPtr(&TypedArrayObject::classes[Scalar::MaxTypedArrayViewType]), failures); - GuardResizableOrGrowableTypedArray(masm, object, tmpReg, failures); // Load length. masm.loadTypedOrValue(Address(object, TypedArrayObject::lengthOffset()), output); @@ -1645,9 +1644,6 @@ GetPropertyIC::tryAttachTypedArrayLength(JSContext* cx, HandleScript outerScript if (!JSID_IS_ATOM(id, cx->names().length)) return true; - if (obj->as().hasResizableOrGrowableBuffer()) - return true; - if (hasTypedArrayLengthStub(obj)) return true; @@ -4042,12 +4038,6 @@ GetPropertyIC::canAttachTypedOrUnboxedArrayElement(JSObject* obj, const Value& i if (!obj->is() && !obj->is()) return false; - if (obj->is() && - obj->as().hasResizableOrGrowableBuffer()) - { - return false; - } - MOZ_ASSERT(idval.isInt32() || idval.isString()); // Don't emit a stub if the access is out of bounds. We make to make @@ -4102,9 +4092,6 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm, // Decide to what type index the stub should be optimized Register tmpReg = output.scratchReg().gpr(); MOZ_ASSERT(tmpReg != InvalidReg); - if (array->is()) - GuardResizableOrGrowableTypedArray(masm, object, tmpReg, &failures); - Register indexReg = tmpReg; if (idval.isString()) { MOZ_ASSERT(GetIndexFromString(idval.toString()) != UINT32_MAX); @@ -4588,7 +4575,6 @@ GenerateSetTypedArrayElement(JSContext* cx, MacroAssembler& masm, IonCache::Stub if (!shape) return false; masm.branchTestObjShape(Assembler::NotEqual, object, shape, &failures); - GuardResizableOrGrowableTypedArray(masm, object, temp, &failures); // Ensure the index is an int32. Register indexReg; @@ -4675,9 +4661,6 @@ SetPropertyIC::tryAttachTypedArrayElement(JSContext* cx, HandleScript outerScrip if (!IsTypedArrayElementSetInlineable(obj, idval, val)) return true; - if (obj->as().hasResizableOrGrowableBuffer()) - return true; - *emitted = true; MacroAssembler masm(cx, ion, outerScript, profilerLeavePc_); diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index 4585a838b4..0f78ef3f2f 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -365,9 +365,13 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target) // Try to optimize typed array lengths. if (TypedArrayObject::isOriginalLengthGetter(native)) { - // RAB/GSAB views can have dynamic length or temporarily become - // out-of-bounds. Let the property IC/VM path handle the getter. - return InliningStatus_NotInlined; + Scalar::Type type = thisTypes->getTypedArrayType(constraints()); + if (type == Scalar::MaxTypedArrayViewType) + return InliningStatus_NotInlined; + + MInstruction* length = addTypedArrayLength(thisArg); + current->push(length); + return InliningStatus_Inlined; } // Try to optimize RegExp getters. @@ -2476,10 +2480,21 @@ IsTypedArrayObject(CompilerConstraintList* constraints, MDefinition* def) IonBuilder::InliningStatus IonBuilder::inlinePossiblyWrappedTypedArrayLength(CallInfo& callInfo) { - (void) callInfo; + MOZ_ASSERT(!callInfo.constructing()); + MOZ_ASSERT(callInfo.argc() == 1); + if (callInfo.getArg(0)->type() != MIRType::Object) + return InliningStatus_NotInlined; + if (getInlineReturnType() != MIRType::Int32) + return InliningStatus_NotInlined; - // RAB/GSAB views require dynamic length semantics. - return InliningStatus_NotInlined; + if (!IsTypedArrayObject(constraints(), callInfo.getArg(0))) + return InliningStatus_NotInlined; + + MInstruction* length = addTypedArrayLength(callInfo.getArg(0)); + current->push(length); + + callInfo.setImplicitlyUsedUnchecked(); + return InliningStatus_Inlined; } IonBuilder::InliningStatus @@ -3236,14 +3251,45 @@ bool IonBuilder::atomicsMeetsPreconditions(CallInfo& callInfo, Scalar::Type* arrayType, bool* requiresTagCheck, AtomicCheckResult checkResult) { - (void) callInfo; - (void) arrayType; - (void) requiresTagCheck; - (void) checkResult; + if (!JitSupportsAtomics()) + return false; - // Atomics bounds checks through addTypedArrayLengthAndData assume stable - // SharedArrayBuffer lengths. Avoid this path now that growable SAB exists. - return false; + if (callInfo.getArg(0)->type() != MIRType::Object) + return false; + + if (callInfo.getArg(1)->type() != MIRType::Int32) + return false; + + // Ensure that the first argument is a TypedArray that maps shared + // memory. + // + // Then check both that the element type is something we can + // optimize and that the return type is suitable for that element + // type. + + TemporaryTypeSet* arg0Types = callInfo.getArg(0)->resultTypeSet(); + if (!arg0Types) + return false; + + TemporaryTypeSet::TypedArraySharedness sharedness; + *arrayType = arg0Types->getTypedArrayType(constraints(), &sharedness); + *requiresTagCheck = sharedness != TemporaryTypeSet::KnownShared; + switch (*arrayType) { + case Scalar::Int8: + case Scalar::Uint8: + case Scalar::Int16: + case Scalar::Uint16: + case Scalar::Int32: + return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Int32; + case Scalar::Uint32: + // Bug 1077305: it would be attractive to allow inlining even + // if the inline return type is Int32, which it will frequently + // be. + return checkResult == DontCheckAtomicResult || getInlineReturnType() == MIRType::Double; + default: + // Excludes floating types and Uint8Clamped. + return false; + } } void diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index 8f13179bfd..197737c1ef 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5505,15 +5505,25 @@ jit::ElementAccessIsTypedArray(CompilerConstraintList* constraints, MDefinition* obj, MDefinition* id, Scalar::Type* arrayType) { - (void) constraints; - (void) obj; - (void) id; - (void) arrayType; + if (obj->mightBeType(MIRType::String)) + return false; - // Resizable ArrayBuffer and growable SharedArrayBuffer views need dynamic - // length/out-of-bounds handling. This older MIR path assumes stable - // typed-array length/data slots, so keep element accesses on IC/VM paths. - return false; + if (id->type() != MIRType::Int32 && id->type() != MIRType::Double) + return false; + + TemporaryTypeSet* types = obj->resultTypeSet(); + if (!types) + return false; + + *arrayType = types->getTypedArrayType(constraints); + + // FIXME: https://bugzil.la/1536699 + if (*arrayType == Scalar::MaxTypedArrayViewType || + Scalar::isBigIntType(*arrayType)) { + return false; + } + + return true; } bool diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index edf39837cd..2805651f12 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -3631,17 +3631,6 @@ CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Labe masm.branch32(Assembler::NotEqual, AbsoluteAddress(address), Imm32(0), failure); } -void -GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch, - Label* failure) -{ - masm.loadPtr(Address(obj, NativeObject::offsetOfElements()), scratch); - masm.branchTest32(Assembler::NonZero, - Address(scratch, ObjectElements::offsetOfFlags()), - Imm32(ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER), - failure); -} - void LoadTypedThingData(MacroAssembler& masm, TypedThingLayout layout, Register obj, Register result) { diff --git a/js/src/jit/SharedIC.h b/js/src/jit/SharedIC.h index cf23490942..ab379d3039 100644 --- a/js/src/jit/SharedIC.h +++ b/js/src/jit/SharedIC.h @@ -2307,11 +2307,7 @@ CheckDOMProxyExpandoDoesNotShadow(JSContext* cx, MacroAssembler& masm, Register void CheckForTypedObjectWithDetachedStorage(JSContext* cx, MacroAssembler& masm, Label* failure); -void -GuardResizableOrGrowableTypedArray(MacroAssembler& masm, Register obj, Register scratch, - Label* failure); - -[[nodiscard]] bool +MOZ_MUST_USE bool DoCallNativeGetter(JSContext* cx, HandleFunction callee, HandleObject obj, MutableHandleValue result); diff --git a/js/src/js.msg b/js/src/js.msg index c635bb54ed..499e7a1623 100644 --- a/js/src/js.msg +++ b/js/src/js.msg @@ -548,8 +548,6 @@ MSG_DEF(JSMSG_TOO_LONG_ARRAY, 0, JSEXN_TYPEERR, "Too long array") // Typed array MSG_DEF(JSMSG_BAD_INDEX, 0, JSEXN_RANGEERR, "invalid or out-of-range index") -MSG_DEF(JSMSG_ARRAYBUFFER_NOT_RESIZABLE, 0, JSEXN_TYPEERR, "ArrayBuffer is not resizable") -MSG_DEF(JSMSG_ARRAYBUFFER_CANNOT_DETACH, 0, JSEXN_TYPEERR, "ArrayBuffer cannot be detached") MSG_DEF(JSMSG_NON_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected ArrayBuffer, but species constructor returned non-ArrayBuffer") MSG_DEF(JSMSG_SAME_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different ArrayBuffer, but species constructor returned same ArrayBuffer") MSG_DEF(JSMSG_SHORT_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected ArrayBuffer with at least {0} bytes, but species constructor returns ArrayBuffer with {1} bytes") @@ -557,15 +555,12 @@ MSG_DEF(JSMSG_TYPED_ARRAY_BAD_ARGS, 0, JSEXN_TYPEERR, "invalid arguments") MSG_DEF(JSMSG_TYPED_ARRAY_NEGATIVE_ARG,1, JSEXN_RANGEERR, "argument {0} must be >= 0") MSG_DEF(JSMSG_TYPED_ARRAY_DETACHED, 0, JSEXN_TYPEERR, "attempting to access detached ArrayBuffer") MSG_DEF(JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS, 0, JSEXN_RANGEERR, "attempting to construct out-of-bounds TypedArray on ArrayBuffer") -MSG_DEF(JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds TypedArray") -MSG_DEF(JSMSG_DATA_VIEW_OUT_OF_BOUNDS, 0, JSEXN_TYPEERR, "attempting to access out-of-bounds DataView") MSG_DEF(JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT, 1, JSEXN_TYPEERR, "cannot directly {0} builtin %TypedArray%") MSG_DEF(JSMSG_NON_TYPED_ARRAY_RETURNED, 0, JSEXN_TYPEERR, "constructor didn't return TypedArray object") MSG_DEF(JSMSG_SHORT_TYPED_ARRAY_RETURNED, 2, JSEXN_TYPEERR, "expected TypedArray of at least length {0}, but constructor returned TypedArray of length {1}") // Shared array buffer MSG_DEF(JSMSG_SHARED_ARRAY_BAD_LENGTH, 0, JSEXN_RANGEERR, "length argument out of range") -MSG_DEF(JSMSG_SHARED_ARRAY_NOT_GROWABLE, 0, JSEXN_TYPEERR, "SharedArrayBuffer is not growable") MSG_DEF(JSMSG_NON_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected SharedArrayBuffer, but species constructor returned non-SharedArrayBuffer") MSG_DEF(JSMSG_SAME_SHARED_ARRAY_BUFFER_RETURNED, 0, JSEXN_TYPEERR, "expected different SharedArrayBuffer, but species constructor returned same SharedArrayBuffer") MSG_DEF(JSMSG_SHORT_SHARED_ARRAY_BUFFER_RETURNED, 2, JSEXN_TYPEERR, "expected SharedArrayBuffer with at least {0} bytes, but species constructor returns SharedArrayBuffer with {1} bytes") diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3ea147eaff..f1627e481e 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -951,20 +951,6 @@ LookupStdName(const JSAtomState& names, JSAtom* name, const JSStdName* table) return nullptr; } -static bool -IsStreamExtraName(JSFlatString* name) -{ - return JS_FlatStringEqualsAscii(name, "WritableStream") || - JS_FlatStringEqualsAscii(name, "WritableStreamDefaultWriter") || - JS_FlatStringEqualsAscii(name, "WritableStreamDefaultController") || - JS_FlatStringEqualsAscii(name, "TransformStream") || - JS_FlatStringEqualsAscii(name, "TransformStreamDefaultController") || - JS_FlatStringEqualsAscii(name, "TextEncoderStream") || - JS_FlatStringEqualsAscii(name, "TextDecoderStream") || - JS_FlatStringEqualsAscii(name, "CompressionStream") || - JS_FlatStringEqualsAscii(name, "DecompressionStream"); -} - /* * Table of standard classes, indexed by JSProtoKey. For entries where the * JSProtoKey does not correspond to a class with a meaningful constructor, we @@ -1055,27 +1041,11 @@ JS_ResolveStandardClass(JSContext* cx, HandleObject obj, HandleId id, bool* reso if (!GlobalObject::ensureConstructor(cx, global, key)) return false; - if (key == JSProto_ReadableStream) { - RootedObject globalObj(cx, global); - if (!InitStreamExtras(cx, globalObj)) - return false; - } - *resolved = true; return true; } } - if (cx->options().streams() && IsStreamExtraName(idAtom)) { - RootedObject globalObj(cx, global); - if (!InitStreamExtras(cx, globalObj)) - return false; - - if (!HasOwnProperty(cx, globalObj, id, resolved)) - return false; - return true; - } - // There is no such property to resolve. An ordinary resolve hook would // just return true at this point. But the global object is special in one // more way: its prototype chain is lazily initialized. That is, @@ -1105,7 +1075,6 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj return atom == names.undefined || atom == names.globalThis || - IsStreamExtraName(atom) || LookupStdName(names, atom, standard_class_names) || LookupStdName(names, atom, builtin_property_names); } diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 7744bdd592..cae2297ae4 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -998,9 +998,7 @@ class JS_PUBLIC_API(ContextOptions) { werror_(false), strictMode_(false), extraWarnings_(false), - arrayProtoValues_(true), - streams_(true), - weakRefs_(false) + arrayProtoValues_(true) { } @@ -1140,16 +1138,6 @@ class JS_PUBLIC_API(ContextOptions) { return *this; } - bool weakRefs() const { return weakRefs_; } - ContextOptions& setWeakRefs(bool flag) { - weakRefs_ = flag; - return *this; - } - ContextOptions& toggleWeakRefs() { - weakRefs_ = !weakRefs_; - return *this; - } - private: bool baseline_ : 1; bool ion_ : 1; @@ -1167,7 +1155,6 @@ class JS_PUBLIC_API(ContextOptions) { bool extraWarnings_ : 1; bool arrayProtoValues_ : 1; bool streams_ : 1; - bool weakRefs_ : 1; }; JS_PUBLIC_API(ContextOptions&) diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 2697cb5337..c463019dac 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1748,9 +1748,6 @@ JS_IsFloat64Array(JSObject* obj); extern JS_FRIEND_API(bool) JS_GetTypedArraySharedness(JSObject* obj); -extern JS_FRIEND_API(uint32_t) -JS_GetTypedArrayLength(JSObject* obj); - /* * Test for specific typed array types (ArrayBufferView subtypes) and return * the unwrapped object if so, else nullptr. Never throws. @@ -1817,7 +1814,8 @@ inline void \ Get ## Type ## ArrayLengthAndData(JSObject* obj, uint32_t* length, bool* isSharedMemory, type** data) \ { \ MOZ_ASSERT(GetObjectClass(obj) == detail::Type ## ArrayClassPtr); \ - *length = JS_GetTypedArrayLength(obj); \ + const JS::Value& lenSlot = GetReservedSlot(obj, detail::TypedArrayLengthSlot); \ + *length = mozilla::AssertedCast(lenSlot.toInt32()); \ *isSharedMemory = JS_GetTypedArraySharedness(obj); \ *data = static_cast(GetObjectPrivate(obj)); \ } diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h index 6005724f89..9822a47b6c 100644 --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -119,7 +119,6 @@ IF_SAB(real,imaginary)(Atomics, InitAtomicsClass, OCLASP(Atomics)) \ imaginary(WritableStreamDefaultController,dummy, dummy) \ real(ByteLengthQueuingStrategy, InitViaClassSpec, &js::ByteLengthQueuingStrategy::class_) \ real(CountQueuingStrategy, InitViaClassSpec, &js::CountQueuingStrategy::class_) \ - real(WeakRef, InitWeakRefClass, OCLASP(WeakRef)) \ #define JS_FOR_EACH_PROTOTYPE(macro) JS_FOR_PROTOTYPES(macro,macro) diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index 67de5d7236..5209e979de 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -3344,8 +3344,6 @@ static const JSFunctionSpec string_methods[] = { JS_SELF_HOSTED_FN("toLocaleUpperCase", "String_toLocaleUpperCase", 0,0), JS_SELF_HOSTED_FN("localeCompare", "String_localeCompare", 1,0), JS_SELF_HOSTED_FN("repeat", "String_repeat", 1,0), - JS_SELF_HOSTED_FN("isWellFormed", "String_isWellFormed", 0,0), - JS_SELF_HOSTED_FN("toWellFormed", "String_toWellFormed", 0,0), JS_FN("normalize", str_normalize, 0,0), /* Perl-ish methods (search is actually Python-esque). */ diff --git a/js/src/jsweakmap.h b/js/src/jsweakmap.h index ec0fd8ddc6..c13baa7825 100644 --- a/js/src/jsweakmap.h +++ b/js/src/jsweakmap.h @@ -16,25 +16,11 @@ #include "gc/Marking.h" #include "gc/StoreBuffer.h" #include "js/HashTable.h" -#include "vm/Symbol.h" namespace js { class WeakMapBase; -template <> -struct MovableCellHasher -{ - using Key = JS::Symbol*; - using Lookup = JS::Symbol*; - - static bool hasHash(const Lookup& l) { return true; } - static bool ensureHash(const Lookup& l) { return true; } - static HashNumber hash(const Lookup& l) { return l->hash(); } - static bool match(const Key& k, const Lookup& l) { return k == l; } - static void rekey(Key& k, const Key& newKey) { k = newKey; } -}; - // A subclass template of js::HashMap whose keys and values may be garbage-collected. When // a key is collected, the table entry disappears, dropping its reference to the value. // @@ -310,16 +296,9 @@ class WeakMap : public HashMap, return nullptr; } - JSObject* getDelegate(JS::Symbol* sym) const { - return nullptr; - } - private: void exposeGCThingToActiveJS(const JS::Value& v) const { JS::ExposeValueToActiveJS(v); } void exposeGCThingToActiveJS(JSObject* obj) const { JS::ExposeObjectToActiveJS(obj); } - void exposeGCThingToActiveJS(JS::Symbol* sym) const { - gc::ExposeGCThingToActiveJS(JS::GCCellPtr(sym)); - } bool keyNeedsMark(JSObject* key) const { JSObject* delegate = getDelegate(key); @@ -334,10 +313,6 @@ class WeakMap : public HashMap, return false; } - bool keyNeedsMark(JS::Symbol* sym) const { - return false; - } - bool findZoneEdges() override { // This is overridden by ObjectValueMap. return true; @@ -403,9 +378,6 @@ WeakMap_set(JSContext* cx, unsigned argc, Value* vp); extern bool WeakMap_delete(JSContext* cx, unsigned argc, Value* vp); -extern bool -SetWeakMapEntryValue(JSContext* cx, HandleObject mapObj, HandleValue key, HandleValue val); - extern JSObject* InitWeakMapClass(JSContext* cx, HandleObject obj); @@ -422,16 +394,6 @@ class ObjectValueMap : public WeakMap, HeapPtr, virtual bool findZoneEdges(); }; -class SymbolValueMap : public WeakMap, HeapPtr, - MovableCellHasher>> -{ - public: - SymbolValueMap(JSContext* cx, JSObject* obj) - : WeakMap, HeapPtr, - MovableCellHasher>>(cx, obj) - {} -}; - // Generic weak map for mapping objects to other objects. class ObjectWeakMap diff --git a/js/src/moz.build b/js/src/moz.build index 6672e41220..baa4e1a19e 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -142,7 +142,6 @@ main_deunified_sources = [ 'builtin/TestingFunctions.cpp', 'builtin/TypedObject.cpp', 'builtin/WeakMapObject.cpp', - 'builtin/WeakRefObject.cpp', 'builtin/WeakSetObject.cpp', 'devtools/sharkctl.cpp', 'ds/LifoAlloc.cpp', diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index 8f075ce228..ed30afa7ef 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -3330,15 +3330,6 @@ static const JSClass sandbox_class = { &sandbox_classOps }; -enum GlobalAppSlot { - GlobalAppSlotModuleMetadataHook, - GlobalAppSlotModuleDynamicImportHook, - GlobalAppSlotCount -}; - -static_assert(GlobalAppSlotCount <= JSCLASS_GLOBAL_APPLICATION_SLOTS, - "global application slots overflow"); - static void SetStandardCompartmentOptions(JS::CompartmentOptions& options) { @@ -4167,7 +4158,7 @@ ParseModule(JSContext* cx, unsigned argc, Value* vp) const char16_t* chars = stableChars.twoByteRange().begin().get(); JS::SourceBufferHolder srcBuf(chars, scriptContents->length(), - JS::SourceBufferHolder::NoOwnership); + SourceBufferHolder::NoOwnership); RootedObject module(cx, frontend::CompileModule(cx, options, srcBuf)); if (!module) @@ -4378,7 +4369,7 @@ AbortDynamicModuleImport(JSContext* cx, unsigned argc, Value* vp) RootedString specifier(cx, args[1].toString()); Rooted promise(cx, &args[2].toObject().as()); - cx->setPendingException(args[3], nullptr); + cx->setPendingException(args[3]); return js::FinishDynamicModuleImport(cx, args[0], specifier, promise); } @@ -8431,7 +8422,7 @@ main(int argc, char** argv, char** envp) JS::SetModuleResolveHook(cx->runtime(), ShellModuleResolveHook); JS::SetModuleDynamicImportHook(cx, ShellModuleDynamicImportHook); - JS::SetModuleMetadataHook(cx, CallModuleMetadataHook); + JS::SetModuleMetadataHook(cx, ShellModuleMetadataHook); result = Shell(cx, &op, envp); diff --git a/js/src/tests/non262/ArrayBuffer/resizable-transfer.js b/js/src/tests/non262/ArrayBuffer/resizable-transfer.js deleted file mode 100644 index f603edabff..0000000000 --- a/js/src/tests/non262/ArrayBuffer/resizable-transfer.js +++ /dev/null @@ -1,98 +0,0 @@ -// |reftest| skip-if(!ArrayBuffer.prototype.transfer) - -var fixed = new ArrayBuffer(4); -assertEq(fixed.byteLength, 4); -assertEq(fixed.maxByteLength, 4); -assertEq(fixed.resizable, false); -assertEq(fixed.detached, false); -new Uint8Array(fixed).set([1, 2, 3, 4]); -fixed.extra = 17; -assertEq(Array.from(new Uint8Array(fixed)).join(","), "1,2,3,4"); -assertThrowsInstanceOf(() => fixed.resize(2), TypeError); -assertEq(ArrayBuffer.prototype.transfer.length, 0); -assertEq(ArrayBuffer.prototype.transferToFixedLength.length, 0); -var resizeArgumentConverted = false; -assertThrowsInstanceOf(() => fixed.resize({ valueOf() { resizeArgumentConverted = true; return 1; } }), - TypeError); -assertEq(resizeArgumentConverted, false); - -var resizable = new ArrayBuffer(4, { maxByteLength: 8 }); -assertEq(resizable.byteLength, 4); -assertEq(resizable.maxByteLength, 8); -assertEq(resizable.resizable, true); - -var bytes = new Uint8Array(resizable); -bytes[0] = 11; -bytes[3] = 44; -resizable.resize(6); -assertEq(resizable.byteLength, 6); -assertEq(new Uint8Array(resizable)[0], 11); -assertEq(new Uint8Array(resizable)[3], 44); -assertEq(new Uint8Array(resizable)[4], 0); -assertThrowsInstanceOf(() => resizable.resize(9), RangeError); - -var source = new ArrayBuffer(4); -var sourceBytes = new Uint8Array(source); -sourceBytes[0] = 1; -sourceBytes[1] = 2; -var sourceView = new Uint8Array(source); -var moved = source.transfer(6); -assertEq(source.detached, true); -assertEq(source.byteLength, 0); -assertEq(source.maxByteLength, 0); -assertEq(sourceView.length, 0); -assertEq(moved.byteLength, 6); -assertEq(moved.resizable, false); -assertEq(moved.maxByteLength, 6); -assertEq(new Uint8Array(moved)[0], 1); -assertEq(new Uint8Array(moved)[1], 2); -assertEq(new Uint8Array(moved)[4], 0); - -var resizableSource = new ArrayBuffer(4, { maxByteLength: 8 }); -new Uint8Array(resizableSource)[0] = 7; -var resizableMoved = resizableSource.transfer(); -assertEq(resizableSource.detached, true); -assertEq(resizableSource.resizable, true); -assertEq(resizableMoved.byteLength, 4); -assertEq(resizableMoved.maxByteLength, 8); -assertEq(resizableMoved.resizable, true); -assertEq(new Uint8Array(resizableMoved)[0], 7); - -var fixedMoved = resizableMoved.transferToFixedLength(10); -assertEq(resizableMoved.detached, true); -assertEq(fixedMoved.byteLength, 10); -assertEq(fixedMoved.maxByteLength, 10); -assertEq(fixedMoved.resizable, false); -assertEq(new Uint8Array(fixedMoved)[0], 7); - -var sliceSource = new ArrayBuffer(8, { maxByteLength: 8 }); -var sliceSourceBytes = new Uint8Array(sliceSource); -for (var i = 0; i < sliceSourceBytes.length; i++) - sliceSourceBytes[i] = i + 1; - -sliceSource.constructor = { - [Symbol.species]: function(byteLength) { - sliceSource.resize(4); - return new ArrayBuffer(byteLength); - } -}; - -var sliced = sliceSource.slice(2, 8); -var slicedBytes = new Uint8Array(sliced); -assertEq(sliced.byteLength, 6); -assertEq(slicedBytes[0], 3); -assertEq(slicedBytes[1], 4); -assertEq(slicedBytes[2], 0); -assertEq(slicedBytes[5], 0); - -sliceSource.resize(8); -for (var i = 0; i < sliceSourceBytes.length; i++) - sliceSourceBytes[i] = i + 1; -var zeroCopied = sliceSource.slice(6, 8); -assertEq(zeroCopied.byteLength, 2); -assertEq(new Uint8Array(zeroCopied)[0], 0); - -assertThrowsInstanceOf(() => new ArrayBuffer(4, { maxByteLength: 3 }), RangeError); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/non262/ArrayBuffer/resizable-views.js b/js/src/tests/non262/ArrayBuffer/resizable-views.js deleted file mode 100644 index e8d810b165..0000000000 --- a/js/src/tests/non262/ArrayBuffer/resizable-views.js +++ /dev/null @@ -1,218 +0,0 @@ -// |reftest| skip-if(!this.SharedArrayBuffer) - -var rab = new ArrayBuffer(4, { maxByteLength: 16 }); -var tracking = new Uint8Array(rab); -var fixed = new Uint8Array(rab, 1, 2); -var bytes = new Uint8Array(rab); - -bytes[1] = 11; -bytes[2] = 22; - -assertEq(tracking.length, 4); -assertEq(tracking.byteLength, 4); -assertEq(tracking.byteOffset, 0); -assertEq(fixed.length, 2); -assertEq(fixed.byteLength, 2); -assertEq(fixed.byteOffset, 1); - -rab.resize(2); -assertEq(tracking.length, 2); -assertEq(tracking.byteLength, 2); -assertEq(fixed.length, 0); -assertEq(fixed.byteLength, 0); -assertEq(fixed.byteOffset, 0); -assertEq(fixed[0], undefined); - -rab.resize(8); -assertEq(tracking.length, 8); -assertEq(tracking.byteLength, 8); -assertEq(fixed.length, 2); -assertEq(fixed.byteLength, 2); -assertEq(fixed.byteOffset, 1); -assertEq(fixed[0], 11); -assertEq(fixed[1], 0); -tracking[6] = 66; -assertEq(new Uint8Array(rab)[6], 66); - -var dv = new DataView(rab, 4); -assertEq(dv.byteOffset, 4); -assertEq(dv.byteLength, 4); -dv.setUint8(0, 44); -assertEq(tracking[4], 44); - -rab.resize(3); -assertThrowsInstanceOf(() => dv.byteOffset, TypeError); -assertThrowsInstanceOf(() => dv.byteLength, TypeError); -assertThrowsInstanceOf(() => dv.getUint8(0), TypeError); - -rab.resize(6); -assertEq(dv.byteOffset, 4); -assertEq(dv.byteLength, 2); -assertEq(dv.getUint8(0), 0); - -var fixedDv = new DataView(rab, 4, 2); -rab.resize(5); -assertThrowsInstanceOf(() => fixedDv.byteOffset, TypeError); -assertThrowsInstanceOf(() => fixedDv.byteLength, TypeError); -assertThrowsInstanceOf(() => fixedDv.getUint8(0), TypeError); -rab.resize(6); -assertEq(fixedDv.byteOffset, 4); -assertEq(fixedDv.byteLength, 2); - -var methodRab = new ArrayBuffer(4, { maxByteLength: 8 }); -var methodFixed = new Uint8Array(methodRab, 2, 2); -methodRab.resize(2); -[ - () => methodFixed.at(0), - () => methodFixed.copyWithin(0, 0), - () => methodFixed.entries(), - () => methodFixed.every(x => true), - () => methodFixed.fill(1), - () => methodFixed.filter(x => true), - () => methodFixed.find(x => true), - () => methodFixed.findIndex(x => true), - () => methodFixed.findLast(x => true), - () => methodFixed.findLastIndex(x => true), - () => methodFixed.forEach(x => x), - () => methodFixed.includes(0), - () => methodFixed.indexOf(0), - () => methodFixed.join(","), - () => methodFixed.keys(), - () => methodFixed.lastIndexOf(0), - () => methodFixed.map(x => x), - () => methodFixed.reduce((a, b) => a + b, 0), - () => methodFixed.reduceRight((a, b) => a + b, 0), - () => methodFixed.reverse(), - () => methodFixed.set([1], 0), - () => methodFixed.slice(), - () => methodFixed.some(x => true), - () => methodFixed.sort(), - () => methodFixed.subarray(), - () => methodFixed.toLocaleString(), - () => methodFixed.toReversed(), - () => methodFixed.toSorted(), - () => methodFixed.toString(), - () => methodFixed.values(), - () => methodFixed.with(0, 1), - () => methodFixed[Symbol.iterator](), -].forEach(fn => assertThrowsInstanceOf(fn, TypeError)); - -methodRab.resize(4); -assertEq(methodFixed.length, 2); - -var sourceRab = new ArrayBuffer(4, { maxByteLength: 8 }); -var oobSource = new Uint8Array(sourceRab, 2, 2); -sourceRab.resize(2); -assertThrowsInstanceOf(() => new Uint8Array(oobSource), TypeError); -assertThrowsInstanceOf(() => new Uint16Array(oobSource), TypeError); -assertThrowsInstanceOf(() => new Uint8Array(4).set(oobSource), TypeError); -sourceRab.resize(4); -assertEq(new Uint8Array(oobSource).length, 2); - -var ctorRab = new ArrayBuffer(8, { maxByteLength: 8 }); -var ShrinkingNewTarget = new Proxy(function() {}, { - get(target, prop, receiver) { - if (prop === "prototype") { - ctorRab.resize(2); - return DataView.prototype; - } - return Reflect.get(target, prop, receiver); - } -}); -assertThrowsInstanceOf(() => Reflect.construct(DataView, [ctorRab, 4], ShrinkingNewTarget), - RangeError); - -var fixedCtorRab = new ArrayBuffer(8, { maxByteLength: 8 }); -var FixedShrinkingNewTarget = new Proxy(function() {}, { - get(target, prop, receiver) { - if (prop === "prototype") { - fixedCtorRab.resize(5); - return DataView.prototype; - } - return Reflect.get(target, prop, receiver); - } -}); -assertThrowsInstanceOf(() => Reflect.construct(DataView, [fixedCtorRab, 4, 2], - FixedShrinkingNewTarget), - RangeError); - -var gsab = new SharedArrayBuffer(4, { maxByteLength: 16 }); -var sharedTracking = new Uint8Array(gsab); -assertEq(sharedTracking.length, 4); -gsab.grow(8); -assertEq(sharedTracking.length, 8); -sharedTracking[6] = 33; -assertEq(new Uint8Array(gsab)[6], 33); - -var sharedDv = new DataView(gsab); -assertEq(sharedDv.buffer, gsab); -assertEq(sharedDv.byteOffset, 0); -assertEq(sharedDv.byteLength, 8); -sharedDv.setUint8(7, 99); -assertEq(sharedTracking[7], 99); -gsab.grow(12); -assertEq(sharedDv.byteLength, 12); -assertEq(sharedDv.getUint8(7), 99); - -var fixedSharedDv = new DataView(gsab, 4, 2); -assertEq(fixedSharedDv.byteOffset, 4); -assertEq(fixedSharedDv.byteLength, 2); -gsab.grow(16); -assertEq(fixedSharedDv.byteOffset, 4); -assertEq(fixedSharedDv.byteLength, 2); - -function readLength(view) { - return view.length; -} - -function readElement(view, index) { - return view[index]; -} - -function writeElement(view, index, value) { - view[index] = value; -} - -var normal = new Uint8Array(4); -normal[0] = 7; -for (var i = 0; i < 2000; i++) { - assertEq(readLength(normal), 4); - assertEq(readElement(normal, 0), 7); - writeElement(normal, 1, 8); -} - -var icRab = new ArrayBuffer(4, { maxByteLength: 8 }); -var icTracking = new Uint8Array(icRab); -icTracking[0] = 9; -assertEq(readLength(icTracking), 4); -assertEq(readElement(icTracking, 0), 9); -icRab.resize(0); -assertEq(readLength(icTracking), 0); -assertEq(readElement(icTracking, 0), undefined); -writeElement(icTracking, 0, 1); -icRab.resize(4); -assertEq(readLength(icTracking), 4); -assertEq(readElement(icTracking, 0), 0); -writeElement(icTracking, 0, 12); -assertEq(readElement(icTracking, 0), 12); - -var icFixed = new Uint8Array(icRab, 1, 2); -assertEq(readLength(icFixed), 2); -icRab.resize(2); -assertEq(readLength(icFixed), 0); -assertEq(readElement(icFixed, 0), undefined); -writeElement(icFixed, 0, 55); -icRab.resize(4); -assertEq(readLength(icFixed), 2); -assertEq(readElement(icFixed, 0), 0); - -var icGsab = new SharedArrayBuffer(4, { maxByteLength: 8 }); -var icSharedTracking = new Uint8Array(icGsab); -assertEq(readLength(icSharedTracking), 4); -icGsab.grow(8); -assertEq(readLength(icSharedTracking), 8); -writeElement(icSharedTracking, 5, 77); -assertEq(readElement(icSharedTracking, 5), 77); - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/non262/Atomics/waitAsync.js b/js/src/tests/non262/Atomics/waitAsync.js deleted file mode 100644 index a2b23a4f80..0000000000 --- a/js/src/tests/non262/Atomics/waitAsync.js +++ /dev/null @@ -1,77 +0,0 @@ -// |reftest| skip-if(!this.SharedArrayBuffer || !this.Atomics || !this.drainJobQueue) - -if (typeof SharedArrayBuffer === "function" && typeof Atomics === "object" && - typeof drainJobQueue === "function") { - const sab = new SharedArrayBuffer(4); - const i32 = new Int32Array(sab); - - let result = Atomics.waitAsync(i32, 0, 1, 10); - assertEq(result.async, false); - assertEq(result.value, "not-equal"); - - result = Atomics.waitAsync(i32, 0, 0, 0); - assertEq(result.async, false); - assertEq(result.value, "timed-out"); - - result = Atomics.waitAsync(i32, 0, 0); - assertEq(result.async, true); - let notified; - result.value.then(value => { - notified = value; - }); - assertEq(Atomics.notify(i32, 0, 1), 1); - drainJobQueue(); - assertEq(notified, "ok"); - - result = Atomics.waitAsync(i32, 0, 0, 1); - assertEq(result.async, true); - let timedOut; - result.value.then(value => { - timedOut = value; - }); - drainJobQueue(); - assertEq(timedOut, "timed-out"); - - if (typeof BigInt64Array === "function") { - const bigSab = new SharedArrayBuffer(16); - const i64 = new BigInt64Array(bigSab); - const u64 = new BigUint64Array(bigSab); - - assertEq(Atomics.store(i64, 0, -1n), -1n); - assertEq(Atomics.load(i64, 0), -1n); - assertEq(Atomics.load(u64, 0), 18446744073709551615n); - assertEq(Atomics.exchange(i64, 0, 7n), -1n); - assertEq(Atomics.compareExchange(i64, 0, 7n, 10n), 7n); - assertEq(Atomics.add(i64, 0, 5n), 10n); - assertEq(Atomics.load(i64, 0), 15n); - assertEq(Atomics.sub(i64, 0, 20n), 15n); - assertEq(Atomics.load(i64, 0), -5n); - assertEq(Atomics.and(u64, 0, 7n), 18446744073709551611n); - assertEq(Atomics.or(u64, 0, 8n), 3n); - assertEq(Atomics.xor(u64, 0, 15n), 11n); - - assertThrowsInstanceOf(() => Atomics.waitAsync(u64, 0, 0n), TypeError); - - result = Atomics.waitAsync(i64, 1, 1n, 10); - assertEq(result.async, false); - assertEq(result.value, "not-equal"); - - result = Atomics.waitAsync(i64, 1, 0n, 0); - assertEq(result.async, false); - assertEq(result.value, "timed-out"); - - let offsetView = new BigInt64Array(bigSab, 8); - result = Atomics.waitAsync(offsetView, 0, 0n); - assertEq(result.async, true); - notified = undefined; - result.value.then(value => { - notified = value; - }); - assertEq(Atomics.notify(i64, 1, 1), 1); - drainJobQueue(); - assertEq(notified, "ok"); - } -} - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/non262/Promise/with-resolvers.js b/js/src/tests/non262/Promise/with-resolvers.js deleted file mode 100644 index 985d458622..0000000000 --- a/js/src/tests/non262/Promise/with-resolvers.js +++ /dev/null @@ -1,31 +0,0 @@ -// |reftest| skip-if(!Promise.withResolvers) - -var desc = Object.getOwnPropertyDescriptor(Promise, "withResolvers"); -assertEq(desc.enumerable, false); -assertEq(desc.configurable, true); -assertEq(desc.writable, true); -assertEq(Promise.withResolvers.length, 0); -assertEq(Promise.withResolvers.name, "withResolvers"); - -var capability = Promise.withResolvers(); -assertEq(capability.promise instanceof Promise, true); -assertEq(typeof capability.resolve, "function"); -assertEq(typeof capability.reject, "function"); -assertEqArray(Object.keys(capability), ["promise", "resolve", "reject"]); - -capability.resolve(42); -capability.promise.then(v => assertEq(v, 42)); - -class MyPromise extends Promise {} -var subCapability = Promise.withResolvers.call(MyPromise); -assertEq(subCapability.promise instanceof MyPromise, true); -subCapability.reject("rejected"); -subCapability.promise.then( - () => { throw new Error("expected rejection"); }, - reason => assertEq(reason, "rejected") -); - -assertThrowsInstanceOf(() => Promise.withResolvers.call({}), TypeError); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/non262/SharedArrayBuffer/growable.js b/js/src/tests/non262/SharedArrayBuffer/growable.js deleted file mode 100644 index 7b9ce85ffe..0000000000 --- a/js/src/tests/non262/SharedArrayBuffer/growable.js +++ /dev/null @@ -1,40 +0,0 @@ -// |reftest| skip-if(!this.SharedArrayBuffer) - -if (typeof SharedArrayBuffer === "function") { - const fixed = new SharedArrayBuffer(4); - assertEq(fixed.byteLength, 4); - assertEq(fixed.maxByteLength, 4); - assertEq(fixed.growable, false); - assertThrowsInstanceOf(() => fixed.grow(4), TypeError); - - assertThrowsInstanceOf(() => new SharedArrayBuffer(-1), RangeError); - assertThrowsInstanceOf(() => new SharedArrayBuffer(8, {maxByteLength: 4}), RangeError); - - let optionGetterCalled = false; - const growable = new SharedArrayBuffer(4, { - get maxByteLength() { - optionGetterCalled = true; - return 16; - } - }); - assertEq(optionGetterCalled, true); - assertEq(growable.byteLength, 4); - assertEq(growable.maxByteLength, 16); - assertEq(growable.growable, true); - - const before = new Uint8Array(growable); - before[0] = 37; - assertEq(growable.grow(12), undefined); - assertEq(growable.byteLength, 12); - assertEq(growable.maxByteLength, 16); - - const after = new Uint8Array(growable); - assertEq(after.length, 12); - assertEq(after[0], 37); - - assertThrowsInstanceOf(() => growable.grow(11), RangeError); - assertThrowsInstanceOf(() => growable.grow(17), RangeError); -} - -if (typeof reportCompare === "function") - reportCompare(true, true); diff --git a/js/src/tests/non262/String/well-formed.js b/js/src/tests/non262/String/well-formed.js deleted file mode 100644 index 7472f6afa8..0000000000 --- a/js/src/tests/non262/String/well-formed.js +++ /dev/null @@ -1,26 +0,0 @@ -// |reftest| skip-if(!String.prototype.isWellFormed||!String.prototype.toWellFormed) - -assertEq("".isWellFormed(), true); -assertEq("abc".isWellFormed(), true); -assertEq("\uD83D\uDE00".isWellFormed(), true); -assertEq("\uD800".isWellFormed(), false); -assertEq("\uDC00".isWellFormed(), false); -assertEq("\uD800a".isWellFormed(), false); -assertEq("a\uDC00".isWellFormed(), false); -assertEq("\uD800\uD800\uDC00".isWellFormed(), false); - -assertEq("abc".toWellFormed(), "abc"); -assertEq("\uD83D\uDE00".toWellFormed(), "\uD83D\uDE00"); -assertEq("\uD800".toWellFormed(), "\uFFFD"); -assertEq("\uDC00".toWellFormed(), "\uFFFD"); -assertEq("\uD800a\uDC00".toWellFormed(), "\uFFFDa\uFFFD"); -assertEq("\uD800\uD800\uDC00".toWellFormed(), "\uFFFD\uD800\uDC00"); - -assertEq(String.prototype.isWellFormed.call(123), true); -assertEq(String.prototype.toWellFormed.call({ toString() { return "\uD800x"; } }), "\uFFFDx"); - -assertThrowsInstanceOf(() => String.prototype.isWellFormed.call(null), TypeError); -assertThrowsInstanceOf(() => String.prototype.toWellFormed.call(undefined), TypeError); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/non262/WeakMap/symbol-keys.js b/js/src/tests/non262/WeakMap/symbol-keys.js deleted file mode 100644 index 0edb542974..0000000000 --- a/js/src/tests/non262/WeakMap/symbol-keys.js +++ /dev/null @@ -1,36 +0,0 @@ -var key = Symbol("weak"); -var map = new WeakMap(); -assertEq(map.has(key), false); -assertEq(map.get(key), undefined); -assertEq(map.set(key, 13), map); -assertEq(map.has(key), true); -assertEq(map.get(key), 13); -assertEq(map.delete(key), true); -assertEq(map.has(key), false); - -var constructedKey = Symbol("constructed"); -var constructed = new WeakMap([[constructedKey, 7]]); -assertEq(constructed.get(constructedKey), 7); - -var registered = Symbol.for("registered"); -assertEq(map.has(registered), false); -assertEq(map.get(registered), undefined); -assertEq(map.delete(registered), false); -assertThrowsInstanceOf(() => map.set(registered, 1), TypeError); -assertThrowsInstanceOf(() => new WeakMap([[registered, 1]]), TypeError); - -var setKey = Symbol("set"); -var set = new WeakSet([setKey]); -assertEq(set.has(setKey), true); -assertEq(set.delete(setKey), true); -assertEq(set.has(setKey), false); -assertEq(set.add(setKey), set); -assertEq(set.has(setKey), true); - -assertEq(set.has(registered), false); -assertEq(set.delete(registered), false); -assertThrowsInstanceOf(() => set.add(registered), TypeError); -assertThrowsInstanceOf(() => new WeakSet([registered]), TypeError); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/tests/non262/collections/groupBy.js b/js/src/tests/non262/collections/groupBy.js deleted file mode 100644 index 121a899ede..0000000000 --- a/js/src/tests/non262/collections/groupBy.js +++ /dev/null @@ -1,34 +0,0 @@ -// |reftest| skip-if(!Object.groupBy||!Map.groupBy) - -var objectGroups = Object.groupBy(["a", "bb", "c"], value => value.length); -assertEq(Object.getPrototypeOf(objectGroups), null); -assertEqArray(objectGroups["1"], ["a", "c"]); -assertEqArray(objectGroups["2"], ["bb"]); - -var symbol = Symbol(); -var symbolGroups = Object.groupBy([1, 2], value => value === 1 ? symbol : "__proto__"); -assertEqArray(symbolGroups[symbol], [1]); -assertEqArray(symbolGroups.__proto__, [2]); - -var indexes = []; -var mapGroups = Map.groupBy(["a", "bb", "c"], (value, index) => { - indexes.push(index); - return value.length; -}); -assertEq(mapGroups instanceof Map, true); -assertEqArray(indexes, [0, 1, 2]); -assertEqArray(mapGroups.get(1), ["a", "c"]); -assertEqArray(mapGroups.get(2), ["bb"]); - -var key = {}; -var objectKeyGroups = Map.groupBy([1, 2], value => value === 1 ? key : NaN); -assertEqArray(objectKeyGroups.get(key), [1]); -assertEqArray(objectKeyGroups.get(NaN), [2]); - -assertThrowsInstanceOf(() => Object.groupBy(null, x => x), TypeError); -assertThrowsInstanceOf(() => Map.groupBy(undefined, x => x), TypeError); -assertThrowsInstanceOf(() => Object.groupBy([], null), TypeError); -assertThrowsInstanceOf(() => Map.groupBy([], null), TypeError); - -if (typeof reportCompare === "function") - reportCompare(0, 0); diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 666fc774df..e43edab690 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -22,7 +22,6 @@ # include #endif -#include #include "jsapi.h" #include "jsarray.h" #include "jscntxt.h" @@ -46,7 +45,6 @@ #include "vm/Interpreter.h" #include "vm/SelfHosting.h" #include "vm/SharedArrayObject.h" -#include "vm/TypedArrayObject.h" #include "vm/WrapperObject.h" #include "wasm/WasmSignalHandlers.h" #include "wasm/WasmTypes.h" @@ -172,18 +170,12 @@ static const JSPropertySpec static_properties[] = { static const JSFunctionSpec prototype_functions[] = { - JS_FN("resize", ArrayBufferObject::fun_resize, 1, 0), JS_SELF_HOSTED_FN("slice", "ArrayBufferSlice", 2, 0), - JS_FN("transfer", ArrayBufferObject::fun_transfer, 0, 0), - JS_FN("transferToFixedLength", ArrayBufferObject::fun_transferToFixedLength, 0, 0), JS_FS_END }; static const JSPropertySpec prototype_properties[] = { JS_PSG("byteLength", ArrayBufferObject::byteLengthGetter, 0), - JS_PSG("detached", ArrayBufferObject::detachedGetter, 0), - JS_PSG("maxByteLength", ArrayBufferObject::maxByteLengthGetter, 0), - JS_PSG("resizable", ArrayBufferObject::resizableGetter, 0), JS_STRING_SYM_PS(toStringTag, "ArrayBuffer", JSPROP_READONLY), JS_PS_END }; @@ -260,52 +252,6 @@ ArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* vp) return CallNonGenericMethod(cx, args); } -MOZ_ALWAYS_INLINE bool -ArrayBufferObject::detachedGetterImpl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsArrayBuffer(args.thisv())); - args.rval().setBoolean(args.thisv().toObject().as().isDetached()); - return true; -} - -bool -ArrayBufferObject::detachedGetter(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -MOZ_ALWAYS_INLINE bool -ArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsArrayBuffer(args.thisv())); - ArrayBufferObject& buffer = args.thisv().toObject().as(); - args.rval().setInt32(buffer.isDetached() ? 0 : int32_t(buffer.maxByteLength())); - return true; -} - -bool -ArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -MOZ_ALWAYS_INLINE bool -ArrayBufferObject::resizableGetterImpl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsArrayBuffer(args.thisv())); - args.rval().setBoolean(args.thisv().toObject().as().isResizable()); - return true; -} - -bool -ArrayBufferObject::resizableGetter(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - /* * ArrayBuffer.isView(obj); ES6 (Dec 2013 draft) 24.1.3.1 */ @@ -318,39 +264,6 @@ ArrayBufferObject::fun_isView(JSContext* cx, unsigned argc, Value* vp) return true; } -static bool -GetArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options, - uint32_t byteLength, uint32_t* maxByteLength, - bool* resizable) -{ - *maxByteLength = byteLength; - *resizable = false; - - if (!options.isObject()) - return true; - - RootedObject opts(cx, &options.toObject()); - RootedValue maxByteLengthValue(cx); - if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue)) - return false; - - if (maxByteLengthValue.isUndefined()) - return true; - - uint64_t max; - if (!ToIndex(cx, maxByteLengthValue, &max)) - return false; - - if (max > INT32_MAX || max < byteLength) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); - return false; - } - - *maxByteLength = uint32_t(max); - *resizable = true; - return true; -} - // ES2017 draft 24.1.2.1 bool @@ -374,22 +287,12 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) } // Step 3. - uint32_t maxByteLength; - bool resizable; - if (!GetArrayBufferMaxByteLengthOption(cx, args.get(1), uint32_t(byteLength), - &maxByteLength, &resizable)) - { - return false; - } - - // Step 4. RootedObject proto(cx); RootedObject newTarget(cx, &args.newTarget().toObject()); if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) return false; - JSObject* bufobj = create(cx, uint32_t(byteLength), BufferContents::createPlain(nullptr), - OwnsData, proto, GenericObject, maxByteLength, resizable); + JSObject* bufobj = create(cx, uint32_t(byteLength), proto); if (!bufobj) return false; args.rval().setObject(*bufobj); @@ -399,66 +302,13 @@ ArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) static ArrayBufferObject::BufferContents AllocateArrayBufferContents(JSContext* cx, uint32_t nbytes) { - uint8_t* p = cx->runtime()->pod_callocCanGC(nbytes ? nbytes : 1); + uint8_t* p = cx->runtime()->pod_callocCanGC(nbytes); if (!p) ReportOutOfMemory(cx); return ArrayBufferObject::BufferContents::create(p); } -static bool -ReportArrayBufferNotResizable(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_NOT_RESIZABLE); - return false; -} - -static bool -ReportArrayBufferCannotDetach(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARRAYBUFFER_CANNOT_DETACH); - return false; -} - -static bool -ReportArrayBufferLengthOutOfRange(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); - return false; -} - -static bool -ArrayBufferViewFits(ArrayBufferViewObject* view, uint32_t newByteLength) -{ - if (view->is()) { - DataViewObject& dataView = view->as(); - uint32_t byteOffset = dataView.byteOffsetMaybeOutOfBounds(); - if (byteOffset > newByteLength) - return false; - uint32_t byteLength = dataView.isLengthTracking() - ? newByteLength - byteOffset - : dataView.fixedByteLengthMaybeOutOfBounds(); - return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset; - } - - if (view->is()) { - TypedArrayObject& typedArray = view->as(); - if (typedArray.isSharedMemory()) - return true; - uint32_t byteOffset = typedArray.byteOffsetMaybeOutOfBounds(); - if (byteOffset > newByteLength) - return false; - uint32_t byteLength = typedArray.isLengthTracking() - ? newByteLength - byteOffset - : typedArray.fixedLengthMaybeOutOfBounds() * - typedArray.bytesPerElement(); - return byteOffset <= newByteLength && byteLength <= newByteLength - byteOffset; - } - - // Outline typed objects don't have a recoverable fixed byte range here. - return false; -} - static void NoteViewBufferWasDetached(ArrayBufferViewObject* view, ArrayBufferObject::BufferContents newContents, @@ -541,8 +391,7 @@ ArrayBufferObject::setNewData(FreeOp* fop, BufferContents newContents, OwnsState void ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view, - uint8_t* oldDataPointer, BufferContents newContents, - uint32_t newByteLength) + uint8_t* oldDataPointer, BufferContents newContents) { MOZ_ASSERT(!view->isSharedMemory()); @@ -553,18 +402,7 @@ ArrayBufferObject::changeViewContents(JSContext* cx, ArrayBufferViewObject* view uint8_t* viewDataPointer = view->dataPointerUnshared(nogc); if (viewDataPointer) { MOZ_ASSERT(newContents); - uint32_t offset; - if (view->is()) { - offset = view->as().byteOffsetMaybeOutOfBounds(); - } else if (view->is()) { - offset = view->as().byteOffsetMaybeOutOfBounds(); - } else { - ptrdiff_t oldOffset = viewDataPointer - oldDataPointer; - MOZ_ASSERT(oldOffset >= 0); - offset = uint32_t(oldOffset); - } - if (offset > newByteLength) - offset = 0; + ptrdiff_t offset = viewDataPointer - oldDataPointer; viewDataPointer = static_cast(newContents.data()) + offset; view->setDataPointerUnshared(viewDataPointer); } @@ -590,180 +428,10 @@ ArrayBufferObject::changeContents(JSContext* cx, BufferContents newContents, auto& innerViews = cx->compartment()->innerViews.get(); if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) { for (size_t i = 0; i < views->length(); i++) - changeViewContents(cx, (*views)[i], oldDataPointer, newContents, byteLength()); + changeViewContents(cx, (*views)[i], oldDataPointer, newContents); } if (firstView()) - changeViewContents(cx, firstView(), oldDataPointer, newContents, byteLength()); -} - -void -ArrayBufferObject::changeContentsForResize(JSContext* cx, BufferContents newContents, - OwnsState ownsState, uint32_t newByteLength) -{ - MOZ_RELEASE_ASSERT(!isWasm()); - MOZ_ASSERT(!forInlineTypedObject()); - - uint8_t* oldDataPointer = dataPointer(); - setNewData(cx->runtime()->defaultFreeOp(), newContents, ownsState); - setByteLength(newByteLength); - - auto& innerViews = cx->compartment()->innerViews.get(); - if (InnerViewTable::ViewVector* views = innerViews.maybeViewsUnbarriered(this)) { - for (size_t i = 0; i < views->length(); i++) { - ArrayBufferViewObject* view = (*views)[i]; - if (view->is() || view->is()) - changeViewContents(cx, view, oldDataPointer, newContents, newByteLength); - else if (ArrayBufferViewFits(view, newByteLength)) - changeViewContents(cx, view, oldDataPointer, newContents, newByteLength); - else - NoteViewBufferWasDetached(view, newContents, cx); - } - } - - if (firstView()) { - if (firstView()->is() || firstView()->is()) - changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength); - else if (ArrayBufferViewFits(firstView(), newByteLength)) - changeViewContents(cx, firstView(), oldDataPointer, newContents, newByteLength); - else - NoteViewBufferWasDetached(firstView(), newContents, cx); - } -} - -static bool -ResizeArrayBuffer(JSContext* cx, Handle buffer, uint32_t newByteLength) -{ - if (!buffer->isResizable()) - return ReportArrayBufferNotResizable(cx); - - if (buffer->isDetached()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - - if (newByteLength > buffer->maxByteLength()) - return ReportArrayBufferLengthOutOfRange(cx); - - if (!buffer->isPlain() || buffer->isPreparedForAsmJS() || buffer->forInlineTypedObject()) - return ReportArrayBufferCannotDetach(cx); - - if (newByteLength == buffer->byteLength()) - return true; - - ArrayBufferObject::BufferContents newContents = AllocateArrayBufferContents(cx, newByteLength); - if (!newContents) - return false; - - uint32_t copyLength = std::min(newByteLength, buffer->byteLength()); - if (copyLength > 0) - memcpy(newContents.data(), buffer->dataPointer(), copyLength); - - buffer->changeContentsForResize(cx, newContents, ArrayBufferObject::OwnsData, newByteLength); - return true; -} - -bool -ArrayBufferObject::fun_resize_impl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsArrayBuffer(args.thisv())); - - Rooted buffer(cx, &args.thisv().toObject().as()); - if (!buffer->isResizable()) - return ReportArrayBufferNotResizable(cx); - - uint64_t newByteLength; - if (!ToIndex(cx, args.get(0), &newByteLength)) - return false; - if (newByteLength > INT32_MAX) - return ReportArrayBufferLengthOutOfRange(cx); - - if (!ResizeArrayBuffer(cx, buffer, uint32_t(newByteLength))) - return false; - - args.rval().setUndefined(); - return true; -} - -bool -ArrayBufferObject::fun_resize(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -static bool -ArrayBufferTransfer(JSContext* cx, const CallArgs& args, bool preserveResizability) -{ - MOZ_ASSERT(IsArrayBuffer(args.thisv())); - Rooted buffer(cx, &args.thisv().toObject().as()); - - uint32_t newByteLength = buffer->byteLength(); - if (args.hasDefined(0)) { - uint64_t newLength; - if (!ToIndex(cx, args.get(0), &newLength)) - return false; - if (newLength > INT32_MAX) - return ReportArrayBufferLengthOutOfRange(cx); - newByteLength = uint32_t(newLength); - } - - if (buffer->isDetached()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - - if (buffer->isWasm() || buffer->isPreparedForAsmJS()) - return ReportArrayBufferCannotDetach(cx); - - bool newResizable = preserveResizability && buffer->isResizable(); - uint32_t newMaxByteLength = newResizable ? buffer->maxByteLength() : newByteLength; - if (newResizable && newByteLength > newMaxByteLength) - return ReportArrayBufferLengthOutOfRange(cx); - - Rooted newBuffer(cx, - ArrayBufferObject::create(cx, newByteLength, ArrayBufferObject::BufferContents::createPlain(nullptr), - ArrayBufferObject::OwnsData, nullptr, GenericObject, - newMaxByteLength, newResizable)); - if (!newBuffer) - return false; - - uint32_t copyLength = std::min(newByteLength, buffer->byteLength()); - if (copyLength > 0) - memcpy(newBuffer->dataPointer(), buffer->dataPointer(), copyLength); - - ArrayBufferObject::BufferContents detachedContents = - buffer->hasStealableContents() ? ArrayBufferObject::BufferContents::createPlain(nullptr) - : buffer->contents(); - ArrayBufferObject::detach(cx, buffer, detachedContents); - - args.rval().setObject(*newBuffer); - return true; -} - -bool -ArrayBufferObject::fun_transfer_impl(JSContext* cx, const CallArgs& args) -{ - return ArrayBufferTransfer(cx, args, true); -} - -bool -ArrayBufferObject::fun_transfer(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -bool -ArrayBufferObject::fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args) -{ - return ArrayBufferTransfer(cx, args, false); -} - -bool -ArrayBufferObject::fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + changeViewContents(cx, firstView(), oldDataPointer, newContents); } /* @@ -1219,14 +887,6 @@ ArrayBufferObject::byteLength() const return getSlot(BYTE_LENGTH_SLOT).toInt32(); } -uint32_t -ArrayBufferObject::maxByteLength() const -{ - if (!isResizable()) - return byteLength(); - return getSlot(MAX_BYTE_LENGTH_SLOT).toInt32(); -} - void ArrayBufferObject::setByteLength(uint32_t length) { @@ -1269,7 +929,7 @@ js::WasmArrayBufferMaxSize(const ArrayBufferObjectMaybeShared* buf) if (buf->is()) return buf->as().wasmMaxSize(); - return Some(buf->as().maxByteLength()); + return Some(buf->as().byteLength()); } /* static */ bool @@ -1375,12 +1035,9 @@ ArrayBufferObject* ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents contents, OwnsState ownsState /* = OwnsData */, HandleObject proto /* = nullptr */, - NewObjectKind newKind /* = GenericObject */, - uint32_t maxByteLength /* = 0 */, - bool resizable /* = false */) + NewObjectKind newKind /* = GenericObject */) { MOZ_ASSERT_IF(contents.kind() == MAPPED, contents); - MOZ_ASSERT_IF(resizable, maxByteLength >= nbytes); // 24.1.1.1, step 3 (Inlined 6.2.6.1 CreateByteDataBlock, step 2). // Refuse to allocate too large buffers, currently limited to ~2 GiB. @@ -1389,6 +1046,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content return nullptr; } + // If we need to allocate data, try to use a larger object size class so + // that the array buffer's data can be allocated inline with the object. + // The extra space will be left unused by the object's fixed slots and + // available for the buffer's data, see NewObject(). size_t reservedSlots = JSCLASS_RESERVED_SLOTS(&class_); size_t nslots = reservedSlots; @@ -1405,10 +1066,18 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content } } else { MOZ_ASSERT(ownsState == OwnsData); - contents = AllocateArrayBufferContents(cx, nbytes); - if (!contents) - return nullptr; - allocated = true; + size_t usableSlots = NativeObject::MAX_FIXED_SLOTS - reservedSlots; + if (nbytes <= usableSlots * sizeof(Value)) { + int newSlots = (nbytes - 1) / sizeof(Value) + 1; + MOZ_ASSERT(int(nbytes) <= newSlots * int(sizeof(Value))); + nslots = reservedSlots + newSlots; + contents = BufferContents::createPlain(nullptr); + } else { + contents = AllocateArrayBufferContents(cx, nbytes); + if (!contents) + return nullptr; + allocated = true; + } } MOZ_ASSERT(!(class_.flags & JSCLASS_HAS_PRIVATE)); @@ -1428,11 +1097,10 @@ ArrayBufferObject::create(JSContext* cx, uint32_t nbytes, BufferContents content if (!contents) { void* data = obj->inlineDataPointer(); - memset(data, 0, nbytes); - obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData, - maxByteLength, resizable); + js_memset(data, 0, nbytes); + obj->initialize(nbytes, BufferContents::createPlain(data), DoesntOwnData); } else { - obj->initialize(nbytes, contents, ownsState, maxByteLength, resizable); + obj->initialize(nbytes, contents, ownsState); } return obj; @@ -1462,28 +1130,25 @@ ArrayBufferObject::createEmpty(JSContext* cx) bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args) { - MOZ_ASSERT(IsAnyArrayBuffer(args.thisv())); + MOZ_ASSERT(IsArrayBuffer(args.thisv())); /* * This method is only called for |DataView(alienBuf, ...)| which calls * this as |createDataViewForThis.call(alienBuf, byteOffset, byteLength, - * DataView.prototype, lengthTracking)|, - * ergo there must be exactly 4 arguments. + * DataView.prototype)|, + * ergo there must be exactly 3 arguments. */ - MOZ_ASSERT(args.length() == 4); + MOZ_ASSERT(args.length() == 3); uint32_t byteOffset = args[0].toPrivateUint32(); uint32_t byteLength = args[1].toPrivateUint32(); - bool lengthTracking = args[3].toBoolean(); - Rooted buffer(cx, - &args.thisv().toObject().as()); + Rooted buffer(cx, &args.thisv().toObject().as()); /* * Pop off the passed-along prototype and delegate to normal DataViewObject * construction. */ - JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, - &args[2].toObject(), lengthTracking); + JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, &args[2].toObject()); if (!obj) return false; args.rval().setObject(*obj); @@ -1494,7 +1159,7 @@ bool ArrayBufferObject::createDataViewForThis(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); + return CallNonGenericMethod(cx, args); } /* static */ ArrayBufferObject::BufferContents @@ -1863,8 +1528,6 @@ ArrayBufferViewObject::trace(JSTracer* trc, JSObject* objArg) // The data may or may not be inline with the buffer. The buffer // can only move during a compacting GC, in which case its // objectMoved hook has already updated the buffer's data pointer. - if (offset > buf.byteLength()) - offset = 0; obj->initPrivate(buf.dataPointer() + offset); } } @@ -1915,8 +1578,6 @@ ArrayBufferViewObject::dataPointerUnshared(const JS::AutoRequireNoGC& nogc) bool ArrayBufferViewObject::isSharedMemory() { - if (is()) - return as().isSharedMemory(); if (is()) return as().isSharedMemory(); return false; @@ -1948,7 +1609,7 @@ ArrayBufferViewObject::bufferObject(JSContext* cx, Handleas().bufferEither(); } MOZ_ASSERT(thisObject->is()); - return &thisObject->as().arrayBufferEither(); + return &thisObject->as().arrayBuffer(); } /* JS Friend API */ @@ -2199,7 +1860,7 @@ JS_GetArrayBufferViewData(JSObject* obj, bool* isSharedMemory, const JS::AutoChe if (!obj) return nullptr; if (obj->is()) { - *isSharedMemory = obj->as().isSharedMemory(); + *isSharedMemory = false; return obj->as().dataPointer(); } TypedArrayObject& ta = obj->as(); @@ -2269,7 +1930,7 @@ js::GetArrayBufferViewLengthAndData(JSObject* obj, uint32_t* length, bool* isSha : obj->as().byteLength(); if (obj->is()) { - *isSharedMemory = obj->as().isSharedMemory(); + *isSharedMemory = false; *data = static_cast(obj->as().dataPointer()); } else { diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index f9e3353b7e..f4010c6c77 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -82,7 +82,7 @@ ArrayBufferObjectMaybeShared& AsAnyArrayBuffer(HandleValue val); class ArrayBufferObjectMaybeShared : public NativeObject { public: - uint32_t byteLength() const { + uint32_t byteLength() { return AnyArrayBufferByteLength(this); } @@ -128,22 +128,15 @@ typedef MutableHandle MutableHandleArrayBufferObj class ArrayBufferObject : public ArrayBufferObjectMaybeShared { static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args); - static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args); - static bool resizableGetterImpl(JSContext* cx, const CallArgs& args); - static bool detachedGetterImpl(JSContext* cx, const CallArgs& args); static bool fun_slice_impl(JSContext* cx, const CallArgs& args); - static bool fun_resize_impl(JSContext* cx, const CallArgs& args); - static bool fun_transfer_impl(JSContext* cx, const CallArgs& args); - static bool fun_transferToFixedLength_impl(JSContext* cx, const CallArgs& args); public: static const uint8_t DATA_SLOT = 0; static const uint8_t BYTE_LENGTH_SLOT = 1; static const uint8_t FIRST_VIEW_SLOT = 2; static const uint8_t FLAGS_SLOT = 3; - static const uint8_t MAX_BYTE_LENGTH_SLOT = 4; - static const uint8_t RESERVED_SLOTS = 5; + static const uint8_t RESERVED_SLOTS = 4; static const size_t ARRAY_BUFFER_ALIGNMENT = 8; @@ -196,11 +189,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared // This PLAIN or WASM buffer has been prepared for asm.js and cannot // henceforth be transferred/detached. - FOR_ASMJS = 0x40, - - // This buffer was created with [[ArrayBufferMaxByteLength]] and can - // be resized up to that maximum. - RESIZABLE = 0x80 + FOR_ASMJS = 0x40 }; static_assert(JS_ARRAYBUFFER_DETACHED_FLAG == DETACHED, @@ -241,14 +230,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared static const Class class_; static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp); - static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp); - static bool resizableGetter(JSContext* cx, unsigned argc, Value* vp); - static bool detachedGetter(JSContext* cx, unsigned argc, Value* vp); static bool fun_slice(JSContext* cx, unsigned argc, Value* vp); - static bool fun_resize(JSContext* cx, unsigned argc, Value* vp); - static bool fun_transfer(JSContext* cx, unsigned argc, Value* vp); - static bool fun_transferToFixedLength(JSContext* cx, unsigned argc, Value* vp); static bool fun_isView(JSContext* cx, unsigned argc, Value* vp); @@ -260,9 +243,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared BufferContents contents, OwnsState ownsState = OwnsData, HandleObject proto = nullptr, - NewObjectKind newKind = GenericObject, - uint32_t maxByteLength = 0, - bool resizable = false); + NewObjectKind newKind = GenericObject); static ArrayBufferObject* create(JSContext* cx, uint32_t nbytes, HandleObject proto = nullptr, NewObjectKind newKind = GenericObject); @@ -313,8 +294,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared void setNewData(FreeOp* fop, BufferContents newContents, OwnsState ownsState); void changeContents(JSContext* cx, BufferContents newContents, OwnsState ownsState); - void changeContentsForResize(JSContext* cx, BufferContents newContents, - OwnsState ownsState, uint32_t newByteLength); // Detach this buffer from its original memory. (This necessarily makes // views of this buffer unusable for modifying that original memory.) @@ -323,8 +302,7 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared private: void changeViewContents(JSContext* cx, ArrayBufferViewObject* view, - uint8_t* oldDataPointer, BufferContents newContents, - uint32_t newByteLength); + uint8_t* oldDataPointer, BufferContents newContents); void setFirstView(ArrayBufferViewObject* view); uint8_t* inlineDataPointer() const; @@ -333,7 +311,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared uint8_t* dataPointer() const; SharedMem dataPointerShared() const; uint32_t byteLength() const; - uint32_t maxByteLength() const; BufferContents contents() const { return BufferContents(dataPointer(), bufferKind()); @@ -357,7 +334,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared bool isWasm() const { return bufferKind() == WASM; } bool isMapped() const { return bufferKind() == MAPPED; } bool isDetached() const { return flags() & DETACHED; } - bool isResizable() const { return flags() & RESIZABLE; } bool isPreparedForAsmJS() const { return flags() & FOR_ASMJS; } // WebAssembly support: @@ -415,17 +391,12 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared void setIsDetached() { setFlags(flags() | DETACHED); } void setIsPreparedForAsmJS() { setFlags(flags() | FOR_ASMJS); } - void setIsResizable() { setFlags(flags() | RESIZABLE); } - void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState, - uint32_t maxByteLength = 0, bool resizable = false) { + void initialize(size_t byteLength, BufferContents contents, OwnsState ownsState) { setByteLength(byteLength); setFlags(0); - setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(maxByteLength ? maxByteLength : byteLength)); setFirstView(nullptr); setDataPointer(contents, ownsState); - if (resizable) - setIsResizable(); } // Note: initialize() may be called after initEmpty(); initEmpty() must @@ -433,7 +404,6 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared void initEmpty() { setByteLength(0); setFlags(0); - setFixedSlot(MAX_BYTE_LENGTH_SLOT, Int32Value(0)); setFirstView(nullptr); setDataPointer(BufferContents::createPlain(nullptr), DoesntOwnData); } diff --git a/js/src/vm/CommonPropertyNames.h b/js/src/vm/CommonPropertyNames.h index 82d49b201a..6edd49c6c0 100644 --- a/js/src/vm/CommonPropertyNames.h +++ b/js/src/vm/CommonPropertyNames.h @@ -248,7 +248,6 @@ macro(lookupSetter, lookupSetter, "__lookupSetter__") \ macro(MapConstructorInit, MapConstructorInit, "MapConstructorInit") \ macro(MapIterator, MapIterator, "Map Iterator") \ - macro(maxByteLength, maxByteLength, "maxByteLength") \ macro(maximumFractionDigits, maximumFractionDigits, "maximumFractionDigits") \ macro(maximumSignificantDigits, maximumSignificantDigits, "maximumSignificantDigits") \ macro(message, message, "message") \ diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 9d1dab322e..b3080d6edd 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -27,7 +27,6 @@ #include "builtin/SymbolObject.h" #include "builtin/TypedObject.h" #include "builtin/WeakMapObject.h" -#include "builtin/WeakRefObject.h" #include "builtin/WeakSetObject.h" #include "vm/Debugger.h" #include "vm/EnvironmentObject.h" @@ -465,7 +464,6 @@ GlobalObject::initStandardClasses(JSContext* cx, Handle global) if (!ensureConstructor(cx, global, static_cast(k))) return false; } - return true; } @@ -540,7 +538,6 @@ GlobalObject::initSelfHostingBuiltins(JSContext* cx, Handle globa InitBareBuiltinCtor(cx, global, JSProto_Int32Array) && InitBareSymbolCtor(cx, global) && InitBareWeakMapCtor(cx, global) && - InitBareWeakRefCtor(cx, global) && InitStopIterationClass(cx, global) && DefineFunctions(cx, global, builtins, AsIntrinsic); } diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index b34a20c91b..cde86fb829 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -43,22 +43,6 @@ static const ObjectElements emptyElementsHeaderShared(0, 0, ObjectElements::Shar HeapSlot* const js::emptyObjectElementsShared = reinterpret_cast(uintptr_t(&emptyElementsHeaderShared) + sizeof(ObjectElements)); -static const ObjectElements emptyElementsHeaderResizableOrGrowable( - 0, 0, ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER); - -/* Objects with no elements share one empty set of elements. */ -HeapSlot* const js::emptyObjectElementsResizableOrGrowable = - reinterpret_cast(uintptr_t(&emptyElementsHeaderResizableOrGrowable) + - sizeof(ObjectElements)); - -static const ObjectElements emptyElementsHeaderSharedResizableOrGrowable( - 0, 0, ObjectElements::SHARED_MEMORY | ObjectElements::RESIZABLE_OR_GROWABLE_BUFFER); - -/* Objects with no elements share one empty set of elements. */ -HeapSlot* const js::emptyObjectElementsSharedResizableOrGrowable = - reinterpret_cast(uintptr_t(&emptyElementsHeaderSharedResizableOrGrowable) + - sizeof(ObjectElements)); - #ifdef DEBUG @@ -77,12 +61,10 @@ ObjectElements::ConvertElementsToDoubles(JSContext* cx, uintptr_t elementsPtr) * This function is infallible, but has a fallible interface so that it can * be called directly from Ion code. Only arrays can have their dense * elements converted to doubles, and arrays never have empty elements. - */ + */ HeapSlot* elementsHeapPtr = (HeapSlot*) elementsPtr; MOZ_ASSERT(elementsHeapPtr != emptyObjectElements && - elementsHeapPtr != emptyObjectElementsShared && - elementsHeapPtr != emptyObjectElementsResizableOrGrowable && - elementsHeapPtr != emptyObjectElementsSharedResizableOrGrowable); + elementsHeapPtr != emptyObjectElementsShared); ObjectElements* header = ObjectElements::fromElements(elementsHeapPtr); MOZ_ASSERT(!header->shouldConvertDoubleElements()); diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 67fd3a7a46..86977d109f 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -185,11 +185,6 @@ class ObjectElements // These elements are set to integrity level "frozen". FROZEN = 0x10, - - // For TypedArrays only: this TypedArray views a resizable - // ArrayBuffer or growable SharedArrayBuffer. JIT fast paths with - // cached length/data assumptions must fall back for these objects. - RESIZABLE_OR_GROWABLE_BUFFER = 0x20, }; private: @@ -260,10 +255,6 @@ class ObjectElements : flags(SHARED_MEMORY), initializedLength(0), capacity(capacity), length(length) {} - constexpr ObjectElements(uint32_t capacity, uint32_t length, uint32_t flags) - : flags(flags), initializedLength(0), capacity(capacity), length(length) - {} - HeapSlot* elements() { return reinterpret_cast(uintptr_t(this) + sizeof(ObjectElements)); } @@ -278,10 +269,6 @@ class ObjectElements return flags & SHARED_MEMORY; } - bool hasResizableOrGrowableBuffer() const { - return flags & RESIZABLE_OR_GROWABLE_BUFFER; - } - GCPtrNativeObject& ownerObject() const { MOZ_ASSERT(isCopyOnWrite()); return *(GCPtrNativeObject*)(&elements()[initializedLength]); @@ -339,8 +326,6 @@ static_assert(ObjectElements::VALUES_PER_HEADER * sizeof(HeapSlot) == sizeof(Obj */ extern HeapSlot* const emptyObjectElements; extern HeapSlot* const emptyObjectElementsShared; -extern HeapSlot* const emptyObjectElementsResizableOrGrowable; -extern HeapSlot* const emptyObjectElementsSharedResizableOrGrowable; struct Class; class GCMarker; @@ -495,12 +480,6 @@ class NativeObject : public ShapedObject elements_ = emptyObjectElementsShared; } - void setHasResizableOrGrowableBuffer() { - MOZ_ASSERT(elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared); - elements_ = isSharedMemory() ? emptyObjectElementsSharedResizableOrGrowable - : emptyObjectElementsResizableOrGrowable; - } - bool isInWholeCellBuffer() const { const gc::TenuredCell* cell = &asTenured(); gc::ArenaCellSet* cells = cell->arena()->bufferedCells; @@ -1275,10 +1254,7 @@ class NativeObject : public ShapedObject } inline bool hasEmptyElements() const { - return elements_ == emptyObjectElements || - elements_ == emptyObjectElementsShared || - elements_ == emptyObjectElementsResizableOrGrowable || - elements_ == emptyObjectElementsSharedResizableOrGrowable; + return elements_ == emptyObjectElements || elements_ == emptyObjectElementsShared; } /* diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 24b23f19ff..26fd6cc9e1 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -38,7 +38,6 @@ #include "builtin/SelfHostingDefines.h" #include "builtin/Stream.h" #include "builtin/TypedObject.h" -#include "builtin/WeakRefObject.h" #include "builtin/WeakSetObject.h" #include "gc/Marking.h" #include "gc/Policy.h" @@ -106,14 +105,6 @@ intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp) return true; } -static bool -intrinsic_CanBeHeldWeakly(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - args.rval().setBoolean(CanBeHeldWeakly(args.get(0))); - return true; -} - static bool intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp) { @@ -279,20 +270,6 @@ intrinsic_GetBuiltinConstructor(JSContext* cx, unsigned argc, Value* vp) return true; } -static bool -intrinsic_NewMap(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 0); - - Rooted map(cx, MapObject::create(cx)); - if (!map) - return false; - - args.rval().setObject(*map); - return true; -} - static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) { @@ -1310,36 +1287,6 @@ intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, unsigned arg return true; } -static bool -intrinsic_TypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 1); - - RootedObject obj(cx, &args[0].toObject()); - MOZ_ASSERT(obj->is()); - args.rval().setBoolean(obj->as().isOutOfBounds()); - return true; -} - -static bool -intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - MOZ_ASSERT(args.length() == 1); - MOZ_ASSERT(args[0].isObject()); - - JSObject* obj = CheckedUnwrap(&args[0].toObject()); - if (!obj) { - JS_ReportErrorASCII(cx, "Permission denied to access object"); - return false; - } - - MOZ_ASSERT(obj->is()); - args.rval().setBoolean(obj->as().isOutOfBounds()); - return true; -} - static bool intrinsic_MoveTypedArrayElements(JSContext* cx, unsigned argc, Value* vp) { @@ -1462,10 +1409,6 @@ intrinsic_SetFromTypedArrayApproach(JSContext* cx, unsigned argc, Value* vp) JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); return false; } - if (unsafeTypedArrayCrossCompartment->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return false; - } // Steps 21, 23. uint32_t unsafeSrcLengthCrossCompartment = unsafeTypedArrayCrossCompartment->length(); @@ -2325,10 +2268,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin), JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs), - JS_FN("std_Map_create", intrinsic_NewMap, 0,0), - JS_FN("std_Map_get", MapObject::get, 1,0), JS_FN("std_Map_has", MapObject::has, 1,0), - JS_FN("std_Map_set", MapObject::set, 2,0), JS_FN("std_Map_iterator", MapObject::entries, 0,0), JS_FN("std_Number_valueOf", num_valueOf, 0,0), @@ -2376,7 +2316,6 @@ static const JSFunctionSpec intrinsic_functions[] = { // Helper funtions after this point. JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1,0, IntrinsicToObject), JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1,0, IntrinsicIsObject), - JS_FN("CanBeHeldWeakly", intrinsic_CanBeHeldWeakly, 1,0), JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1,0, ArrayIsArray), JS_INLINABLE_FN("IsWrappedArrayConstructor", intrinsic_IsWrappedArrayConstructor, 1,0, IntrinsicIsWrappedArrayConstructor), @@ -2536,10 +2475,6 @@ static const JSFunctionSpec intrinsic_functions[] = { 1, 0, IntrinsicPossiblyWrappedTypedArrayLength), JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer", intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0), - JS_FN("TypedArrayIsOutOfBounds", - intrinsic_TypedArrayIsOutOfBounds, 1, 0), - JS_FN("PossiblyWrappedTypedArrayIsOutOfBounds", - intrinsic_PossiblyWrappedTypedArrayIsOutOfBounds, 1, 0), JS_FN("MoveTypedArrayElements", intrinsic_MoveTypedArrayElements, 4,0), JS_FN("SetFromTypedArrayApproach",intrinsic_SetFromTypedArrayApproach, 4, 0), diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index a597564695..6a3c6a91c3 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -8,7 +8,6 @@ #include "mozilla/Atomics.h" #include "jsfriendapi.h" -#include "jsnum.h" #include "jsprf.h" #ifdef XP_WIN @@ -105,18 +104,15 @@ SharedArrayAllocSize(uint32_t length) } SharedArrayRawBuffer* -SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable) +SharedArrayRawBuffer::New(JSContext* cx, uint32_t length) { // The value (uint32_t)-1 is used as a signal in various places, // so guard against it on principle. MOZ_ASSERT(length != (uint32_t)-1); - MOZ_ASSERT(maxLength != (uint32_t)-1); - MOZ_ASSERT(maxLength >= length); // Add a page for the header and round to a page boundary. - uint32_t allocationLength = growable ? maxLength : length; - uint32_t allocSize = SharedArrayAllocSize(allocationLength); - if (allocSize <= allocationLength) + uint32_t allocSize = SharedArrayAllocSize(length); + if (allocSize <= length) return nullptr; // Test >= to guard against the case where multiple extant runtimes @@ -131,8 +127,7 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bo } } - bool preparedForAsmJS = - !growable && jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length); + bool preparedForAsmJS = jit::JitOptions.asmJSAtomicsEnable && IsValidAsmJSHeapLength(length); void* p = nullptr; if (preparedForAsmJS) { @@ -166,9 +161,8 @@ SharedArrayRawBuffer::New(JSContext* cx, uint32_t length, uint32_t maxLength, bo uint8_t* buffer = reinterpret_cast(p) + gc::SystemPageSize(); uint8_t* base = buffer - sizeof(SharedArrayRawBuffer); - SharedArrayRawBuffer* rawbuf = - new (base) SharedArrayRawBuffer(buffer, length, maxLength, growable, preparedForAsmJS); - MOZ_ASSERT(rawbuf->allocatedByteLength() == allocationLength); // Deallocation needs this. + SharedArrayRawBuffer* rawbuf = new (base) SharedArrayRawBuffer(buffer, length, preparedForAsmJS); + MOZ_ASSERT(rawbuf->length == length); // Deallocation needs this return rawbuf; } @@ -207,7 +201,7 @@ SharedArrayRawBuffer::dropReference() MOZ_ASSERT(p.asValue() % gc::SystemPageSize() == 0); uint8_t* address = p.unwrap(/*safe - only reference*/); - uint32_t allocSize = SharedArrayAllocSize(this->allocatedByteLength()); + uint32_t allocSize = SharedArrayAllocSize(this->length); if (this->preparedForAsmJS) { uint32_t mappedSize = SharedArrayMappedSize(allocSize); @@ -227,23 +221,6 @@ SharedArrayRawBuffer::dropReference() numLive--; } -bool -SharedArrayRawBuffer::growTo(uint32_t newLength) -{ - MOZ_ASSERT(growable); - MOZ_ASSERT(newLength <= maxLength); - - for (;;) { - uint32_t oldLength = length; - if (newLength < oldLength) - return false; - if (newLength == oldLength) - return true; - if (length.compareExchange(oldLength, newLength)) - return true; - } -} - MOZ_ALWAYS_INLINE bool SharedArrayBufferObject::byteLengthGetterImpl(JSContext* cx, const CallArgs& args) @@ -260,112 +237,6 @@ SharedArrayBufferObject::byteLengthGetter(JSContext* cx, unsigned argc, Value* v return CallNonGenericMethod(cx, args); } -MOZ_ALWAYS_INLINE bool -SharedArrayBufferObject::maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsSharedArrayBuffer(args.thisv())); - args.rval().setInt32(args.thisv().toObject().as().maxByteLength()); - return true; -} - -bool -SharedArrayBufferObject::maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -MOZ_ALWAYS_INLINE bool -SharedArrayBufferObject::growableGetterImpl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsSharedArrayBuffer(args.thisv())); - args.rval().setBoolean(args.thisv().toObject().as().isGrowable()); - return true; -} - -bool -SharedArrayBufferObject::growableGetter(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - -static bool -ReportSharedArrayBufferNotGrowable(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_NOT_GROWABLE); - return false; -} - -static bool -ReportSharedArrayBufferLengthOutOfRange(JSContext* cx) -{ - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH); - return false; -} - -static bool -GetSharedArrayBufferMaxByteLengthOption(JSContext* cx, HandleValue options, - uint32_t byteLength, uint32_t* maxByteLength, - bool* growable) -{ - *maxByteLength = byteLength; - *growable = false; - - if (!options.isObject()) - return true; - - RootedObject opts(cx, &options.toObject()); - RootedValue maxByteLengthValue(cx); - if (!GetProperty(cx, opts, opts, cx->names().maxByteLength, &maxByteLengthValue)) - return false; - - if (maxByteLengthValue.isUndefined()) - return true; - - uint64_t max; - if (!ToIndex(cx, maxByteLengthValue, &max)) - return false; - - if (max > INT32_MAX || max < byteLength) - return ReportSharedArrayBufferLengthOutOfRange(cx); - - *maxByteLength = uint32_t(max); - *growable = true; - return true; -} - -MOZ_ALWAYS_INLINE bool -SharedArrayBufferObject::fun_grow_impl(JSContext* cx, const CallArgs& args) -{ - MOZ_ASSERT(IsSharedArrayBuffer(args.thisv())); - - Rooted buffer(cx, - &args.thisv().toObject().as()); - if (!buffer->isGrowable()) - return ReportSharedArrayBufferNotGrowable(cx); - - uint64_t newByteLength; - if (!ToIndex(cx, args.get(0), &newByteLength)) - return false; - if (newByteLength > INT32_MAX) - return ReportSharedArrayBufferLengthOutOfRange(cx); - - uint32_t newLength = uint32_t(newByteLength); - if (newLength > buffer->maxByteLength() || !buffer->growTo(newLength)) - return ReportSharedArrayBufferLengthOutOfRange(cx); - - args.rval().setUndefined(); - return true; -} - -bool -SharedArrayBufferObject::fun_grow(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - return CallNonGenericMethod(cx, args); -} - bool SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* vp) { @@ -374,19 +245,11 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* if (!ThrowIfNotConstructing(cx, args, "SharedArrayBuffer")) return false; - uint64_t length64; - if (!ToIndex(cx, args.get(0), &length64)) - return false; // Bugs 1068458, 1161298: Limit length to 2^31-1. - if (length64 > INT32_MAX) - return ReportSharedArrayBufferLengthOutOfRange(cx); - uint32_t length = uint32_t(length64); - - uint32_t maxByteLength; - bool growable; - if (!GetSharedArrayBufferMaxByteLengthOption(cx, args.get(1), length, - &maxByteLength, &growable)) - { + uint32_t length; + bool overflow_unused; + if (!ToLengthClamped(cx, args.get(0), &length, &overflow_unused) || length > INT32_MAX) { + JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_SHARED_ARRAY_BAD_LENGTH); return false; } @@ -395,7 +258,7 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) return false; - JSObject* bufobj = New(cx, length, maxByteLength, growable, proto); + JSObject* bufobj = New(cx, length, proto); if (!bufobj) return false; args.rval().setObject(*bufobj); @@ -403,10 +266,9 @@ SharedArrayBufferObject::class_constructor(JSContext* cx, unsigned argc, Value* } SharedArrayBufferObject* -SharedArrayBufferObject::New(JSContext* cx, uint32_t length, uint32_t maxLength, bool growable, - HandleObject proto) +SharedArrayBufferObject::New(JSContext* cx, uint32_t length, HandleObject proto) { - SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length, maxLength, growable); + SharedArrayRawBuffer* buffer = SharedArrayRawBuffer::New(cx, length); if (!buffer) return nullptr; @@ -479,7 +341,7 @@ SharedArrayBufferObject::addSizeOfExcludingThis(JSObject* obj, mozilla::MallocSi // just live with the risk. const SharedArrayBufferObject& buf = obj->as(); info->objectsNonHeapElementsShared += - buf.rawBufferObject()->allocatedByteLength() / buf.rawBufferObject()->refcount(); + buf.byteLength() / buf.rawBufferObject()->refcount(); } /* static */ void @@ -547,15 +409,12 @@ static const JSPropertySpec static_properties[] = { }; static const JSFunctionSpec prototype_functions[] = { - JS_FN("grow", SharedArrayBufferObject::fun_grow, 1, 0), JS_SELF_HOSTED_FN("slice", "SharedArrayBufferSlice", 2, 0), JS_FS_END }; static const JSPropertySpec prototype_properties[] = { JS_PSG("byteLength", SharedArrayBufferObject::byteLengthGetter, 0), - JS_PSG("growable", SharedArrayBufferObject::growableGetter, 0), - JS_PSG("maxByteLength", SharedArrayBufferObject::maxByteLengthGetter, 0), JS_STRING_SYM_PS(toStringTag, "SharedArrayBuffer", JSPROP_READONLY), JS_PS_END }; diff --git a/js/src/vm/SharedArrayObject.h b/js/src/vm/SharedArrayObject.h index 01872aaff6..81fb49f3a8 100644 --- a/js/src/vm/SharedArrayObject.h +++ b/js/src/vm/SharedArrayObject.h @@ -44,9 +44,7 @@ class SharedArrayRawBuffer { private: mozilla::Atomic refcount_; - mozilla::Atomic length; - uint32_t maxLength; - bool growable; + uint32_t length; bool preparedForAsmJS; // A list of structures representing tasks waiting on some @@ -54,12 +52,9 @@ class SharedArrayRawBuffer FutexWaiter* waiters_; protected: - SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, uint32_t maxLength, bool growable, - bool preparedForAsmJS) + SharedArrayRawBuffer(uint8_t* buffer, uint32_t length, bool preparedForAsmJS) : refcount_(1), length(length), - maxLength(maxLength), - growable(growable), preparedForAsmJS(preparedForAsmJS), waiters_(nullptr) { @@ -67,11 +62,7 @@ class SharedArrayRawBuffer } public: - static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length, uint32_t maxLength, - bool growable); - static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length) { - return New(cx, length, length, false); - } + static SharedArrayRawBuffer* New(JSContext* cx, uint32_t length); // This may be called from multiple threads. The caller must take // care of mutual exclusion. @@ -94,20 +85,6 @@ class SharedArrayRawBuffer return length; } - uint32_t maxByteLength() const { - return growable ? maxLength : byteLength(); - } - - uint32_t allocatedByteLength() const { - return growable ? maxLength : byteLength(); - } - - bool isGrowable() const { - return growable; - } - - [[nodiscard]] bool growTo(uint32_t newLength); - bool isPreparedForAsmJS() const { return preparedForAsmJS; } @@ -140,9 +117,6 @@ class SharedArrayRawBuffer class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared { static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args); - static bool maxByteLengthGetterImpl(JSContext* cx, const CallArgs& args); - static bool growableGetterImpl(JSContext* cx, const CallArgs& args); - static bool fun_grow_impl(JSContext* cx, const CallArgs& args); public: // RAWBUF_SLOT holds a pointer (as "private" data) to the @@ -154,23 +128,13 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared static const Class class_; static bool byteLengthGetter(JSContext* cx, unsigned argc, Value* vp); - static bool maxByteLengthGetter(JSContext* cx, unsigned argc, Value* vp); - static bool growableGetter(JSContext* cx, unsigned argc, Value* vp); - static bool fun_grow(JSContext* cx, unsigned argc, Value* vp); static bool class_constructor(JSContext* cx, unsigned argc, Value* vp); // Create a SharedArrayBufferObject with a new SharedArrayRawBuffer. static SharedArrayBufferObject* New(JSContext* cx, uint32_t length, - uint32_t maxLength, - bool growable, HandleObject proto = nullptr); - static SharedArrayBufferObject* New(JSContext* cx, - uint32_t length, - HandleObject proto = nullptr) { - return New(cx, length, length, false, proto); - } // Create a SharedArrayBufferObject using an existing SharedArrayRawBuffer. static SharedArrayBufferObject* New(JSContext* cx, @@ -200,15 +164,6 @@ class SharedArrayBufferObject : public ArrayBufferObjectMaybeShared uint32_t byteLength() const { return rawBufferObject()->byteLength(); } - uint32_t maxByteLength() const { - return rawBufferObject()->maxByteLength(); - } - bool isGrowable() const { - return rawBufferObject()->isGrowable(); - } - [[nodiscard]] bool growTo(uint32_t newLength) { - return rawBufferObject()->growTo(newLength); - } bool isPreparedForAsmJS() const { return rawBufferObject()->isPreparedForAsmJS(); } diff --git a/js/src/vm/StructuredClone.cpp b/js/src/vm/StructuredClone.cpp index 50e6162923..e1f1b2777e 100644 --- a/js/src/vm/StructuredClone.cpp +++ b/js/src/vm/StructuredClone.cpp @@ -45,7 +45,6 @@ #include "builtin/MapObject.h" #include "js/Date.h" #include "js/GCHashTable.h" -#include "vm/ArrayBufferObject-inl.h" #include "vm/SavedFrame.h" #include "vm/SharedArrayObject.h" #include "vm/TypedArrayObject.h" diff --git a/js/src/vm/TypedArrayCommon.h b/js/src/vm/TypedArrayCommon.h index 056f8b52be..fab7210417 100644 --- a/js/src/vm/TypedArrayCommon.h +++ b/js/src/vm/TypedArrayCommon.h @@ -1065,40 +1065,16 @@ class TypedArrayMethods if (!ToInt32(cx, args[1], &offset)) return false; - if (offset < 0) { + if (offset < 0 || uint32_t(offset) > target->length()) { + // the given offset is bogus JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX); return false; } } - if (target->hasDetachedBuffer()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - if (target->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return false; - } - - uint32_t targetLength = target->length(); - if (uint32_t(offset) > targetLength) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_INDEX); - return false; - } - RootedObject arg0(cx, &args[0].toObject()); if (arg0->is()) { - Rooted source(cx, &arg0->as()); - if (source->hasDetachedBuffer()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - if (source->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return false; - } - - if (source->length() > targetLength - offset) { + if (arg0->as().length() > target->length() - offset) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); return false; } @@ -1110,7 +1086,7 @@ class TypedArrayMethods if (!GetLengthProperty(cx, arg0, &len)) return false; - if (len > targetLength - offset) { + if (uint32_t(offset) > target->length() || len > target->length() - offset) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_ARRAY_LENGTH); return false; } @@ -1123,32 +1099,13 @@ class TypedArrayMethods return true; } - static bool - setFromTypedArray(JSContext* cx, Handle target, HandleObject source, - uint32_t offset = 0) - { - MOZ_ASSERT(source->is(), "use setFromNonTypedArray"); + static bool + setFromTypedArray(JSContext* cx, Handle target, HandleObject source, + uint32_t offset = 0) + { + MOZ_ASSERT(source->is(), "use setFromNonTypedArray"); - if (target->hasDetachedBuffer()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - if (target->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return false; - } - - Rooted sourceArray(cx, &source->as()); - if (sourceArray->hasDetachedBuffer()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); - return false; - } - if (sourceArray->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return false; - } - - bool isShared = target->isSharedMemory() || sourceArray->isSharedMemory(); + bool isShared = target->isSharedMemory() || source->as().isSharedMemory(); switch (target->type()) { case Scalar::Int8: diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 22d21c8550..faf3dc40df 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -484,9 +484,8 @@ class TypedArrayObjectTemplate : public TypedArrayObject } static TypedArrayObject* - makeInstance(JSContext* cx, Handle buffer, - uint32_t byteOffset, uint32_t len, HandleObject proto, - bool lengthTracking = false) + makeInstance(JSContext* cx, Handle buffer, uint32_t byteOffset, uint32_t len, + HandleObject proto) { MOZ_ASSERT_IF(!buffer, byteOffset == 0); @@ -511,19 +510,12 @@ class TypedArrayObjectTemplate : public TypedArrayObject return nullptr; bool isSharedMemory = buffer && IsSharedArrayBuffer(buffer.get()); - bool hasResizableOrGrowableBuffer = - buffer && - ((buffer->is() && buffer->as().isResizable()) || - (buffer->is() && - buffer->as().isGrowable())); obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectOrNullValue(buffer)); // This is invariant. Self-hosting code that sets BUFFER_SLOT // (if it does) must maintain it, should it need to. if (isSharedMemory) obj->setIsSharedMemory(); - if (hasResizableOrGrowableBuffer) - obj->setHasResizableOrGrowableBuffer(); if (buffer) { obj->initViewData(buffer->dataPointerEither() + byteOffset); @@ -557,9 +549,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject #endif } - obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, - Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING - : int32_t(len))); + obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(len)); obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset)); #ifdef DEBUG @@ -908,7 +898,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject return nullptr; // invalid byteOffset } - bool lengthTracking = false; uint32_t len; if (lengthInt == -1) { len = (buffer->byteLength() - byteOffset) / sizeof(NativeType); @@ -917,12 +906,6 @@ class TypedArrayObjectTemplate : public TypedArrayObject JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS); return nullptr; // given byte array doesn't map exactly to sizeof(NativeType) * N } - if ((buffer->is() && buffer->as().isResizable()) || - (buffer->is() && - buffer->as().isGrowable())) - { - lengthTracking = true; - } } else { len = uint32_t(lengthInt); } @@ -941,7 +924,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject return nullptr; // byteOffset + len is too big for the arraybuffer } - return makeInstance(cx, buffer, byteOffset, len, proto, lengthTracking); + return makeInstance(cx, buffer, byteOffset, len, proto); } static bool @@ -1337,10 +1320,6 @@ TypedArrayObjectTemplate::fromTypedArray(JSContext* cx, HandleObject other, b JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); return nullptr; } - if (srcArray->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_OUT_OF_BOUNDS); - return nullptr; - } // Step 9. uint32_t elementLength = srcArray->length(); @@ -1880,8 +1859,7 @@ DataViewNewObjectKind(JSContext* cx, uint32_t byteLength, JSObject* proto) DataViewObject* DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, - Handle arrayBuffer, JSObject* protoArg, - bool lengthTracking) + Handle arrayBuffer, JSObject* protoArg) { if (arrayBuffer->isDetached()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); @@ -1890,18 +1868,8 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, MOZ_ASSERT(byteOffset <= INT32_MAX); MOZ_ASSERT(byteLength <= INT32_MAX); - - uint32_t bufferByteLength = arrayBuffer->byteLength(); - if (byteOffset > bufferByteLength || - (!lengthTracking && byteLength > bufferByteLength - byteOffset)) - { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, - "1"); - return nullptr; - } - - if (lengthTracking) - byteLength = bufferByteLength - byteOffset; + MOZ_ASSERT(byteOffset + byteLength < UINT32_MAX); + MOZ_ASSERT(!arrayBuffer || !arrayBuffer->is()); RootedObject proto(cx, protoArg); RootedObject obj(cx); @@ -1925,72 +1893,57 @@ DataViewObject::create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, } } + // Caller should have established these preconditions, and no + // (non-self-hosted) JS code has had an opportunity to run so nothing can + // have invalidated them. MOZ_ASSERT(byteOffset <= arrayBuffer->byteLength()); MOZ_ASSERT(byteOffset + byteLength <= arrayBuffer->byteLength()); DataViewObject& dvobj = obj->as(); dvobj.setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT, Int32Value(byteOffset)); - dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, - Int32Value(lengthTracking ? TypedArrayObject::LENGTH_TRACKING - : int32_t(byteLength))); + dvobj.setFixedSlot(TypedArrayObject::LENGTH_SLOT, Int32Value(byteLength)); dvobj.setFixedSlot(TypedArrayObject::BUFFER_SLOT, ObjectValue(*arrayBuffer)); - auto dataPointer = arrayBuffer->dataPointerEither(); - dvobj.initPrivate((dataPointer + byteOffset).unwrap(/*safe - stored as private data*/)); + dvobj.initPrivate(arrayBuffer->dataPointer() + byteOffset); // Include a barrier if the data view's data pointer is in the nursery, as // is done for typed arrays. - if (arrayBuffer->is() && - !IsInsideNursery(obj) && - cx->runtime()->gc.nursery.isInside(dataPointer)) - { + if (!IsInsideNursery(obj) && cx->runtime()->gc.nursery.isInside(arrayBuffer->dataPointer())) cx->runtime()->gc.storeBuffer.putWholeCell(obj); - } // Verify that the private slot is at the expected place MOZ_ASSERT(dvobj.numFixedSlots() == TypedArrayObject::DATA_SLOT); - if (arrayBuffer->is()) { - if (!arrayBuffer->as().addView(cx, &dvobj)) - return nullptr; - } + if (!arrayBuffer->addView(cx, &dvobj)) + return nullptr; return &dvobj; } bool DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args, - uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr, - bool* lengthTrackingPtr) + uint32_t* byteOffsetPtr, uint32_t* byteLengthPtr) { - if (!IsAnyArrayBuffer(bufobj)) { + if (!IsArrayBuffer(bufobj)) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_NOT_EXPECTED_TYPE, - "DataView", "ArrayBuffer or SharedArrayBuffer", - bufobj->getClass()->name); + "DataView", "ArrayBuffer", bufobj->getClass()->name); return false; } - Rooted buffer(cx, &bufobj->as()); + Rooted buffer(cx, &AsArrayBuffer(bufobj)); uint32_t byteOffset = 0; uint32_t byteLength = buffer->byteLength(); - bool isResizableOrGrowable = - (buffer->is() && buffer->as().isResizable()) || - (buffer->is() && - buffer->as().isGrowable()); - bool lengthTracking = isResizableOrGrowable && !args.hasDefined(2); if (args.length() > 1) { - uint64_t offset; - if (!ToIndex(cx, args[1], &offset)) + if (!ToUint32(cx, args[1], &byteOffset)) return false; - if (offset > INT32_MAX) { + if (byteOffset > INT32_MAX) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "1"); return false; } - byteOffset = uint32_t(offset); } - if (buffer->is() && buffer->as().isDetached()) { + if (buffer->isDetached()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); return false; } @@ -2004,18 +1957,14 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons if (args.get(2).isUndefined()) { byteLength -= byteOffset; - lengthTracking = isResizableOrGrowable; } else { - uint64_t viewByteLength; - if (!ToIndex(cx, args[2], &viewByteLength)) + if (!ToUint32(cx, args[2], &byteLength)) return false; - lengthTracking = false; - if (viewByteLength > INT32_MAX) { + if (byteLength > INT32_MAX) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, "2"); return false; } - byteLength = uint32_t(viewByteLength); MOZ_ASSERT(byteOffset + byteLength >= byteOffset, "can't overflow: both numbers are less than INT32_MAX"); @@ -2034,7 +1983,6 @@ DataViewObject::getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, cons *byteOffsetPtr = byteOffset; *byteLengthPtr = byteLength; - *lengthTrackingPtr = lengthTracking; return true; } @@ -2046,8 +1994,7 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con assertSameCompartment(cx, bufobj); uint32_t byteOffset, byteLength; - bool lengthTracking; - if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength, &lengthTracking)) + if (!getAndCheckConstructorArgs(cx, bufobj, args, &byteOffset, &byteLength)) return false; RootedObject proto(cx); @@ -2055,9 +2002,8 @@ DataViewObject::constructSameCompartment(JSContext* cx, HandleObject bufobj, con if (!GetPrototypeFromConstructor(cx, newTarget, &proto)) return false; - Rooted buffer(cx, &bufobj->as()); - JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto, - lengthTracking); + Rooted buffer(cx, &AsArrayBuffer(bufobj)); + JSObject* obj = DataViewObject::create(cx, byteOffset, byteLength, buffer, proto); if (!obj) return false; args.rval().setObject(*obj); @@ -2097,12 +2043,8 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA // NB: This entails the IsArrayBuffer check uint32_t byteOffset, byteLength; - bool lengthTracking; - if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength, - &lengthTracking)) - { + if (!getAndCheckConstructorArgs(cx, unwrapped, args, &byteOffset, &byteLength)) return false; - } // Make sure to get the [[Prototype]] for the created view from this // compartment. @@ -2118,12 +2060,11 @@ DataViewObject::constructWrapped(JSContext* cx, HandleObject bufobj, const CallA return false; } - FixedInvokeArgs<4> args2(cx); + FixedInvokeArgs<3> args2(cx); args2[0].set(PrivateUint32Value(byteOffset)); args2[1].set(PrivateUint32Value(byteLength)); args2[2].setObject(*proto); - args2[3].setBoolean(lengthTracking); RootedValue fval(cx, global->createDataViewForThis()); RootedValue thisv(cx, ObjectValue(*bufobj)); @@ -2151,11 +2092,6 @@ template /* static */ uint8_t* DataViewObject::getDataPointer(JSContext* cx, Handle obj, uint64_t offset) { - if (obj->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS); - return nullptr; - } - const size_t TypeSize = sizeof(NativeType); if (offset > UINT32_MAX - TypeSize || offset + TypeSize > obj->byteLength()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_ARG_INDEX_OUT_OF_RANGE, @@ -2319,7 +2255,7 @@ DataViewObject::read(JSContext* cx, Handle obj, bool isLittleEndian = args.length() >= 2 && ToBoolean(args[1]); // Steps 6-7. - if (obj->arrayBufferEither().isDetached()) { + if (obj->arrayBuffer().isDetached()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); return false; } @@ -2418,7 +2354,7 @@ DataViewObject::write(JSContext* cx, Handle obj, bool isLittleEndian = args.length() >= 3 && ToBoolean(args[2]); // Steps 7-8. - if (obj->arrayBufferEither().isDetached()) { + if (obj->arrayBuffer().isDetached()) { JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_DETACHED); return false; } @@ -3243,13 +3179,7 @@ template bool DataViewObject::getterImpl(JSContext* cx, const CallArgs& args) { - Rooted view(cx, &args.thisv().toObject().as()); - if (ValueGetter != bufferValue && view->isOutOfBounds()) { - JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_DATA_VIEW_OUT_OF_BOUNDS); - return false; - } - - args.rval().set(ValueGetter(view)); + args.rval().set(ValueGetter(&args.thisv().toObject().as())); return true; } diff --git a/js/src/vm/TypedArrayObject.h b/js/src/vm/TypedArrayObject.h index 8c08bb870e..8b4b0b5092 100644 --- a/js/src/vm/TypedArrayObject.h +++ b/js/src/vm/TypedArrayObject.h @@ -52,8 +52,6 @@ class TypedArrayObject : public NativeObject "right buffer slot"); // Slot containing length of the view in number of typed elements. - // Length-tracking views on resizable/growable buffers store - // LENGTH_TRACKING here and compute their visible length from the buffer. static const size_t LENGTH_SLOT = 1; static_assert(LENGTH_SLOT == JS_TYPEDARRAYLAYOUT_LENGTH_SLOT, "self-hosted code with burned-in constants must get the " @@ -67,8 +65,6 @@ class TypedArrayObject : public NativeObject static const size_t RESERVED_SLOTS = 3; - static const int32_t LENGTH_TRACKING = -1; - #ifdef DEBUG static const uint8_t ZeroLengthArrayData = 0x4A; #endif @@ -143,13 +139,15 @@ class TypedArrayObject : public NativeObject return tarr->getFixedSlot(BUFFER_SLOT); } static Value byteOffsetValue(TypedArrayObject* tarr) { - return Int32Value(tarr->byteOffset()); + Value v = tarr->getFixedSlot(BYTEOFFSET_SLOT); + MOZ_ASSERT(v.toInt32() >= 0); + return v; } static Value byteLengthValue(TypedArrayObject* tarr) { - return Int32Value(tarr->byteLength()); + return Int32Value(tarr->getFixedSlot(LENGTH_SLOT).toInt32() * tarr->bytesPerElement()); } static Value lengthValue(TypedArrayObject* tarr) { - return Int32Value(tarr->length()); + return tarr->getFixedSlot(LENGTH_SLOT); } static bool @@ -161,70 +159,14 @@ class TypedArrayObject : public NativeObject JSObject* bufferObject() const { return bufferValue(const_cast(this)).toObjectOrNull(); } - bool isLengthTracking() const { - return getFixedSlot(LENGTH_SLOT).toInt32() == LENGTH_TRACKING; - } - bool hasResizableOrGrowableBuffer() const { - if (!hasBuffer()) - return false; - if (isSharedMemory()) - return bufferShared()->isGrowable(); - return bufferUnshared()->isResizable(); - } - uint32_t byteOffsetMaybeOutOfBounds() const { - Value v = getFixedSlot(BYTEOFFSET_SLOT); - MOZ_ASSERT(v.toInt32() >= 0); - return v.toInt32(); - } - uint32_t fixedLengthMaybeOutOfBounds() const { - int32_t length = getFixedSlot(LENGTH_SLOT).toInt32(); - MOZ_ASSERT(length >= 0); - return length; - } - uint32_t bufferByteLength() const { - MOZ_ASSERT(hasBuffer()); - if (isSharedMemory()) - return bufferShared()->byteLength(); - return bufferUnshared()->byteLength(); - } - bool isOutOfBounds() const { - if (!hasBuffer()) - return false; - if (hasDetachedBuffer()) - return true; - - uint32_t bufferByteLength = this->bufferByteLength(); - uint32_t offset = byteOffsetMaybeOutOfBounds(); - if (offset > bufferByteLength) - return true; - - if (isLengthTracking()) - return false; - - uint32_t byteLength = fixedLengthMaybeOutOfBounds() * bytesPerElement(); - return byteLength > bufferByteLength - offset; - } uint32_t byteOffset() const { - if (isOutOfBounds()) - return 0; - return byteOffsetMaybeOutOfBounds(); + return byteOffsetValue(const_cast(this)).toInt32(); } uint32_t byteLength() const { - return length() * bytesPerElement(); + return byteLengthValue(const_cast(this)).toInt32(); } uint32_t length() const { - if (!isLengthTracking()) { - if (isOutOfBounds()) - return 0; - return fixedLengthMaybeOutOfBounds(); - } - - if (isOutOfBounds()) - return 0; - - uint32_t bufferByteLength = this->bufferByteLength(); - uint32_t offset = byteOffsetMaybeOutOfBounds(); - return (bufferByteLength - offset) / bytesPerElement(); + return lengthValue(const_cast(this)).toInt32(); } bool hasInlineElements() const; @@ -524,26 +466,28 @@ class DataViewObject : public NativeObject defineGetter(JSContext* cx, PropertyName* name, HandleNativeObject proto); static bool getAndCheckConstructorArgs(JSContext* cx, JSObject* bufobj, const CallArgs& args, - uint32_t *byteOffset, uint32_t* byteLength, - bool* lengthTracking); + uint32_t *byteOffset, uint32_t* byteLength); static bool constructSameCompartment(JSContext* cx, HandleObject bufobj, const CallArgs& args); static bool constructWrapped(JSContext* cx, HandleObject bufobj, const CallArgs& args); friend bool ArrayBufferObject::createDataViewForThisImpl(JSContext* cx, const CallArgs& args); static DataViewObject* create(JSContext* cx, uint32_t byteOffset, uint32_t byteLength, - Handle arrayBuffer, JSObject* proto, - bool lengthTracking = false); + Handle arrayBuffer, JSObject* proto); public: static const Class class_; static Value byteOffsetValue(DataViewObject* view) { - return Int32Value(view->byteOffset()); + Value v = view->getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT); + MOZ_ASSERT(v.toInt32() >= 0); + return v; } static Value byteLengthValue(DataViewObject* view) { - return Int32Value(view->byteLength()); + Value v = view->getFixedSlot(TypedArrayObject::LENGTH_SLOT); + MOZ_ASSERT(v.toInt32() >= 0); + return v; } static Value bufferValue(DataViewObject* view) { @@ -551,66 +495,21 @@ class DataViewObject : public NativeObject } uint32_t byteOffset() const { - if (isOutOfBounds()) - return 0; - return byteOffsetMaybeOutOfBounds(); + return byteOffsetValue(const_cast(this)).toInt32(); } uint32_t byteLength() const { - if (isOutOfBounds()) - return 0; - if (isLengthTracking()) - return arrayBufferEither().byteLength() - byteOffsetMaybeOutOfBounds(); - return fixedByteLengthMaybeOutOfBounds(); + return byteLengthValue(const_cast(this)).toInt32(); } - ArrayBufferObjectMaybeShared& arrayBufferEither() const { - return bufferValue(const_cast(this)). - toObject().as(); - } - - bool isSharedMemory() const { - return bufferValue(const_cast(this)). - toObject().is(); + ArrayBufferObject& arrayBuffer() const { + return bufferValue(const_cast(this)).toObject().as(); } void* dataPointer() const { return getPrivate(); } - bool isLengthTracking() const { - return getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32() == - TypedArrayObject::LENGTH_TRACKING; - } - - uint32_t byteOffsetMaybeOutOfBounds() const { - Value v = getFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT); - MOZ_ASSERT(v.toInt32() >= 0); - return v.toInt32(); - } - - uint32_t fixedByteLengthMaybeOutOfBounds() const { - int32_t length = getFixedSlot(TypedArrayObject::LENGTH_SLOT).toInt32(); - MOZ_ASSERT(length >= 0); - return length; - } - - bool isOutOfBounds() const { - const ArrayBufferObjectMaybeShared& buffer = arrayBufferEither(); - if (buffer.isDetached()) - return true; - - uint32_t bufferByteLength = buffer.byteLength(); - uint32_t offset = byteOffsetMaybeOutOfBounds(); - if (offset > bufferByteLength) - return true; - - if (isLengthTracking()) - return false; - - return fixedByteLengthMaybeOutOfBounds() > bufferByteLength - offset; - } - static bool class_constructor(JSContext* cx, unsigned argc, Value* vp); static bool getInt8Impl(JSContext* cx, const CallArgs& args); diff --git a/js/xpconnect/src/XPCJSContext.cpp b/js/xpconnect/src/XPCJSContext.cpp index 9365937fdd..3ca3da6b8b 100644 --- a/js/xpconnect/src/XPCJSContext.cpp +++ b/js/xpconnect/src/XPCJSContext.cpp @@ -1446,7 +1446,6 @@ ReloadPrefsCallback(const char* pref, void* data) bool extraWarnings = Preferences::GetBool(JS_OPTIONS_DOT_STR "strict"); bool streams = Preferences::GetBool(JS_OPTIONS_DOT_STR "streams"); - bool weakRefs = Preferences::GetBool(JS_OPTIONS_DOT_STR "weakrefs"); bool unboxedObjects = Preferences::GetBool(JS_OPTIONS_DOT_STR "unboxed_objects"); @@ -1473,8 +1472,7 @@ ReloadPrefsCallback(const char* pref, void* data) .setWerror(werror) .setExtraWarnings(extraWarnings) .setArrayProtoValues(arrayProtoValues) - .setStreams(streams) - .setWeakRefs(weakRefs); + .setStreams(streams); JS_SetParallelParsingEnabled(cx, parallelParsing); JS_SetOffthreadIonCompilationEnabled(cx, offthreadIonCompilation); diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 54d89a7abb..e13c9e94c9 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -9,7 +9,7 @@ * * Platform-specific #ifdefs at the end of this file override the generic * entries at the top. - * + */ /* * SYNTAX HINTS: @@ -639,7 +639,7 @@ pref("layout.event-regions.enabled", false); // gfx/layers/apz/src/AsyncPanZoomController.cpp. pref("apz.allow_checkerboarding", true); pref("apz.allow_immediate_handoff", true); -pref("apz.allow_zooming", true); +pref("apz.allow_zooming", false); // Whether to lock touch scrolling to one axis at a time // 0 = FREE (No locking at all) @@ -651,7 +651,7 @@ pref("apz.axis_lock.breakout_threshold", "0.03125"); // 1/32 inches pref("apz.axis_lock.breakout_angle", "0.3926991"); // PI / 8 (22.5 degrees) pref("apz.axis_lock.direct_pan_angle", "1.047197"); // PI / 3 (60 degrees) pref("apz.content_response_timeout", 400); -pref("apz.drag.enabled", true); +pref("apz.drag.enabled", false); pref("apz.danger_zone_x", 50); pref("apz.danger_zone_y", 100); pref("apz.disable_for_scroll_linked_effects", false); @@ -710,7 +710,7 @@ pref("apz.zoom_animation_duration_ms", 250); pref("apz.scale_repaint_delay_ms", 500); #if !defined(MOZ_WIDGET_UIKIT) -pref("apz.desktop.enabled", true); +pref("apz.desktop.enabled", false); #endif #ifdef XP_MACOSX @@ -1348,9 +1348,6 @@ pref("javascript.options.dynamicImport", true); // Streams API pref("javascript.options.streams", true); -// Enable garbage collection of weakrefed objects -pref("javascript.options.weakrefs", false); - // advanced prefs pref("advanced.mailftp", false); pref("image.animation_mode", "normal");