diff --git a/README.md b/README.md
index e9429949b9..2c69459f92 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-Official Discord server | Official Telegram channel
+Official Discord server
-
+
Dactyloidae is a heavily modified fork of Eclipse Hydra (fork of roytam1's Serpent, which is a fork of Basilisk, which is a fork of Firefox).
diff --git a/browser/branding/unofficial/pref/uaoverrides.inc b/browser/branding/unofficial/pref/uaoverrides.inc
index e2659ecbe1..f1f9451981 100644
--- a/browser/branding/unofficial/pref/uaoverrides.inc
+++ b/browser/branding/unofficial/pref/uaoverrides.inc
@@ -65,9 +65,9 @@ pref("@GUAO_PREF@.mewe.com", "Mozilla/5.0 (%OS_SLICE% rv:102.0) Gecko/20100101 F
// UA-sniffing domains that are "app/vendor-specific" and do not like Dactyloidae
pref("@GUAO_PREF@.web.whatsapp.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36");
-pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
-pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
-pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (%OS_SLICE%; Win64; x64; rv:147.0) Gecko/20100101 Firefox/147.0");
+pref("@GUAO_PREF@.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
+pref("@GUAO_PREF@.studio.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
+pref("@GUAO_PREF@.gaming.youtube.com","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36");
// The following domains do not like the Goanna slice
pref("@GUAO_PREF@.bab.la","Mozilla/5.0 (%OS_SLICE% rv:@GK_VERSION@) @GK_SLICE@ @FX_SLICE@");
diff --git a/browser/config/version.txt b/browser/config/version.txt
index ceedae9682..c059982684 100644
--- a/browser/config/version.txt
+++ b/browser/config/version.txt
@@ -1 +1 @@
-52.13.2.1
\ No newline at end of file
+52.13.2
\ No newline at end of file
diff --git a/browser/config/version_display.txt b/browser/config/version_display.txt
index 16b080e5b3..4092290770 100644
--- a/browser/config/version_display.txt
+++ b/browser/config/version_display.txt
@@ -1 +1 @@
-13.2.1
\ No newline at end of file
+13.2
\ No newline at end of file
diff --git a/docs/readme/demo.png b/docs/readme/demo.png
deleted file mode 100644
index af13017634..0000000000
Binary files a/docs/readme/demo.png and /dev/null differ
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/nsDOMTokenList.cpp b/dom/base/nsDOMTokenList.cpp
index 02acabacac..87fb11e8c7 100644
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -127,29 +127,7 @@ void
nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
const nsTArray& aTokens)
{
- if (!mElement || aTokens.IsEmpty()) {
- return;
- }
-
- // Hot path: single-token classList.add() when the class is already present.
- // Skip attribute rebuild and SetAttr entirely (avoids mutation observers /
- // style invalidation). Frameworks hit this constantly.
- if (aTokens.Length() == 1) {
- const nsString& token = aTokens[0];
- if (aAttr && aAttr->Contains(token)) {
- return;
- }
-
- nsAutoString resultStr;
- if (aAttr) {
- aAttr->ToString(resultStr);
- if (!resultStr.IsEmpty() &&
- !nsContentUtils::IsHTMLWhitespace(resultStr.Last())) {
- resultStr.Append(' ');
- }
- }
- resultStr.Append(token);
- mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
+ if (!mElement) {
return;
}
@@ -183,11 +161,6 @@ nsDOMTokenList::AddInternal(const nsAttrValue* aAttr,
addedClasses.AppendElement(aToken);
}
- // No new tokens: leave the attribute untouched (do not create class="").
- if (!oneWasAdded) {
- return;
- }
-
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, resultStr, true);
}
@@ -217,37 +190,20 @@ nsDOMTokenList::RemoveInternal(const nsAttrValue* aAttr,
{
MOZ_ASSERT(aAttr, "Need an attribute");
- if (aTokens.IsEmpty()) {
- return;
- }
-
- // Hot path: single-token classList.remove() when the class is absent.
- if (aTokens.Length() == 1 && !aAttr->Contains(aTokens[0])) {
- return;
- }
-
nsAutoString input;
aAttr->ToString(input);
WhitespaceTokenizer tokenizer(input);
nsAutoString output;
- bool removed = false;
while (tokenizer.hasMoreTokens()) {
auto& currentToken = tokenizer.nextToken();
- if (aTokens.Contains(currentToken)) {
- removed = true;
- continue;
+ if (!aTokens.Contains(currentToken)) {
+ if (!output.IsEmpty()) {
+ output.Append(char16_t(' '));
+ }
+ output.Append(currentToken);
}
- if (!output.IsEmpty()) {
- output.Append(char16_t(' '));
- }
- output.Append(currentToken);
- }
-
- // Token set unchanged: skip SetAttr to avoid style/mutation work.
- if (!removed) {
- return;
}
mElement->SetAttr(kNameSpaceID_None, mAttrAtom, output, true);
@@ -346,16 +302,6 @@ nsDOMTokenList::ReplaceInternal(const nsAttrValue* aAttr,
const nsAString& aToken,
const nsAString& aNewToken)
{
- // Replacing a token with itself cannot change the token set.
- if (aToken.Equals(aNewToken)) {
- return;
- }
-
- // Old token absent: no update (and avoid rewriting whitespace).
- if (!aAttr->Contains(aToken)) {
- return;
- }
-
nsAutoString attribute;
aAttr->ToString(attribute);
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/base/nsINode.cpp b/dom/base/nsINode.cpp
index 740c18417f..5218938ca3 100644
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -2927,35 +2927,6 @@ FindMatchingElementsWithId(const nsAString& aId, nsINode* aRoot,
// Actually find elements matching aSelectorList (which must not be
// null) and which are descendants of aRoot and put them in aList. If
// onlyFirstMatch, then stop once the first one is found.
-template
-static void
-FindMatchingElementsWithClass(nsINode* aRoot, nsIAtom* aClass,
- nsCaseTreatment aCaseTreatment, T& aList)
-{
- Collector results;
- for (nsIContent* cur = aRoot->GetFirstChild(); cur;
- cur = cur->GetNextNode(aRoot)) {
- if (!cur->IsElement()) {
- continue;
- }
- const nsAttrValue* classes = cur->AsElement()->GetClasses();
- if (classes && classes->Contains(aClass, aCaseTreatment)) {
- if (onlyFirstMatch) {
- aList.AppendElement(cur->AsElement());
- return;
- }
- results.AppendElement(cur->AsElement());
- }
- }
- const uint32_t len = results.Length();
- if (len) {
- aList.SetCapacity(len);
- for (uint32_t i = 0; i < len; ++i) {
- aList.AppendElement(results.ElementAt(i));
- }
- }
-}
-
template
MOZ_ALWAYS_INLINE static void
FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList,
@@ -2963,23 +2934,6 @@ FindMatchingElements(nsINode* aRoot, nsCSSSelectorList* aSelectorList, T &aList,
{
nsIDocument* doc = aRoot->OwnerDoc();
- // Parsed selectors are already cached by the document. A lone class needs
- // only an atom lookup per element, not the general CSS matching context.
- nsCSSSelector* selector = aSelectorList->mSelectors;
- if (!aSelectorList->mNext && !selector->mNext &&
- selector->mClassList && !selector->mClassList->mNext &&
- !selector->mLowercaseTag && !selector->mIDList &&
- !selector->mAttrList && !selector->mPseudoClassList &&
- !selector->mNegations && selector->mNameSpace == kNameSpaceID_Unknown &&
- selector->IsRestrictedSelector() && !selector->IsHybridPseudoElement()) {
- nsCaseTreatment caseTreatment =
- doc->GetCompatibilityMode() == eCompatibility_NavQuirks
- ? eIgnoreCase : eCaseMatters;
- FindMatchingElementsWithClass(
- aRoot, selector->mClassList->mAtom, caseTreatment, aList);
- return;
- }
-
TreeMatchContext matchingContext(false, nsRuleWalker::eRelevantLinkUnvisited,
doc, TreeMatchContext::eNeverMatchVisited);
doc->FlushPendingLinkUpdates();
diff --git a/dom/base/test/file_class_selector_checks.js b/dom/base/test/file_class_selector_checks.js
deleted file mode 100644
index 0be76bc6ef..0000000000
--- a/dom/base/test/file_class_selector_checks.js
+++ /dev/null
@@ -1,59 +0,0 @@
-function checkClassSelectors(parse, equal) {
- function check(root, selector, expected) {
- var all = root.querySelectorAll(selector);
- equal(all.length, expected.length, selector + " count");
- for (var i = 0; i < expected.length; i++) {
- equal(all[i].id, expected[i], selector + " order " + i);
- }
- equal(root.querySelector(selector), all.length ? all[0] : null,
- selector + " first match");
- }
-
- var doc = parse('' +
- '' +
- '
' +
- '' +
- '' +
- '', 'text/html');
- var root = doc.getElementById('root');
- for (var repeat = 0; repeat < 10; repeat++) {
- check(root, '.toggle', ['a', 'b', 'd', 'svg']);
- check(root, '*|*.toggle', ['a', 'b', 'd', 'svg']);
- check(root, '.t\\6f ggle', ['a', 'b', 'd', 'svg']);
- check(root, '.TOGGLE', ['c']);
- check(root, '.missing', []);
- check(root, '.toggle.completed', ['a']);
- check(root, 'button.toggle', ['d']);
- check(root, '.toggle:not(.completed)', ['b', 'd', 'svg']);
- check(root, '.toggle, .other', ['a', 'b', 'd', 'svg']);
- }
- check(doc, '.toggle', ['root', 'a', 'b', 'd', 'svg']);
-
- var snapshot = root.querySelectorAll('.toggle');
- doc.getElementById('a').className = '';
- root.removeChild(doc.getElementById('d'));
- doc.getElementById('c').className = 'toggle';
- check(root, '.toggle', ['b', 'c', 'svg']);
- equal(snapshot.length, 4, 'querySelectorAll remains a static snapshot');
- equal(snapshot[0].id, 'a', 'snapshot retains a changed element');
- equal(snapshot[2].id, 'd', 'snapshot retains a removed element');
-
- var fragment = doc.createDocumentFragment();
- fragment.appendChild(root);
- check(fragment, '.toggle', ['root', 'b', 'c', 'svg']);
- check(root, '.toggle', ['b', 'c', 'svg']);
-
- var quirks = parse('' +
- '', 'text/html');
- equal(quirks.compatMode, 'BackCompat', 'quirks document');
- check(quirks, '.toggle', ['lower', 'upper']);
- check(quirks, '.TOGGLE', ['lower', 'upper']);
-
- var xml = parse(' ' +
- ' ' +
- ' ',
- 'application/xml');
- check(xml, '.toggle', ['plain', 'namespaced']);
- check(xml, '|*.toggle', ['plain']);
- check(xml, '*|*.toggle', ['plain', 'namespaced']);
-}
diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini
index f903dc5a3d..6f5e0ea835 100644
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -1,6 +1,5 @@
[DEFAULT]
support-files =
- file_class_selector_checks.js
audio.ogg
audioEndedDuringPlaying.webm
iframe_bug962251.html
@@ -616,7 +615,6 @@ skip-if = os == "mac" # Different tab focus behavior on mac
[test_caretPositionFromPoint.html]
[test_change_policy.html]
[test_classList.html]
-[test_class_selector_fast_path.html]
[test_clearTimeoutIntervalNoArg.html]
[test_constructor-assignment.html]
[test_constructor.html]
diff --git a/dom/base/test/test_class_selector_fast_path.html b/dom/base/test/test_class_selector_fast_path.html
deleted file mode 100644
index 3eb87d2cf2..0000000000
--- a/dom/base/test/test_class_selector_fast_path.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-Class selector query fast path
-
-
-
diff --git a/dom/console/ConsoleAPIStorage.js b/dom/console/ConsoleAPIStorage.js
index b17c6855ec..31be449e91 100644
--- a/dom/console/ConsoleAPIStorage.js
+++ b/dom/console/ConsoleAPIStorage.js
@@ -94,24 +94,13 @@ ConsoleAPIStorageService.prototype = {
getEvents: function CS_getEvents(aId)
{
if (aId != null) {
- let storage = _consoleStorage.get(aId);
- if (!storage) {
- return [];
- }
- let { events, next } = storage;
- return next === 0 ? events.slice() :
- events.slice(next).concat(events.slice(0, next));
+ return (_consoleStorage.get(aId) || []).slice(0);
}
let result = [];
- for (let { events, next } of _consoleStorage.values()) {
- for (let i = next; i < events.length; i++) {
- result.push(events[i]);
- }
- for (let i = 0; i < next; i++) {
- result.push(events[i]);
- }
+ for (let [id, events] of _consoleStorage) {
+ result.push.apply(result, events);
}
return result.sort(function(a, b) {
@@ -133,21 +122,16 @@ ConsoleAPIStorageService.prototype = {
*/
recordEvent: function CS_recordEvent(aId, aOuterId, aEvent)
{
- let storage = _consoleStorage.get(aId);
- if (!storage) {
- storage = { events: [], next: 0 };
- _consoleStorage.set(aId, storage);
+ if (!_consoleStorage.has(aId)) {
+ _consoleStorage.set(aId, []);
}
- // Overwrite the oldest event once full, without moving the other entries.
- // Advance before notifying observers, which may read or reenter storage.
- if (storage.events.length < STORAGE_MAX_EVENTS) {
- storage.events.push(aEvent);
- } else {
- storage.events[storage.next] = aEvent;
- if (++storage.next === STORAGE_MAX_EVENTS) {
- storage.next = 0;
- }
+ let storage = _consoleStorage.get(aId);
+ storage.push(aEvent);
+
+ // truncate
+ if (storage.length > STORAGE_MAX_EVENTS) {
+ storage.shift();
}
Services.obs.notifyObservers(aEvent, "console-api-log-event", aOuterId);
diff --git a/dom/console/moz.build b/dom/console/moz.build
index ce2ae8d054..d18b089626 100644
--- a/dom/console/moz.build
+++ b/dom/console/moz.build
@@ -40,6 +40,5 @@ LOCAL_INCLUDES += [
MOCHITEST_MANIFESTS += [ 'tests/mochitest.ini' ]
MOCHITEST_CHROME_MANIFESTS += [ 'tests/chrome.ini' ]
-XPCSHELL_TESTS_MANIFESTS += [ 'tests/xpcshell.ini' ]
FINAL_LIBRARY = 'xul'
diff --git a/dom/console/tests/test_console_storage_ring.js b/dom/console/tests/test_console_storage_ring.js
deleted file mode 100644
index a4e3dbeee8..0000000000
--- a/dom/console/tests/test_console_storage_ring.js
+++ /dev/null
@@ -1,53 +0,0 @@
-function run_test() {
- const storage = Components.classes["@mozilla.org/consoleAPI-storage;1"]
- .getService(Components.interfaces.nsIConsoleAPIStorage);
- Components.utils.import("resource://gre/modules/Services.jsm");
- storage.clearEvents();
- try {
- for (let i = 0; i < 3501; i++) {
- storage.recordEvent("ring-test", "outer", { timeStamp: i });
- if (i === 998 || i === 999 || i === 1000 || i === 1999 || i === 3500) {
- let events = storage.getEvents("ring-test");
- equal(events.length, Math.min(i + 1, 1000));
- for (let j = 0; j < events.length; j++) {
- equal(events[j].timeStamp, i + 1 - events.length + j);
- }
- events.length = 0;
- equal(storage.getEvents("ring-test").length, Math.min(i + 1, 1000));
- }
- }
- storage.recordEvent("other", "outer", { timeStamp: 2500.5 });
- let all = storage.getEvents();
- equal(all.length, 1001);
- equal(all[0].timeStamp, 2500.5);
- equal(all[1].timeStamp, 2501);
- equal(all[1000].timeStamp, 3500);
-
- let reentered = false;
- let observer = {
- observe(subject, topic, data) {
- if (data === "ring-test" && !reentered) {
- equal(storage.getEvents(data)[999].timeStamp, 3501);
- reentered = true;
- storage.recordEvent("ring-test", "outer", { timeStamp: 3502 });
- }
- }
- };
- Services.obs.addObserver(observer, "console-storage-cache-event", false);
- try {
- storage.recordEvent("ring-test", "outer", { timeStamp: 3501 });
- } finally {
- Services.obs.removeObserver(observer, "console-storage-cache-event");
- }
- equal(reentered, true);
- equal(storage.getEvents("ring-test")[999].timeStamp, 3502);
- storage.clearEvents("ring-test");
- equal(storage.getEvents("ring-test").length, 0);
- equal(storage.getEvents("other").length, 1);
- storage.recordEvent("ring-test", "outer", { timeStamp: 4000 });
- equal(storage.getEvents("ring-test")[0].timeStamp, 4000);
- } finally {
- storage.clearEvents();
- }
- equal(storage.getEvents().length, 0);
-}
diff --git a/dom/console/tests/xpcshell.ini b/dom/console/tests/xpcshell.ini
deleted file mode 100644
index 7d3af0c96c..0000000000
--- a/dom/console/tests/xpcshell.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[DEFAULT]
-head =
-tail =
-
-[test_console_storage_ring.js]
diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
index acf5027949..c0b970e58a 100644
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -2334,7 +2334,8 @@ ScriptLoader::EvaluateScript(ScriptLoadRequest* aRequest)
}
if (aRequest->IsModuleRequest()) {
- AutoCurrentScriptUpdater scriptUpdater(this, aRequest->Element());
+ // For modules, currentScript is set to null.
+ AutoCurrentScriptUpdater scriptUpdater(this, nullptr);
ModuleLoadRequest* request = aRequest->AsModuleRequest();
MOZ_ASSERT(request->mModuleScript);
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/image/imgLoader.cpp b/image/imgLoader.cpp
index 5725fd9648..904eaaab2d 100644
--- a/image/imgLoader.cpp
+++ b/image/imgLoader.cpp
@@ -952,38 +952,12 @@ using namespace std;
void
imgCacheQueue::Remove(imgCacheEntry* entry)
{
- uint64_t index = mQueue.IndexOf(entry);
- if (index == queueContainer::NoIndex) {
- return;
+ queueContainer::iterator it = find(mQueue.begin(), mQueue.end(), entry);
+ if (it != mQueue.end()) {
+ mSize -= (*it)->GetDataSize();
+ mQueue.erase(it);
+ MarkDirty();
}
-
- mSize -= mQueue[index]->GetDataSize();
-
- // If the queue is clean and this is the first entry,
- // then we can efficiently remove the entry without
- // dirtying the sort order.
- if (!IsDirty() && index == 0) {
- std::pop_heap(mQueue.begin(), mQueue.end(),
- imgLoader::CompareCacheEntries);
- mQueue.RemoveElementAt(mQueue.Length() - 1);
- return;
- }
-
- // Remove from the middle of the list. This potentially
- // breaks the binary heap sort order.
- mQueue.RemoveElementAt(index);
-
- // If we only have one entry or the queue is empty, though,
- // then the sort order is still effectively good.
- // Simply refresh the list to clear the dirty flag.
- if (mQueue.Length() <= 1) {
- Refresh();
- return;
- }
-
- // Otherwise we must mark the queue dirty and potentially
- // trigger an expensive sort later.
- MarkDirty();
}
void
@@ -992,26 +966,23 @@ imgCacheQueue::Push(imgCacheEntry* entry)
mSize += entry->GetDataSize();
RefPtr refptr(entry);
- mQueue.AppendElement(Move(refptr));
- // If we're not dirty already, then we can efficiently add this to the binary heap immediately.
- if (!IsDirty()) {
- std::push_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
- }
+ mQueue.push_back(refptr);
+ MarkDirty();
}
already_AddRefed
imgCacheQueue::Pop()
{
- if (mQueue.IsEmpty()) {
+ if (mQueue.empty()) {
return nullptr;
}
if (IsDirty()) {
Refresh();
}
+ RefPtr entry = mQueue[0];
std::pop_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
- RefPtr entry = Move(mQueue.LastElement());
- mQueue.RemoveElementAt(mQueue.Length() - 1);
+ mQueue.pop_back();
mSize -= entry->GetDataSize();
return entry.forget();
@@ -1020,7 +991,6 @@ imgCacheQueue::Pop()
void
imgCacheQueue::Refresh()
{
- // Re-heap the list. This is an O(3 * n) operation and best avoided if possible.
std::make_heap(mQueue.begin(), mQueue.end(), imgLoader::CompareCacheEntries);
mDirty = false;
}
@@ -1040,13 +1010,7 @@ imgCacheQueue::IsDirty()
uint32_t
imgCacheQueue::GetNumElements() const
{
- return mQueue.Length();
-}
-
-bool
-imgCacheQueue::Contains(imgCacheEntry* aEntry) const
-{
- return mQueue.Contains(aEntry);
+ return mQueue.size();
}
imgCacheQueue::iterator
@@ -1638,11 +1602,7 @@ void
imgLoader::CacheEntriesChanged(bool aForChrome, int32_t aSizeDiff /* = 0 */)
{
imgCacheQueue& queue = GetCacheQueue(aForChrome);
- // We only need to dirty the queue if there is any sorting taking place.
- // Empty or single-entry lists can't become dirty.
- if (queue.GetNumElements() > 1) {
- queue.MarkDirty();
- }
+ queue.MarkDirty();
queue.UpdateSize(aSizeDiff);
}
@@ -1671,9 +1631,7 @@ imgLoader::CheckCacheLimits(imgCacheTable& cache, imgCacheQueue& queue)
}
if (entry) {
- // We just popped this entry from the queue, so pass AlreadyRemoved
- // to avoid searching the queue again in RemoveFromCache.
- RemoveFromCache(entry, QueueState::AlreadyRemoved);
+ RemoveFromCache(entry);
}
}
}
@@ -1972,7 +1930,7 @@ imgLoader::RemoveFromCache(const ImageCacheKey& aKey)
}
bool
-imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
+imgLoader::RemoveFromCache(imgCacheEntry* entry)
{
LOG_STATIC_FUNC(gImgLog, "imgLoader::RemoveFromCache entry");
@@ -1988,24 +1946,13 @@ imgLoader::RemoveFromCache(imgCacheEntry* entry, QueueState aQueueState)
cache.Remove(key);
- if (queue.IsDirty()) {
- queue.Refresh();
- }
-
if (entry->HasNoProxies()) {
LOG_STATIC_FUNC(gImgLog,
"imgLoader::RemoveFromCache removing from tracker");
if (mCacheTracker) {
mCacheTracker->RemoveObject(entry);
}
- // Only search the queue to remove the entry if its possible it might
- // be in the queue. If we know its not in the queue this would be
- // wasted work.
- MOZ_ASSERT_IF(aQueueState == QueueState::AlreadyRemoved,
- !queue.Contains(entry));
- if (aQueueState == QueueState::MaybeExists) {
- queue.Remove(entry);
- }
+ queue.Remove(entry);
}
entry->SetEvicted(true);
@@ -2050,13 +1997,13 @@ imgLoader::EvictEntries(imgCacheQueue& aQueueToClear)
// We have to make a temporary, since RemoveFromCache removes the element
// from the queue, invalidating iterators.
nsTArray > entries(aQueueToClear.GetNumElements());
- for (auto i = aQueueToClear.begin(); i != aQueueToClear.end(); ++i) {
+ for (imgCacheQueue::const_iterator i = aQueueToClear.begin();
+ i != aQueueToClear.end(); ++i) {
entries.AppendElement(*i);
}
- // Iterate in reverse order to minimize array copying.
- for (auto& entry : entries) {
- if (!RemoveFromCache(entry)) {
+ for (uint32_t i = 0; i < entries.Length(); ++i) {
+ if (!RemoveFromCache(entries[i])) {
return NS_ERROR_FAILURE;
}
}
diff --git a/image/imgLoader.h b/image/imgLoader.h
index 8557e92bd1..7349a666e5 100644
--- a/image/imgLoader.h
+++ b/image/imgLoader.h
@@ -178,8 +178,7 @@ public:
uint32_t GetSize() const;
void UpdateSize(int32_t diff);
uint32_t GetNumElements() const;
- bool Contains(imgCacheEntry* aEntry) const;
- typedef nsTArray > queueContainer;
+ typedef std::vector > queueContainer;
typedef queueContainer::iterator iterator;
typedef queueContainer::const_iterator const_iterator;
@@ -317,16 +316,7 @@ public:
nsresult InitCache();
bool RemoveFromCache(const ImageCacheKey& aKey);
-
- // Enumeration describing if a given entry is in the cache queue or not.
- // There are some cases we know the entry is definitely not in the queue.
- enum class QueueState {
- MaybeExists,
- AlreadyRemoved
- };
-
- bool RemoveFromCache(imgCacheEntry* entry,
- QueueState aQueueState = QueueState::MaybeExists);
+ bool RemoveFromCache(imgCacheEntry* entry);
bool PutIntoCache(const ImageCacheKey& aKey, imgCacheEntry* aEntry);
diff --git a/js/src/builtin/Array.js b/js/src/builtin/Array.js
index 9a6022f340..54446d2578 100644
--- a/js/src/builtin/Array.js
+++ b/js/src/builtin/Array.js
@@ -253,67 +253,6 @@ function ArraySort(comparefn) {
return MergeSort(O, len, comparefn);
}
-// ES2023 22.1.3.30 Array.prototype.toSorted ( comparefn )
-function ArrayToSorted(comparefn) {
- if (comparefn !== undefined) {
- if (!IsCallable(comparefn)) {
- ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn));
- }
- }
-
- // Step 1: Let O be ? ToObject(this). Let len be ? ToLength(O.length).
- var O = ToObject(this);
- var len = ToLength(O.length);
-
- // Step 2: Snapshot values in ascending index order into a List.
- var items = new List();
- var itemsLen = len;
- for (var k = 0; k < len; k++) {
- items[k] = O[k];
- }
-
- // Step 3: Create SortCompare per spec.
- var wrappedCompareFn = comparefn;
- var sortCompare;
- if (wrappedCompareFn === undefined) {
- sortCompare = function(x, y) {
- if (x === undefined)
- return y === undefined ? 0 : 1;
- if (y === undefined)
- return -1;
-
- var xString = ToString(x);
- var yString = ToString(y);
- if (xString < yString)
- return -1;
- if (xString > yString)
- return 1;
- return 0;
- };
- } else {
- sortCompare = function(x, y) {
- if (x === undefined)
- return y === undefined ? 0 : 1;
- if (y === undefined)
- return -1;
-
- var v = ToNumber(wrappedCompareFn(x, y));
- return v !== v ? 0 : v;
- };
- }
-
- // Step 4: Sort the snapshot List using SortCompare.
- if (itemsLen > 1)
- MergeSort(items, itemsLen, sortCompare);
-
- // Step 5: Create result array and write sorted values.
- var A = ArraySpeciesCreate(O, len);
- for (var j = 0; j < itemsLen; j++)
- _DefineDataProperty(A, j, items[j]);
-
- return A;
-}
-
/* ES5 15.4.4.18. */
function ArrayForEach(callbackfn/*, thisArg*/) {
/* Step 1. */
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 8c5afa9f5e..434cd6529b 100644
--- a/js/src/builtin/Map.js
+++ b/js/src/builtin/Map.js
@@ -55,50 +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.
- // Group values are always arrays, so undefined also tells us whether
- // this is a new key without a second hash-table lookup.
- var elements = callFunction(std_Map_get, groups, key);
- if (elements !== undefined) {
- 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