зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central. a=merge
This commit is contained in:
Коммит
4a15041348
|
@ -205,7 +205,6 @@ module.exports = {
|
|||
excludedFiles: [
|
||||
// These are suitable as good first bugs, take one or two related lines
|
||||
// per bug.
|
||||
"caps/tests/unit/test_origin.js",
|
||||
"extensions/permissions/**",
|
||||
"image/test/unit/**",
|
||||
"intl/uconv/tests/unit/test_bug340714.js",
|
||||
|
|
|
@ -1598,6 +1598,12 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flagset"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.24"
|
||||
|
@ -5780,40 +5786,46 @@ version = "0.2.100"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-encoder"
|
||||
version = "0.7.0"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49cfbd7c23474849807ecde008c82eb38d303b07ec61d48f45b65f3c8cdd2770"
|
||||
checksum = "f76068e87fe9b837a6bc2ccded66784173eadb828c4168643e9fddf6f9ed2e61"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-smith"
|
||||
version = "0.8.0"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "440458e050ee2731e85af3368ee58e23d4728d597809a88f841a24778876f2b6"
|
||||
checksum = "b73250e61e41d0e467b78559c7d761841005d724384bb0b78d52ff974acf5520"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"flagset",
|
||||
"indexmap",
|
||||
"leb128",
|
||||
"wasm-encoder",
|
||||
"wasmparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.78.2"
|
||||
version = "0.87.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65"
|
||||
checksum = "5c04e207cd2e8ecb6f9bd28a2cf3119b4c6bfeee6fe3a25cc1daf8041d00a875"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wast"
|
||||
version = "41.0.0"
|
||||
version = "44.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f882898b8b817cc4edc16aa3692fdc087b356edc8cc0c2164f5b5181e31c3870"
|
||||
checksum = "5f474d1b1cb7d92e5360b293f28e8bc9b2d115197a5bbf76bdbfba9161cf9cdc"
|
||||
dependencies = [
|
||||
"leb128",
|
||||
"memchr",
|
||||
"unicode-width",
|
||||
"wasm-encoder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -5,17 +5,19 @@
|
|||
:root {
|
||||
height: 100%;
|
||||
--body-columns: 1fr;
|
||||
--body-rows: auto 2fr 1fr 40px;
|
||||
--body-rows: auto 2fr 1fr auto;
|
||||
--colorway-name-font-size: 1.5em;
|
||||
--colorway-selector-align: center;
|
||||
--figure-height: 200px;
|
||||
--figure-width: 200px;
|
||||
--homepage-reset-column: 1;
|
||||
--homepage-reset-align: space-between;
|
||||
}
|
||||
|
||||
@media (min-width: 50em) {
|
||||
:root {
|
||||
--body-columns: 24px repeat(2, 1fr);
|
||||
--body-rows: auto 1fr 64px;
|
||||
--body-rows: auto 1fr auto;
|
||||
--colorway-name-font-size: 2.5em;
|
||||
--colorway-selector-align: start;
|
||||
--customization-panel-column: 3;
|
||||
|
@ -25,6 +27,8 @@
|
|||
--figure-row: 2;
|
||||
--figure-width: 288px;
|
||||
--header-column: 2/4;
|
||||
--homepage-reset-column: 1/4;
|
||||
--homepage-reset-align: end;
|
||||
}
|
||||
|
||||
#colorway-name,
|
||||
|
@ -38,7 +42,8 @@ body {
|
|||
display: grid;
|
||||
grid-template-columns: var(--body-columns);
|
||||
grid-template-rows: var(--body-rows);
|
||||
padding: 0 24px;
|
||||
padding: 0 2em 1em;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
|
@ -54,6 +59,7 @@ body > header {
|
|||
}
|
||||
|
||||
figure {
|
||||
align-items: center;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
@ -69,6 +75,7 @@ figure > img {
|
|||
}
|
||||
|
||||
#colorway-customization-panel {
|
||||
align-self: center;
|
||||
padding-inline: var(--customization-panel-padding-inline);
|
||||
grid-column: var(--customization-panel-column);
|
||||
}
|
||||
|
@ -101,9 +108,22 @@ figure > img {
|
|||
|
||||
#homepage-reset-container:not([hidden]) {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
padding: 2em;
|
||||
grid-column: var(--homepage-reset-column);
|
||||
text-align: end;
|
||||
}
|
||||
|
||||
.reset-prompt,
|
||||
.success-prompt {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
align-items: center;
|
||||
justify-content: var(--homepage-reset-align);
|
||||
}
|
||||
|
||||
.reset-prompt > span,
|
||||
.success-prompt > span {
|
||||
padding-inline-end: 1em;
|
||||
}
|
||||
|
||||
#homepage-reset-container:not(.success) > .success-prompt,
|
||||
|
@ -111,7 +131,7 @@ figure > img {
|
|||
display: none;
|
||||
}
|
||||
|
||||
#homepage-reset-container > .success-prompt::before {
|
||||
#homepage-reset-container > .success-prompt span::before {
|
||||
display: inline-block;
|
||||
content: "";
|
||||
background: var(--green-50) url('chrome://global/skin/icons/check.svg') center center no-repeat;
|
||||
|
|
|
@ -38,6 +38,13 @@ var gFxaPairDeviceDialog = {
|
|||
},
|
||||
|
||||
uninit() {
|
||||
// When the modal closes we want to remove any query params
|
||||
// To prevent refreshes/restores from reopening the dialog
|
||||
const browser = window.docShell.chromeEventHandler;
|
||||
browser.loadURI("about:preferences#sync", {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
});
|
||||
|
||||
this.teardownListeners();
|
||||
this._emitter.emit("view:Closed");
|
||||
},
|
||||
|
|
|
@ -27,13 +27,15 @@ browser.engagement:
|
|||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1545172 # Telemetry
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1741674
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1755050
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1781578
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1545172#c8
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1781578
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
notification_emails:
|
||||
- loines@mozilla.com
|
||||
expires: 106
|
||||
expires: 112
|
||||
send_in_pings:
|
||||
- baseline
|
||||
- metrics
|
||||
|
@ -53,13 +55,15 @@ browser.engagement:
|
|||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1535169 # Telemetry
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1741674
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1755050
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1781578
|
||||
data_reviews:
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1535169#c14
|
||||
- https://bugzilla.mozilla.org/show_bug.cgi?id=1781578
|
||||
data_sensitivity:
|
||||
- interaction
|
||||
notification_emails:
|
||||
- loines@mozilla.com
|
||||
expires: 106
|
||||
expires: 112
|
||||
send_in_pings:
|
||||
- baseline
|
||||
- metrics
|
||||
|
|
|
@ -462,7 +462,7 @@ const BuiltInThemeConfig = new Map([
|
|||
[
|
||||
"innovator-balanced-colorway@mozilla.org",
|
||||
{
|
||||
version: "1.1",
|
||||
version: "1.1.1",
|
||||
path: "resource://builtin-themes/colorways/2022innovator/balanced/",
|
||||
collection: "independent-voices",
|
||||
l10nId: {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
},
|
||||
"name": "Innovator – Balanced",
|
||||
"author": "Mozilla",
|
||||
"version": "1.1",
|
||||
"version": "1.1.1",
|
||||
"icons": {
|
||||
"32": "icon.svg"
|
||||
},
|
||||
|
@ -26,7 +26,7 @@
|
|||
"popup_highlight": "hsla(17, 89%, 79%, 0.3)",
|
||||
"popup_highlight_text": "hsl(0, 0%, 0%)",
|
||||
"toolbar": "hsl(14, 93%, 83%)",
|
||||
"toolbar_text": "hsl(0, 0%, 100%)",
|
||||
"toolbar_text": "hsl(0, 0%, 0%)",
|
||||
"toolbar_field": "hsl(12, 100%, 91%)",
|
||||
"toolbar_field_text": "hsl(0, 0%, 0%)",
|
||||
"toolbar_field_focus": "hsl(0, 0%, 100%)",
|
||||
|
|
|
@ -664,7 +664,7 @@ richlistitem[selected] .actionsMenu:focus-visible {
|
|||
|
||||
.fxaPairDeviceIcon .close-icon {
|
||||
margin-top: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
border: none;
|
||||
|
|
|
@ -51,6 +51,7 @@ function checkSandboxOriginAttributes(arr, attrs, options) {
|
|||
}
|
||||
|
||||
// utility function useful for debugging
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
function printAttrs(name, attrs) {
|
||||
info(
|
||||
name +
|
||||
|
|
|
@ -2998,19 +2998,21 @@ void BrowsingContext::DidSet(FieldIndex<IDX_IsActiveBrowserWindowInternal>,
|
|||
doc->UpdateDocumentStates(DocumentState::WINDOW_INACTIVE, true);
|
||||
|
||||
RefPtr<nsPIDOMWindowInner> win = doc->GetInnerWindow();
|
||||
RefPtr<MediaDevices> devices;
|
||||
if (isActivateEvent && (devices = win->GetExtantMediaDevices())) {
|
||||
devices->BrowserWindowBecameActive();
|
||||
}
|
||||
if (win) {
|
||||
RefPtr<MediaDevices> devices;
|
||||
if (isActivateEvent && (devices = win->GetExtantMediaDevices())) {
|
||||
devices->BrowserWindowBecameActive();
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess() &&
|
||||
(!aContext->GetParent() || !aContext->GetParent()->IsInProcess())) {
|
||||
// Send the inner window an activate/deactivate event if
|
||||
// the context is the top of a sub-tree of in-process
|
||||
// contexts.
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, win, isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
|
||||
CanBubble::eYes, Cancelable::eYes, nullptr);
|
||||
if (XRE_IsContentProcess() &&
|
||||
(!aContext->GetParent() || !aContext->GetParent()->IsInProcess())) {
|
||||
// Send the inner window an activate/deactivate event if
|
||||
// the context is the top of a sub-tree of in-process
|
||||
// contexts.
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, win, isActivateEvent ? u"activate"_ns : u"deactivate"_ns,
|
||||
CanBubble::eYes, Cancelable::eYes, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1534,14 +1534,14 @@ class Document : public nsINode,
|
|||
|
||||
void DoNotifyPossibleTitleChange();
|
||||
|
||||
nsresult InitFeaturePolicy(nsIChannel* aChannel);
|
||||
|
||||
protected:
|
||||
friend class nsUnblockOnloadEvent;
|
||||
|
||||
nsresult InitCSP(nsIChannel* aChannel);
|
||||
nsresult InitCOEP(nsIChannel* aChannel);
|
||||
|
||||
nsresult InitFeaturePolicy(nsIChannel* aChannel);
|
||||
|
||||
nsresult InitReferrerInfo(nsIChannel* aChannel);
|
||||
|
||||
void PostUnblockOnloadEvent();
|
||||
|
|
|
@ -323,22 +323,23 @@ nsXMLContentSink::DidBuildModel(bool aTerminated) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXMLContentSink::OnDocumentCreated(Document* aResultDocument) {
|
||||
NS_ENSURE_ARG(aResultDocument);
|
||||
|
||||
nsresult nsXMLContentSink::OnDocumentCreated(Document* aSourceDocument,
|
||||
Document* aResultDocument) {
|
||||
aResultDocument->SetDocWriteDisabled(true);
|
||||
|
||||
nsCOMPtr<nsIContentViewer> contentViewer;
|
||||
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
|
||||
if (contentViewer) {
|
||||
// Make sure that we haven't loaded a new document into the contentviewer
|
||||
// after starting the XSLT transform.
|
||||
if (contentViewer && contentViewer->GetDocument() == aSourceDocument) {
|
||||
return contentViewer->SetDocumentInternal(aResultDocument, true);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsXMLContentSink::OnTransformDone(nsresult aResult, Document* aResultDocument) {
|
||||
nsresult nsXMLContentSink::OnTransformDone(Document* aSourceDocument,
|
||||
nsresult aResult,
|
||||
Document* aResultDocument) {
|
||||
MOZ_ASSERT(aResultDocument,
|
||||
"Don't notify about transform end without a document.");
|
||||
|
||||
|
@ -347,42 +348,49 @@ nsXMLContentSink::OnTransformDone(nsresult aResult, Document* aResultDocument) {
|
|||
nsCOMPtr<nsIContentViewer> contentViewer;
|
||||
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
|
||||
|
||||
if (NS_FAILED(aResult) && contentViewer) {
|
||||
// Transform failed.
|
||||
aResultDocument->SetMayStartLayout(false);
|
||||
// We have an error document.
|
||||
contentViewer->SetDocument(aResultDocument);
|
||||
}
|
||||
|
||||
RefPtr<Document> originalDocument = mDocument;
|
||||
bool blockingOnload = mIsBlockingOnload;
|
||||
if (!mRunsToCompletion) {
|
||||
// This BlockOnload call corresponds to the UnblockOnload call in
|
||||
// nsContentSink::DropParserAndPerfHint.
|
||||
aResultDocument->BlockOnload();
|
||||
mIsBlockingOnload = true;
|
||||
|
||||
// Make sure that we haven't loaded a new document into the contentviewer
|
||||
// after starting the XSLT transform.
|
||||
if (contentViewer && (contentViewer->GetDocument() == aSourceDocument ||
|
||||
contentViewer->GetDocument() == aResultDocument)) {
|
||||
if (NS_FAILED(aResult)) {
|
||||
// Transform failed.
|
||||
aResultDocument->SetMayStartLayout(false);
|
||||
// We have an error document.
|
||||
contentViewer->SetDocument(aResultDocument);
|
||||
}
|
||||
|
||||
if (!mRunsToCompletion) {
|
||||
// This BlockOnload call corresponds to the UnblockOnload call in
|
||||
// nsContentSink::DropParserAndPerfHint.
|
||||
aResultDocument->BlockOnload();
|
||||
mIsBlockingOnload = true;
|
||||
}
|
||||
// Transform succeeded, or it failed and we have an error document to
|
||||
// display.
|
||||
mDocument = aResultDocument;
|
||||
aResultDocument->SetDocWriteDisabled(false);
|
||||
|
||||
// Notify document observers that all the content has been stuck
|
||||
// into the document.
|
||||
// XXX do we need to notify for things like PIs? Or just the
|
||||
// documentElement?
|
||||
nsIContent* rootElement = mDocument->GetRootElement();
|
||||
if (rootElement) {
|
||||
NS_ASSERTION(mDocument->ComputeIndexOf(rootElement).isSome(),
|
||||
"rootElement not in doc?");
|
||||
mDocument->BeginUpdate();
|
||||
MutationObservers::NotifyContentInserted(mDocument, rootElement);
|
||||
mDocument->EndUpdate();
|
||||
}
|
||||
|
||||
// Start the layout process
|
||||
StartLayout(false);
|
||||
|
||||
ScrollToRef();
|
||||
}
|
||||
// Transform succeeded, or it failed and we have an error document to display.
|
||||
mDocument = aResultDocument;
|
||||
aResultDocument->SetDocWriteDisabled(false);
|
||||
|
||||
// Notify document observers that all the content has been stuck
|
||||
// into the document.
|
||||
// XXX do we need to notify for things like PIs? Or just the
|
||||
// documentElement?
|
||||
nsIContent* rootElement = mDocument->GetRootElement();
|
||||
if (rootElement) {
|
||||
NS_ASSERTION(mDocument->ComputeIndexOf(rootElement).isSome(),
|
||||
"rootElement not in doc?");
|
||||
mDocument->BeginUpdate();
|
||||
MutationObservers::NotifyContentInserted(mDocument, rootElement);
|
||||
mDocument->EndUpdate();
|
||||
}
|
||||
|
||||
// Start the layout process
|
||||
StartLayout(false);
|
||||
|
||||
ScrollToRef();
|
||||
|
||||
originalDocument->EndLoad();
|
||||
if (blockingOnload) {
|
||||
|
|
|
@ -76,10 +76,11 @@ class nsXMLContentSink : public nsContentSink,
|
|||
}
|
||||
|
||||
// nsITransformObserver
|
||||
NS_IMETHOD OnDocumentCreated(
|
||||
mozilla::dom::Document* aResultDocument) override;
|
||||
NS_IMETHOD OnTransformDone(nsresult aResult,
|
||||
nsresult OnDocumentCreated(mozilla::dom::Document* aSourceDocument,
|
||||
mozilla::dom::Document* aResultDocument) override;
|
||||
nsresult OnTransformDone(mozilla::dom::Document* aSourceDocument,
|
||||
nsresult aResult,
|
||||
mozilla::dom::Document* aResultDocument) override;
|
||||
|
||||
// nsICSSLoaderObserver
|
||||
NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred,
|
||||
|
|
|
@ -33,10 +33,13 @@ class nsITransformObserver : public nsISupports {
|
|||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ITRANSFORMOBSERVER_IID)
|
||||
|
||||
NS_IMETHOD OnDocumentCreated(mozilla::dom::Document* aResultDocument) = 0;
|
||||
virtual nsresult OnDocumentCreated(
|
||||
mozilla::dom::Document* aSourceDocument,
|
||||
mozilla::dom::Document* aResultDocument) = 0;
|
||||
|
||||
NS_IMETHOD OnTransformDone(nsresult aResult,
|
||||
mozilla::dom::Document* aResultDocument) = 0;
|
||||
virtual nsresult OnTransformDone(mozilla::dom::Document* aSourceDocument,
|
||||
nsresult aResult,
|
||||
mozilla::dom::Document* aResultDocument) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsITransformObserver, NS_ITRANSFORMOBSERVER_IID)
|
||||
|
|
|
@ -21,8 +21,11 @@
|
|||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
txMozillaTextOutput::txMozillaTextOutput(nsITransformObserver* aObserver)
|
||||
: mObserver(do_GetWeakReference(aObserver)), mCreatedDocument(false) {
|
||||
txMozillaTextOutput::txMozillaTextOutput(Document* aSourceDocument,
|
||||
nsITransformObserver* aObserver)
|
||||
: mSourceDocument(aSourceDocument),
|
||||
mObserver(do_GetWeakReference(aObserver)),
|
||||
mCreatedDocument(false) {
|
||||
MOZ_COUNT_CTOR(txMozillaTextOutput);
|
||||
}
|
||||
|
||||
|
@ -86,7 +89,7 @@ nsresult txMozillaTextOutput::endDocument(nsresult aResult) {
|
|||
if (NS_SUCCEEDED(aResult)) {
|
||||
nsCOMPtr<nsITransformObserver> observer = do_QueryReferent(mObserver);
|
||||
if (observer) {
|
||||
observer->OnTransformDone(aResult, mDocument);
|
||||
observer->OnTransformDone(mSourceDocument, aResult, mDocument);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,8 +105,7 @@ nsresult txMozillaTextOutput::processingInstruction(const nsString& aTarget,
|
|||
|
||||
nsresult txMozillaTextOutput::startDocument() { return NS_OK; }
|
||||
|
||||
nsresult txMozillaTextOutput::createResultDocument(Document* aSourceDocument,
|
||||
bool aLoadedAsData) {
|
||||
nsresult txMozillaTextOutput::createResultDocument(bool aLoadedAsData) {
|
||||
/*
|
||||
* Create an XHTML document to hold the text.
|
||||
*
|
||||
|
@ -131,13 +133,13 @@ nsresult txMozillaTextOutput::createResultDocument(Document* aSourceDocument,
|
|||
mDocument->SetReadyStateInternal(Document::READYSTATE_LOADING);
|
||||
bool hasHadScriptObject = false;
|
||||
nsIScriptGlobalObject* sgo =
|
||||
aSourceDocument->GetScriptHandlingObject(hasHadScriptObject);
|
||||
mSourceDocument->GetScriptHandlingObject(hasHadScriptObject);
|
||||
NS_ENSURE_STATE(sgo || !hasHadScriptObject);
|
||||
|
||||
NS_ASSERTION(mDocument, "Need document");
|
||||
|
||||
// Reset and set up document
|
||||
URIUtils::ResetWithSource(mDocument, aSourceDocument);
|
||||
URIUtils::ResetWithSource(mDocument, mSourceDocument);
|
||||
// Only do this after resetting the document to ensure we have the
|
||||
// correct principal.
|
||||
mDocument->SetScriptHandlingObject(sgo);
|
||||
|
@ -154,7 +156,7 @@ nsresult txMozillaTextOutput::createResultDocument(Document* aSourceDocument,
|
|||
// Notify the contentsink that the document is created
|
||||
nsCOMPtr<nsITransformObserver> observer = do_QueryReferent(mObserver);
|
||||
if (observer) {
|
||||
rv = observer->OnDocumentCreated(mDocument);
|
||||
rv = observer->OnDocumentCreated(mSourceDocument, mDocument);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,19 +22,20 @@ class Element;
|
|||
|
||||
class txMozillaTextOutput : public txAOutputXMLEventHandler {
|
||||
public:
|
||||
explicit txMozillaTextOutput(nsITransformObserver* aObserver);
|
||||
explicit txMozillaTextOutput(mozilla::dom::Document* aSourceDocument,
|
||||
nsITransformObserver* aObserver);
|
||||
explicit txMozillaTextOutput(mozilla::dom::DocumentFragment* aDest);
|
||||
virtual ~txMozillaTextOutput();
|
||||
|
||||
TX_DECL_TXAXMLEVENTHANDLER
|
||||
TX_DECL_TXAOUTPUTXMLEVENTHANDLER
|
||||
|
||||
nsresult createResultDocument(mozilla::dom::Document* aSourceDocument,
|
||||
bool aLoadedAsData);
|
||||
nsresult createResultDocument(bool aLoadedAsData);
|
||||
|
||||
private:
|
||||
nsresult createXHTMLElement(nsAtom* aName, mozilla::dom::Element** aResult);
|
||||
|
||||
nsCOMPtr<mozilla::dom::Document> mSourceDocument;
|
||||
nsCOMPtr<nsIContent> mTextParent;
|
||||
nsWeakPtr mObserver;
|
||||
RefPtr<mozilla::dom::Document> mDocument;
|
||||
|
|
|
@ -50,7 +50,8 @@ using namespace mozilla::dom;
|
|||
NS_ASSERTION(mCurrentNode, "mCurrentNode is nullptr"); \
|
||||
if (!mCurrentNode) return NS_ERROR_UNEXPECTED
|
||||
|
||||
txMozillaXMLOutput::txMozillaXMLOutput(txOutputFormat* aFormat,
|
||||
txMozillaXMLOutput::txMozillaXMLOutput(Document* aSourceDocument,
|
||||
txOutputFormat* aFormat,
|
||||
nsITransformObserver* aObserver)
|
||||
: mTreeDepth(0),
|
||||
mBadChildLevel(0),
|
||||
|
@ -61,7 +62,7 @@ txMozillaXMLOutput::txMozillaXMLOutput(txOutputFormat* aFormat,
|
|||
mNoFixup(false) {
|
||||
MOZ_COUNT_CTOR(txMozillaXMLOutput);
|
||||
if (aObserver) {
|
||||
mNotifier = new txTransformNotifier();
|
||||
mNotifier = new txTransformNotifier(aSourceDocument);
|
||||
if (mNotifier) {
|
||||
mNotifier->Init(aObserver);
|
||||
}
|
||||
|
@ -776,6 +777,9 @@ nsresult txMozillaXMLOutput::createResultDocument(const nsAString& aName,
|
|||
if (mNotifier) {
|
||||
rv = mNotifier->SetOutputDocument(mDocument);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = mDocument->InitFeaturePolicy(mDocument->GetChannel());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Do this after calling OnDocumentCreated to ensure that the
|
||||
|
@ -835,8 +839,10 @@ nsresult txMozillaXMLOutput::createHTMLElement(nsAtom* aName,
|
|||
return rv;
|
||||
}
|
||||
|
||||
txTransformNotifier::txTransformNotifier()
|
||||
: mPendingStylesheetCount(0), mInTransform(false) {}
|
||||
txTransformNotifier::txTransformNotifier(Document* aSourceDocument)
|
||||
: mSourceDocument(aSourceDocument),
|
||||
mPendingStylesheetCount(0),
|
||||
mInTransform(false) {}
|
||||
|
||||
txTransformNotifier::~txTransformNotifier() = default;
|
||||
|
||||
|
@ -906,7 +912,7 @@ nsresult txTransformNotifier::SetOutputDocument(Document* aDocument) {
|
|||
mDocument = aDocument;
|
||||
|
||||
// Notify the contentsink that the document is created
|
||||
return mObserver->OnDocumentCreated(mDocument);
|
||||
return mObserver->OnDocumentCreated(mSourceDocument, mDocument);
|
||||
}
|
||||
|
||||
void txTransformNotifier::SignalTransformEnd(nsresult aResult) {
|
||||
|
@ -937,6 +943,6 @@ void txTransformNotifier::SignalTransformEnd(nsresult aResult) {
|
|||
}
|
||||
|
||||
if (NS_SUCCEEDED(aResult)) {
|
||||
mObserver->OnTransformDone(aResult, mDocument);
|
||||
mObserver->OnTransformDone(mSourceDocument, aResult, mDocument);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ class Element;
|
|||
class txTransformNotifier final : public nsIScriptLoaderObserver,
|
||||
public nsICSSLoaderObserver {
|
||||
public:
|
||||
txTransformNotifier();
|
||||
explicit txTransformNotifier(mozilla::dom::Document* aSourceDocument);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISCRIPTLOADEROBSERVER
|
||||
|
@ -50,6 +50,7 @@ class txTransformNotifier final : public nsIScriptLoaderObserver,
|
|||
~txTransformNotifier();
|
||||
void SignalTransformEnd(nsresult aResult = NS_OK);
|
||||
|
||||
nsCOMPtr<mozilla::dom::Document> mSourceDocument;
|
||||
nsCOMPtr<mozilla::dom::Document> mDocument;
|
||||
nsCOMPtr<nsITransformObserver> mObserver;
|
||||
nsTArray<nsCOMPtr<nsIScriptElement>> mScriptElements;
|
||||
|
@ -59,7 +60,8 @@ class txTransformNotifier final : public nsIScriptLoaderObserver,
|
|||
|
||||
class txMozillaXMLOutput : public txAOutputXMLEventHandler {
|
||||
public:
|
||||
txMozillaXMLOutput(txOutputFormat* aFormat, nsITransformObserver* aObserver);
|
||||
txMozillaXMLOutput(mozilla::dom::Document* aSourceDocument,
|
||||
txOutputFormat* aFormat, nsITransformObserver* aObserver);
|
||||
txMozillaXMLOutput(txOutputFormat* aFormat,
|
||||
mozilla::dom::DocumentFragment* aFragment, bool aNoFixup);
|
||||
~txMozillaXMLOutput();
|
||||
|
|
|
@ -80,7 +80,7 @@ nsresult txToDocHandlerFactory::createHandlerWith(
|
|||
|
||||
case eHTMLOutput: {
|
||||
UniquePtr<txMozillaXMLOutput> handler(
|
||||
new txMozillaXMLOutput(aFormat, mObserver));
|
||||
new txMozillaXMLOutput(mSourceDocument, aFormat, mObserver));
|
||||
|
||||
nsresult rv = handler->createResultDocument(
|
||||
u""_ns, kNameSpaceID_None, mSourceDocument, mDocumentIsData);
|
||||
|
@ -93,10 +93,9 @@ nsresult txToDocHandlerFactory::createHandlerWith(
|
|||
|
||||
case eTextOutput: {
|
||||
UniquePtr<txMozillaTextOutput> handler(
|
||||
new txMozillaTextOutput(mObserver));
|
||||
new txMozillaTextOutput(mSourceDocument, mObserver));
|
||||
|
||||
nsresult rv =
|
||||
handler->createResultDocument(mSourceDocument, mDocumentIsData);
|
||||
nsresult rv = handler->createResultDocument(mDocumentIsData);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aHandler = handler.release();
|
||||
}
|
||||
|
@ -123,7 +122,7 @@ nsresult txToDocHandlerFactory::createHandlerWith(
|
|||
case eXMLOutput:
|
||||
case eHTMLOutput: {
|
||||
UniquePtr<txMozillaXMLOutput> handler(
|
||||
new txMozillaXMLOutput(aFormat, mObserver));
|
||||
new txMozillaXMLOutput(mSourceDocument, aFormat, mObserver));
|
||||
|
||||
nsresult rv = handler->createResultDocument(aName, aNsID, mSourceDocument,
|
||||
mDocumentIsData);
|
||||
|
@ -136,10 +135,9 @@ nsresult txToDocHandlerFactory::createHandlerWith(
|
|||
|
||||
case eTextOutput: {
|
||||
UniquePtr<txMozillaTextOutput> handler(
|
||||
new txMozillaTextOutput(mObserver));
|
||||
new txMozillaTextOutput(mSourceDocument, mObserver));
|
||||
|
||||
nsresult rv =
|
||||
handler->createResultDocument(mSourceDocument, mDocumentIsData);
|
||||
nsresult rv = handler->createResultDocument(mDocumentIsData);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*aHandler = handler.release();
|
||||
}
|
||||
|
@ -1024,8 +1022,7 @@ void txMozillaXSLTProcessor::notifyError() {
|
|||
MOZ_ASSERT(document->GetReadyStateEnum() == Document::READYSTATE_LOADING,
|
||||
"Bad readyState.");
|
||||
document->SetReadyStateInternal(Document::READYSTATE_INTERACTIVE);
|
||||
|
||||
mObserver->OnTransformDone(mTransformResult, document);
|
||||
mObserver->OnTransformDone(mSource->OwnerDoc(), mTransformResult, document);
|
||||
}
|
||||
|
||||
nsresult txMozillaXSLTProcessor::ensureStylesheet() {
|
||||
|
|
|
@ -231,6 +231,7 @@ ScopedSaveMultiTex::ScopedSaveMultiTex(GLContext* const gl,
|
|||
break;
|
||||
default:
|
||||
gfxCriticalError() << "Unhandled texTarget: " << texTarget;
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < mTexCount; i++) {
|
||||
|
|
|
@ -5,6 +5,6 @@ authors = ["Christian Holler"]
|
|||
license = "MPL 2.0"
|
||||
|
||||
[dependencies]
|
||||
wasm-smith = "0.8.0"
|
||||
wasm-smith = "0.11.2"
|
||||
arbitrary = { version = "1.0.0", features = ["derive"] }
|
||||
libc = "0.2"
|
||||
|
|
|
@ -152,6 +152,7 @@ void TenuringTracer::traverse(JS::Value* thingp) {
|
|||
} else if (value.isBigInt()) {
|
||||
post = JS::BigIntValue(onBigIntEdge(value.toBigInt()));
|
||||
} else {
|
||||
MOZ_ASSERT_IF(value.isGCThing(), !IsInsideNursery(value.toGCThing()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -427,8 +427,7 @@ if (wasmGcEnabled()) {
|
|||
(module
|
||||
(type $s (struct))
|
||||
(func (export "newStruct") (result eqref)
|
||||
rtt.canon $s
|
||||
struct.new_with_rtt $s)
|
||||
struct.new $s)
|
||||
)`).exports;
|
||||
WasmNonNullEqrefValues.push(newStruct());
|
||||
WasmEqrefValues.push(null, ...WasmNonNullEqrefValues);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
function getStack() {
|
||||
enableGeckoProfiling();
|
||||
let stack = readGeckoProfilingStack();
|
||||
// The number of frames depends on JIT flags, but there must be at least
|
||||
// one frame for the caller and at most 3 total (the global script, 'testFun'
|
||||
// and 'getStack').
|
||||
assertEq(stack.length > 0, true);
|
||||
assertEq(stack.length <= 3, true);
|
||||
assertEq(JSON.stringify(stack).includes('"testFun ('), true);
|
||||
disableGeckoProfiling();
|
||||
}
|
||||
function testFun() {
|
||||
// Loop until this is a JIT frame.
|
||||
while (true) {
|
||||
let isJitFrame = inJit();
|
||||
if (typeof isJitFrame === "string") {
|
||||
return; // JIT disabled.
|
||||
}
|
||||
if (isJitFrame) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Now call getStack to check this frame is on the profiler's JIT stack.
|
||||
getStack();
|
||||
getStack();
|
||||
}
|
||||
testFun();
|
|
@ -7,7 +7,7 @@
|
|||
(type $p (struct (field f64) (field (mut i32))))
|
||||
|
||||
(func (export "mkp") (result eqref)
|
||||
(struct.new_with_rtt $p (f64.const 1.5) (i32.const 33) (rtt.canon $p))))`).exports;
|
||||
(struct.new $p (f64.const 1.5) (i32.const 33))))`).exports;
|
||||
|
||||
let p = ins.mkp();
|
||||
assertEq(p[0], 1.5);
|
||||
|
@ -22,7 +22,7 @@
|
|||
(type $p (struct (field f64)))
|
||||
|
||||
(func (export "mkp") (result eqref)
|
||||
(struct.new_with_rtt $p (f64.const 1.5) (rtt.canon $p))))`).exports;
|
||||
(struct.new $p (f64.const 1.5))))`).exports;
|
||||
|
||||
let p = ins.mkp();
|
||||
assertErrorMessage(() => p[0] = 5.7,
|
||||
|
@ -40,10 +40,10 @@
|
|||
(type $r (struct (field (mut eqref))))
|
||||
|
||||
(func (export "mkp") (result eqref)
|
||||
(struct.new_with_rtt $p (ref.null $q) (rtt.canon $p)))
|
||||
(struct.new $p (ref.null $q)))
|
||||
|
||||
(func (export "mkr") (result eqref)
|
||||
(struct.new_with_rtt $r (ref.null eq) (rtt.canon $r))))`).exports;
|
||||
(struct.new $r (ref.null eq))))`).exports;
|
||||
|
||||
assertEq(Object.getPrototypeOf(ins.mkp()), null);
|
||||
assertEq(Object.getPrototypeOf(ins.mkr()), null);
|
||||
|
@ -57,10 +57,10 @@
|
|||
(type $p (struct (field (mut (ref null $q))) (field (mut eqref))))
|
||||
|
||||
(func (export "mkq") (result eqref)
|
||||
(struct.new_with_rtt $q (f64.const 1.5) (rtt.canon $q)))
|
||||
(struct.new $q (f64.const 1.5)))
|
||||
|
||||
(func (export "mkp") (result eqref)
|
||||
(struct.new_with_rtt $p (ref.null $q) (ref.null eq) (rtt.canon $p))))`).exports;
|
||||
(struct.new $p (ref.null $q) (ref.null eq))))`).exports;
|
||||
let q = ins.mkq();
|
||||
assertEq(typeof q, "object");
|
||||
assertEq(q[0], 1.5);
|
||||
|
@ -85,7 +85,7 @@
|
|||
let ins = wasmEvalText(`(module
|
||||
(type $p (struct (field (mut i64))))
|
||||
(func (export "mkp") (result eqref)
|
||||
(struct.new_with_rtt $p (i64.const 0x1234567887654321) (rtt.canon $p))))`).exports;
|
||||
(struct.new $p (i64.const 0x1234567887654321))))`).exports;
|
||||
|
||||
let p = ins.mkp();
|
||||
assertEq(typeof p, "object");
|
||||
|
@ -106,18 +106,16 @@
|
|||
(type $q (struct (field i32) (field i32)))
|
||||
(func $f (param eqref) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $q
|
||||
ref.test
|
||||
ref.test $q
|
||||
)
|
||||
(func $g (param eqref) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $p
|
||||
ref.test
|
||||
ref.test $p
|
||||
)
|
||||
(func (export "t1") (result i32)
|
||||
(call $f (struct.new_with_rtt $p (i64.const 0) (rtt.canon $p))))
|
||||
(call $f (struct.new $p (i64.const 0))))
|
||||
(func (export "t2") (result i32)
|
||||
(call $g (struct.new_with_rtt $q (i32.const 0) (i32.const 0) (rtt.canon $q)))))`).exports;
|
||||
(call $g (struct.new $q (i32.const 0) (i32.const 0)))))`).exports;
|
||||
assertEq(ins.t1(), 0);
|
||||
assertEq(ins.t2(), 0);
|
||||
}
|
||||
|
|
|
@ -34,22 +34,19 @@ for (let [valtype, def, nondef] of GENERAL_TESTS) {
|
|||
(func (export "create") (param i32 ${valtype}) (result eqref)
|
||||
local.get 1
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
array.new_with_rtt $a
|
||||
array.new $a
|
||||
)
|
||||
|
||||
(; new T[0] ;)
|
||||
(func (export "createDefault") (param i32) (result eqref)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
array.new_default_with_rtt $a
|
||||
array.new_default $a
|
||||
)
|
||||
|
||||
(; 0[1] ;)
|
||||
(func (export "get") (param eqref i32) (result ${valtype})
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
local.get 1
|
||||
array.get $a
|
||||
)
|
||||
|
@ -57,8 +54,7 @@ for (let [valtype, def, nondef] of GENERAL_TESTS) {
|
|||
(; 0[1] = 2 ;)
|
||||
(func (export "set") (param eqref i32 ${valtype})
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
local.get 1
|
||||
local.get 2
|
||||
array.set $a
|
||||
|
@ -67,8 +63,7 @@ for (let [valtype, def, nondef] of GENERAL_TESTS) {
|
|||
(; len(a) ;)
|
||||
(func (export "len") (param eqref) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
array.len $a
|
||||
)
|
||||
)`).exports;
|
||||
|
@ -130,15 +125,13 @@ for (let [fieldtype, max] of [
|
|||
(func (export "create") (param i32 i32) (result eqref)
|
||||
local.get 1
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
array.new_with_rtt $a
|
||||
array.new $a
|
||||
)
|
||||
|
||||
(; 0[1] ;)
|
||||
(func (export "getS") (param eqref i32) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
local.get 1
|
||||
array.get_s $a
|
||||
)
|
||||
|
@ -146,8 +139,7 @@ for (let [fieldtype, max] of [
|
|||
(; 0[1] ;)
|
||||
(func (export "getU") (param eqref i32) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
local.get 1
|
||||
array.get_u $a
|
||||
)
|
||||
|
@ -155,8 +147,7 @@ for (let [fieldtype, max] of [
|
|||
(; 0[1] = 2 ;)
|
||||
(func (export "set") (param eqref i32 i32)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
ref.cast
|
||||
ref.cast $a
|
||||
local.get 1
|
||||
local.get 2
|
||||
array.set $a
|
||||
|
@ -193,10 +184,9 @@ assertErrorMessage(() => wasmEvalText(`(module
|
|||
(type $a (array i32))
|
||||
(func
|
||||
(array.set $a
|
||||
(array.new_with_rtt $a
|
||||
(array.new $a
|
||||
i32.const 0xff
|
||||
i32.const 10
|
||||
rtt.canon $a)
|
||||
i32.const 10)
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
)
|
||||
|
|
|
@ -10,8 +10,7 @@ function typingModule(types, castToTypeIndex, brParams, blockResults) {
|
|||
(; push params onto the stack in the same order as they appear, leaving
|
||||
the last param at the top of the stack. ;)
|
||||
${brParams.map((_, i) => `local.get ${i}`).join('\n')}
|
||||
rtt.canon ${castToTypeIndex}
|
||||
br_on_cast 0
|
||||
br_on_cast 0 ${castToTypeIndex}
|
||||
unreachable
|
||||
)
|
||||
)`;
|
||||
|
@ -56,20 +55,17 @@ invalidTyping('(type $a (struct))', '$a', ['i32', 'f32', 'eqref'], ['f32', 'i32'
|
|||
(type $b (struct (field i32)))
|
||||
|
||||
(func (export "makeA") (result eqref)
|
||||
rtt.canon $a
|
||||
struct.new_default_with_rtt $a
|
||||
struct.new_default $a
|
||||
)
|
||||
|
||||
(func (export "makeB") (result eqref)
|
||||
rtt.canon $b
|
||||
struct.new_default_with_rtt $b
|
||||
struct.new_default $b
|
||||
)
|
||||
|
||||
(func (export "isA") (param eqref) (result i32)
|
||||
(block (result (ref $a))
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
br_on_cast 0
|
||||
br_on_cast 0 $a
|
||||
|
||||
i32.const 0
|
||||
br 1
|
||||
|
@ -81,8 +77,7 @@ invalidTyping('(type $a (struct))', '$a', ['i32', 'f32', 'eqref'], ['f32', 'i32'
|
|||
(func (export "isB") (param eqref) (result i32)
|
||||
(block (result (ref $a))
|
||||
local.get 0
|
||||
rtt.canon $b
|
||||
br_on_cast 0
|
||||
br_on_cast 0 $b
|
||||
|
||||
i32.const 0
|
||||
br 1
|
||||
|
@ -128,19 +123,16 @@ invalidTyping('(type $a (struct))', '$a', ['i32', 'f32', 'eqref'], ['f32', 'i32'
|
|||
(type $f (struct (field i32)))
|
||||
|
||||
(func (export "makeT") (result eqref)
|
||||
rtt.canon $t
|
||||
struct.new_default_with_rtt $t
|
||||
struct.new_default $t
|
||||
)
|
||||
(func (export "makeF") (result eqref)
|
||||
rtt.canon $f
|
||||
struct.new_default_with_rtt $f
|
||||
struct.new_default $f
|
||||
)
|
||||
|
||||
(func (export "select") (param eqref) (result ${values.map((type) => type).join(" ")})
|
||||
(block (result (ref $t))
|
||||
local.get 0
|
||||
rtt.canon $t
|
||||
br_on_cast 0
|
||||
br_on_cast 0 $t
|
||||
|
||||
${values.map((type, i) => `${type}.const ${values.length + i}`).join("\n")}
|
||||
br 1
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
|
||||
// Struct fields of externref type can receive their value in these ways:
|
||||
//
|
||||
// - the struct.new_with_rtt and struct.set instructions
|
||||
// - the struct.new and struct.set instructions
|
||||
// - storing into mutable fields from JS
|
||||
// - from a constructor called from JS
|
||||
//
|
||||
|
@ -25,7 +25,7 @@
|
|||
// into a field, in this case there should be boxing; and where JS reads a
|
||||
// non-pointer value from a field, in this case there should be unboxing.
|
||||
|
||||
// Write with struct.new_with_rtt, read with the JS getter
|
||||
// Write with struct.new, read with the JS getter
|
||||
|
||||
for (let v of WasmExternrefValues)
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ for (let v of WasmExternrefValues)
|
|||
`(module
|
||||
(type $S (struct (field $S.x (mut externref))))
|
||||
(func (export "make") (param $v externref) (result eqref)
|
||||
(struct.new_with_rtt $S (local.get $v) (rtt.canon $S))))`);
|
||||
(struct.new $S (local.get $v))))`);
|
||||
let x = ins.exports.make(v);
|
||||
assertEq(x[0], v);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ for (let v of WasmExternrefValues)
|
|||
let txt = `(module
|
||||
(type $S (struct ${fields}))
|
||||
(func (export "make") ${params} (result eqref)
|
||||
(struct.new_with_rtt $S ${args} (rtt.canon $S))))`;
|
||||
(struct.new $S ${args})))`;
|
||||
let ins = wasmEvalText(txt);
|
||||
let x = ins.exports.make({x:0}, {x:1}, {x:2}, {x:3}, {x:4}, {x:5}, {x:6}, {x:7}, {x:8}, {x:9})
|
||||
gc('shrinking');
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
let { exports: { make, ref_eq, ref_eq_for_control } } = wasmEvalText(`(module
|
||||
(type $s (struct))
|
||||
|
||||
(func (export "make") (result eqref) rtt.canon $s struct.new_with_rtt $s)
|
||||
(func (export "make") (result eqref) struct.new $s)
|
||||
|
||||
(func (export "ref_eq") (param $a eqref) (param $b eqref) (result i32)
|
||||
(ref.eq (local.get $a) (local.get $b)))
|
||||
|
|
|
@ -47,10 +47,10 @@
|
|||
(global $glob (mut (ref null $point)) (ref.null $point))
|
||||
|
||||
(func (export "init")
|
||||
(global.set $glob (struct.new_with_rtt $point (f64.const 0.5) (f64.const 2.75) (rtt.canon $point))))
|
||||
(global.set $glob (struct.new $point (f64.const 0.5) (f64.const 2.75))))
|
||||
|
||||
(func (export "change")
|
||||
(global.set $glob (struct.new_with_rtt $point (f64.const 3.5) (f64.const 37.25) (rtt.canon $point))))
|
||||
(global.set $glob (struct.new $point (f64.const 3.5) (f64.const 37.25))))
|
||||
|
||||
(func (export "clear")
|
||||
(global.set $glob (ref.null $point)))
|
||||
|
|
|
@ -15,7 +15,7 @@ function checkInvalid(body, errorMessage) {
|
|||
errorMessage);
|
||||
}
|
||||
|
||||
// General test case for struct.new_with_rtt, struct.get, and struct.set: binary tree
|
||||
// General test case for struct.new, struct.get, and struct.set: binary tree
|
||||
// manipulation.
|
||||
|
||||
{
|
||||
|
@ -42,13 +42,12 @@ function checkInvalid(body, errorMessage) {
|
|||
(local.set $tmp (global.get $k))
|
||||
(global.set $k (i32.add (local.get $tmp) (i32.const 1)))
|
||||
(if (result (ref null $wabbit)) (i32.le_s (local.get $n) (i32.const 2))
|
||||
(struct.new_with_rtt $wabbit (local.get $tmp) (ref.null $wabbit) (ref.null $wabbit) (rtt.canon $wabbit))
|
||||
(struct.new $wabbit (local.get $tmp) (ref.null $wabbit) (ref.null $wabbit))
|
||||
(block (result (ref null $wabbit))
|
||||
(struct.new_with_rtt $wabbit
|
||||
(struct.new $wabbit
|
||||
(local.get $tmp)
|
||||
(call $make (i32.sub (local.get $n) (i32.const 1)))
|
||||
(call $make (i32.sub (local.get $n) (i32.const 2)))
|
||||
(rtt.canon $wabbit)))))
|
||||
(call $make (i32.sub (local.get $n) (i32.const 2)))))))
|
||||
|
||||
(func (export "accumulate") (result i32)
|
||||
(call $accum (global.get $g)))
|
||||
|
@ -129,7 +128,7 @@ assertErrorMessage(() => wasmEvalText(
|
|||
(type $node (struct (field i32)))
|
||||
(type $node2 (struct (field i32) (field f32)))
|
||||
(func $f (param $p (ref null $node)) (result (ref null $node2))
|
||||
(ref.cast (local.get $p) rtt.canon $node2))
|
||||
(ref.cast $node2 (local.get $p)))
|
||||
(func (export "test") (result eqref)
|
||||
(call $f (ref.null $node))))`).exports.test(),
|
||||
WebAssembly.RuntimeError,
|
||||
|
@ -142,10 +141,10 @@ assertEq(wasmEvalText(
|
|||
(type $node (struct (field i32)))
|
||||
(type $node2 (struct (field i32) (field f32)))
|
||||
(func $f (param $p (ref null $node)) (result (ref null $node2))
|
||||
(ref.cast (local.get $p) rtt.canon $node2))
|
||||
(ref.cast $node2 (local.get $p)))
|
||||
(func (export "test") (result i32)
|
||||
(local $n (ref null $node))
|
||||
(local.set $n (struct.new_with_rtt $node2 (i32.const 0) (f32.const 12) (rtt.canon $node2)))
|
||||
(local.set $n (struct.new $node2 (i32.const 0) (f32.const 12)))
|
||||
(ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
|
||||
1);
|
||||
|
||||
|
@ -156,10 +155,10 @@ assertEq(wasmEvalText(
|
|||
(type $node (struct (field (mut i32))))
|
||||
(type $node2 (struct (field (mut i32)) (field f32)))
|
||||
(func $f (param $p (ref null $node)) (result (ref null $node2))
|
||||
(ref.cast (local.get $p) rtt.canon $node2))
|
||||
(ref.cast $node2 (local.get $p)))
|
||||
(func (export "test") (result i32)
|
||||
(local $n (ref null $node))
|
||||
(local.set $n (struct.new_with_rtt $node2 (i32.const 0) (f32.const 12) (rtt.canon $node2)))
|
||||
(local.set $n (struct.new $node2 (i32.const 0) (f32.const 12)))
|
||||
(ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
|
||||
1);
|
||||
|
||||
|
@ -170,10 +169,10 @@ assertEq(wasmEvalText(
|
|||
`(module
|
||||
(type $node (struct (field i32)))
|
||||
(func $f (param $p eqref) (result (ref null $node))
|
||||
(ref.cast (local.get $p) rtt.canon $node))
|
||||
(ref.cast $node (local.get $p)))
|
||||
(func (export "test") (result i32)
|
||||
(local $n (ref null $node))
|
||||
(local.set $n (struct.new_with_rtt $node (i32.const 0) (rtt.canon $node)))
|
||||
(local.set $n (struct.new $node (i32.const 0)))
|
||||
(ref.eq (call $f (local.get $n)) (local.get $n))))`).exports.test(),
|
||||
1);
|
||||
|
||||
|
@ -187,16 +186,13 @@ assertEq(wasmEvalText(
|
|||
(type $c (struct (field eqref)))
|
||||
|
||||
(func (export "makeA") (result eqref)
|
||||
rtt.canon $a
|
||||
struct.new_default_with_rtt $a
|
||||
struct.new_default $a
|
||||
)
|
||||
(func (export "makeB") (result eqref)
|
||||
rtt.canon $b
|
||||
struct.new_default_with_rtt $b
|
||||
struct.new_default $b
|
||||
)
|
||||
(func (export "makeC") (result eqref)
|
||||
rtt.canon $c
|
||||
struct.new_default_with_rtt $c
|
||||
struct.new_default $c
|
||||
)
|
||||
)`).exports;
|
||||
let a = makeA();
|
||||
|
@ -209,21 +205,19 @@ assertEq(wasmEvalText(
|
|||
assertEq(c[0], null);
|
||||
}
|
||||
|
||||
// struct.new_default_with_rtt: valid if all struct fields are defaultable
|
||||
// struct.new_default: valid if all struct fields are defaultable
|
||||
|
||||
wasmFailValidateText(`(module
|
||||
(type $a (struct (field (ref $a))))
|
||||
(func
|
||||
rtt.canon $a
|
||||
struct.new_default_with_rtt $a
|
||||
struct.new_default $a
|
||||
)
|
||||
)`, /defaultable/);
|
||||
|
||||
wasmFailValidateText(`(module
|
||||
(type $a (struct (field i32) (field i32) (field (ref $a))))
|
||||
(func
|
||||
rtt.canon $a
|
||||
struct.new_default_with_rtt $a
|
||||
struct.new_default $a
|
||||
)
|
||||
)`, /defaultable/);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ let bin = wasmTextToBinary(`
|
|||
)
|
||||
(func $make (param $n i32) (result (ref null $wabbit))
|
||||
(local $tmp i32)
|
||||
(struct.new_with_rtt $wabbit (local.get $tmp) (ref.null $wabbit) (ref.null $wabbit) (rtt.canon $wabbit))
|
||||
(struct.new $wabbit (local.get $tmp) (ref.null $wabbit) (ref.null $wabbit))
|
||||
)
|
||||
`);
|
||||
let mod = new WebAssembly.Module(bin);
|
||||
|
|
|
@ -12,8 +12,7 @@ try {
|
|||
(type $e (struct))
|
||||
(func (export "newStruct")
|
||||
(result eqref)
|
||||
rtt.canon $e
|
||||
struct.new_with_rtt $e
|
||||
struct.new $e
|
||||
)
|
||||
`).exports
|
||||
d.push(newStruct());
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
// |jit-test| skip-if: !wasmGcEnabled()
|
||||
|
||||
function processWat(c) {
|
||||
binary = wasmTextToBinary(c)
|
||||
d = new WebAssembly.Module(binary)
|
||||
return new WebAssembly.Instance(d)
|
||||
}
|
||||
gczeal(14,10)
|
||||
let { createA } = processWat(`
|
||||
(module (type $a (array i32))
|
||||
(global $e (rtt $a) rtt.canon $a)
|
||||
(func
|
||||
(export "createA")
|
||||
(result eqref)
|
||||
i32.const 0
|
||||
i32.const 0
|
||||
global.get $e
|
||||
array.new_with_rtt $a
|
||||
))
|
||||
`).exports;
|
||||
createA();
|
|
@ -1,19 +0,0 @@
|
|||
// |jit-test| skip-if: !wasmGcEnabled()
|
||||
|
||||
function processWat(c) {
|
||||
binary = wasmTextToBinary(c)
|
||||
d = new WebAssembly.Module(binary)
|
||||
return new WebAssembly.Instance(d)
|
||||
}
|
||||
gczeal(14,10)
|
||||
let { createA } = processWat(`
|
||||
(module (type $a (struct))
|
||||
(global $e (rtt $a) rtt.canon $a)
|
||||
(func
|
||||
(export "createA")
|
||||
(result eqref)
|
||||
global.get $e
|
||||
struct.new_with_rtt $a
|
||||
))
|
||||
`).exports;
|
||||
createA();
|
|
@ -4,8 +4,7 @@ let { createDefault } = wasmEvalText(`
|
|||
(module (type $a (array (mut i32)))
|
||||
(func (export "createDefault") (param i32) (result eqref)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
array.new_default_with_rtt $a
|
||||
array.new_default $a
|
||||
)
|
||||
)
|
||||
`).exports;
|
||||
|
|
|
@ -32,7 +32,7 @@ const wat = `
|
|||
|
||||
(func $main
|
||||
(struct.set $S 18
|
||||
(struct.new_with_rtt $S
|
||||
(struct.new $S
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
|
@ -51,9 +51,8 @@ const wat = `
|
|||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(ref.null eq)
|
||||
(rtt.canon $S))
|
||||
(struct.new_with_rtt $S2 (rtt.canon $S2))))
|
||||
(ref.null eq))
|
||||
(struct.new $S2)))
|
||||
(start $main))
|
||||
`
|
||||
wasmEvalText(wat);
|
||||
|
@ -97,7 +96,7 @@ wasmEvalText(`
|
|||
(local $inline (ref null $inline))
|
||||
|
||||
(; create an outline object and acquire multiple views to it ;)
|
||||
(struct.new_with_rtt $outline
|
||||
(struct.new $outline
|
||||
(i64.const 0xFF)
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
|
@ -116,8 +115,7 @@ wasmEvalText(`
|
|||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(i64.const 0)
|
||||
(rtt.canon $outline))
|
||||
(i64.const 0))
|
||||
local.tee $outline
|
||||
local.set $inline
|
||||
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
// |jit-test| skip-if: !wasmGcEnabled()
|
||||
|
||||
// Multiple invocations of rtt.sub are cached
|
||||
{
|
||||
let {createSubA, isSubA} = wasmEvalText(`(module
|
||||
(type $a (struct))
|
||||
(func (export "createSubA") (result eqref)
|
||||
rtt.canon $a
|
||||
rtt.sub $a
|
||||
struct.new_with_rtt $a
|
||||
)
|
||||
(func (export "isSubA") (param eqref) (result i32)
|
||||
local.get 0
|
||||
rtt.canon $a
|
||||
rtt.sub $a
|
||||
ref.test
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
assertEq(isSubA(createSubA()), 1);
|
||||
}
|
||||
|
||||
// rtt.canon is a constant expression
|
||||
{
|
||||
let {createA, isA} = wasmEvalText(`(module
|
||||
(; an immediate function type to cause renumbering ;)
|
||||
(type (func))
|
||||
(type $a (struct))
|
||||
(global $aCanon (rtt $a) rtt.canon $a)
|
||||
(func (export "createA") (result eqref)
|
||||
global.get $aCanon
|
||||
struct.new_with_rtt $a
|
||||
)
|
||||
(func (export "isA") (param eqref) (result i32)
|
||||
local.get 0
|
||||
global.get $aCanon
|
||||
ref.test
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
assertEq(isA(createA()), 1);
|
||||
}
|
||||
|
||||
// rtt.sub is a constant expression
|
||||
{
|
||||
let {createSubA, isSubA} = wasmEvalText(`(module
|
||||
(; an immediate function type to cause renumbering ;)
|
||||
(type (func))
|
||||
(type $a (struct))
|
||||
(global $aSub (rtt $a) rtt.canon $a rtt.sub $a)
|
||||
(func (export "createSubA") (result eqref)
|
||||
global.get $aSub
|
||||
struct.new_with_rtt $a
|
||||
)
|
||||
(func (export "isSubA") (param eqref) (result i32)
|
||||
local.get 0
|
||||
global.get $aSub
|
||||
ref.test
|
||||
)
|
||||
)`).exports;
|
||||
|
||||
assertEq(isSubA(createSubA()), 1);
|
||||
}
|
|
@ -59,10 +59,10 @@ var bin = wasmTextToBinary(
|
|||
;; Useful for testing to ensure that the type is not type #0 here.
|
||||
|
||||
(func (export "mk_point") (result eqref)
|
||||
(struct.new_with_rtt $point (i32.const 37) (i32.const 42) (rtt.canon $point)))
|
||||
(struct.new $point (i32.const 37) (i32.const 42)))
|
||||
|
||||
(func (export "mk_int_node") (param i32) (param externref) (result eqref)
|
||||
(struct.new_with_rtt $int_node (local.get 0) (local.get 1) (rtt.canon $int_node)))
|
||||
(struct.new $int_node (local.get 0) (local.get 1)))
|
||||
|
||||
;; Too big to fit in an InlineTypedObject.
|
||||
|
||||
|
@ -121,7 +121,7 @@ var bin = wasmTextToBinary(
|
|||
(field $az i32)))
|
||||
|
||||
(func (export "mk_bigger") (result eqref)
|
||||
(struct.new_with_rtt $bigger
|
||||
(struct.new $bigger
|
||||
(i32.const 0)
|
||||
(i32.const 1)
|
||||
(i32.const 2)
|
||||
|
@ -173,8 +173,7 @@ var bin = wasmTextToBinary(
|
|||
(i32.const 48)
|
||||
(i32.const 49)
|
||||
(i32.const 50)
|
||||
(i32.const 51)
|
||||
(rtt.canon $bigger)))
|
||||
(i32.const 51)))
|
||||
|
||||
(type $withfloats (struct
|
||||
(field $f1 f32)
|
||||
|
@ -186,7 +185,7 @@ var bin = wasmTextToBinary(
|
|||
(func (export "mk_withfloats")
|
||||
(param f32) (param f64) (param externref) (param f32) (param i32)
|
||||
(result eqref)
|
||||
(struct.new_with_rtt $withfloats (local.get 0) (local.get 1) (local.get 2) (local.get 3) (local.get 4) (rtt.canon $withfloats)))
|
||||
(struct.new $withfloats (local.get 0) (local.get 1) (local.get 2) (local.get 3) (local.get 4)))
|
||||
|
||||
)`)
|
||||
|
||||
|
@ -231,7 +230,7 @@ var stress = wasmTextToBinary(
|
|||
(block $exit
|
||||
(loop $loop
|
||||
(br_if $exit (i32.eqz (local.get $n)))
|
||||
(local.set $list (struct.new_with_rtt $node (local.get $n) (local.get $list) (rtt.canon $node)))
|
||||
(local.set $list (struct.new $node (local.get $n) (local.get $list)))
|
||||
(local.set $n (i32.sub (local.get $n) (i32.const 1)))
|
||||
(br $loop)))
|
||||
(local.get $list)))`);
|
||||
|
@ -259,24 +258,24 @@ assertEq(the_list, null);
|
|||
|
||||
(func (export "set") (param eqref)
|
||||
(local (ref null $big))
|
||||
(local.set 1 (ref.cast (local.get 0) rtt.canon $big))
|
||||
(local.set 1 (ref.cast $big (local.get 0)))
|
||||
(struct.set $big 1 (local.get 1) (i64.const 0x3333333376544567)))
|
||||
|
||||
(func (export "set2") (param $p eqref)
|
||||
(struct.set $big 1
|
||||
(ref.cast (local.get $p) rtt.canon $big)
|
||||
(ref.cast $big (local.get $p))
|
||||
(i64.const 0x3141592653589793)))
|
||||
|
||||
(func (export "low") (param $p eqref) (result i32)
|
||||
(i32.wrap/i64 (struct.get $big 1 (ref.cast (local.get $p) rtt.canon $big))))
|
||||
(i32.wrap/i64 (struct.get $big 1 (ref.cast $big (local.get $p)))))
|
||||
|
||||
(func (export "high") (param $p eqref) (result i32)
|
||||
(i32.wrap/i64 (i64.shr_u
|
||||
(struct.get $big 1 (ref.cast (local.get $p) rtt.canon $big))
|
||||
(struct.get $big 1 (ref.cast $big (local.get $p)))
|
||||
(i64.const 32))))
|
||||
|
||||
(func (export "mk") (result eqref)
|
||||
(struct.new_with_rtt $big (i32.const 0x7aaaaaaa) (i64.const 0x4201020337) (i32.const 0x6bbbbbbb) (rtt.canon $big)))
|
||||
(struct.new $big (i32.const 0x7aaaaaaa) (i64.const 0x4201020337) (i32.const 0x6bbbbbbb)))
|
||||
|
||||
)`;
|
||||
|
||||
|
@ -313,7 +312,7 @@ assertEq(the_list, null);
|
|||
|
||||
(func (export "make") (result eqref)
|
||||
(global.set $g
|
||||
(struct.new_with_rtt $big (i32.const 0x7aaaaaaa) (i64.const 0x4201020337) (i32.const 0x6bbbbbbb) (rtt.canon $big)))
|
||||
(struct.new $big (i32.const 0x7aaaaaaa) (i64.const 0x4201020337) (i32.const 0x6bbbbbbb)))
|
||||
(global.get $g))
|
||||
|
||||
(func (export "update0") (param $x i32)
|
||||
|
@ -378,7 +377,7 @@ var bin = wasmTextToBinary(
|
|||
(global $g (mut (ref null $cons)) (ref.null $cons))
|
||||
|
||||
(func (export "push") (param i32)
|
||||
(global.set $g (struct.new_with_rtt $cons (local.get 0) (global.get $g) (rtt.canon $cons))))
|
||||
(global.set $g (struct.new $cons (local.get 0) (global.get $g))))
|
||||
|
||||
(func (export "top") (result i32)
|
||||
(struct.get $cons 0 (global.get $g)))
|
||||
|
@ -416,9 +415,9 @@ assertErrorMessage(() => ins.pop(),
|
|||
`(module
|
||||
(type $Node (struct (field i32)))
|
||||
(func (export "mk") (result eqref)
|
||||
(struct.new_with_rtt $Node (i32.const 37) (rtt.canon $Node)))
|
||||
(struct.new $Node (i32.const 37)))
|
||||
(func (export "f") (param $n eqref) (result eqref)
|
||||
(ref.cast (local.get $n) rtt.canon $Node)))`).exports;
|
||||
(ref.cast $Node (local.get $n))))`).exports;
|
||||
var n = ins.mk();
|
||||
assertEq(ins.f(n), n);
|
||||
assertErrorMessage(() => ins.f(wrapWithProto(n, {})), TypeError, /can only pass a TypedObject/);
|
||||
|
@ -442,10 +441,10 @@ assertErrorMessage(() => ins.pop(),
|
|||
(struct.get $s $y (local.get $p)))
|
||||
|
||||
(func (export "testf") (param $n i32) (result i32)
|
||||
(call $f (struct.new_with_rtt $s (local.get $n) (i32.mul (local.get $n) (i32.const 2)) (rtt.canon $s))))
|
||||
(call $f (struct.new $s (local.get $n) (i32.mul (local.get $n) (i32.const 2)))))
|
||||
|
||||
(func (export "testg") (param $n i32) (result i32)
|
||||
(call $g (struct.new_with_rtt $s (local.get $n) (i32.mul (local.get $n) (i32.const 2)) (rtt.canon $s))))
|
||||
(call $g (struct.new $s (local.get $n) (i32.mul (local.get $n) (i32.const 2)))))
|
||||
|
||||
)`))).exports;
|
||||
|
||||
|
@ -471,7 +470,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
|
|||
(module
|
||||
(type $r (struct (field i32)))
|
||||
(func $f (param f64) (result eqref)
|
||||
(struct.new_with_rtt $r (local.get 0) (rtt.canon $r)))
|
||||
(struct.new $r (local.get 0)))
|
||||
)`)),
|
||||
WebAssembly.CompileError, /type mismatch/);
|
||||
|
||||
|
@ -481,7 +480,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
|
|||
(module
|
||||
(type $r (struct (field i32) (field i32)))
|
||||
(func $f (result eqref)
|
||||
(struct.new_with_rtt $r (i32.const 0) (rtt.canon $r)))
|
||||
(struct.new $r (i32.const 0)))
|
||||
)`)),
|
||||
WebAssembly.CompileError, /popping value from empty stack/);
|
||||
|
||||
|
@ -494,8 +493,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
|
|||
(i32.const 0)
|
||||
(i32.const 1)
|
||||
(i32.const 2)
|
||||
(rtt.canon $r)
|
||||
struct.new_with_rtt $r)
|
||||
struct.new $r)
|
||||
)`)),
|
||||
WebAssembly.CompileError, /unused values/);
|
||||
|
||||
|
@ -505,7 +503,7 @@ assertErrorMessage(() => new WebAssembly.Module(wasmTextToBinary(`
|
|||
(module
|
||||
(type (func (param i32) (result i32)))
|
||||
(func $f (result eqref)
|
||||
(struct.new_with_rtt 0))
|
||||
(struct.new 0))
|
||||
)`)),
|
||||
WebAssembly.CompileError, /not a struct type/);
|
||||
|
||||
|
@ -517,7 +515,7 @@ wasmEvalText(`
|
|||
(type $p (struct (field i32)))
|
||||
(type $q (struct (field i32)))
|
||||
(func $f (result (ref null $p))
|
||||
(struct.new_with_rtt $q (i32.const 0) (rtt.canon $q))))
|
||||
(struct.new $q (i32.const 0))))
|
||||
`);
|
||||
|
||||
// The field name is optional, so this should work.
|
||||
|
@ -594,7 +592,7 @@ WebAssembly.CompileError, /signature index references non-signature/);
|
|||
(field i32)
|
||||
(field (mut i64))))
|
||||
(func (export "make") (result eqref)
|
||||
(struct.new_with_rtt $s (i32.const 37) (i64.const 42) (rtt.canon $s))))`).exports;
|
||||
(struct.new $s (i32.const 37) (i64.const 42))))`).exports;
|
||||
let v = ins.make();
|
||||
assertErrorMessage(() => v[0] = 12,
|
||||
Error,
|
||||
|
|
|
@ -211,45 +211,3 @@ assertSubtype(
|
|||
'(array (ref 3))',
|
||||
'(struct)',
|
||||
'(struct (field i32))']);
|
||||
|
||||
// Rtt subtyping is equivalence
|
||||
assertSubtype(
|
||||
'(rtt 0 0)',
|
||||
'(rtt 0 1)',
|
||||
['(struct)',
|
||||
'(struct)']);
|
||||
assertNotSubtype(
|
||||
'(rtt 0 0)',
|
||||
'(rtt 0 1)',
|
||||
['(struct)',
|
||||
'(struct (field i32))']);
|
||||
|
||||
// An rtt with depth can be a subtype of rtt without depth
|
||||
assertSubtype(
|
||||
'(rtt $0)',
|
||||
'(rtt 0 $0)',
|
||||
['(struct)']);
|
||||
|
||||
// An rtt without depth is not a subtype of an rtt with depth
|
||||
assertNotSubtype(
|
||||
'(rtt 0 $0)',
|
||||
'(rtt $0)',
|
||||
['(struct)']);
|
||||
|
||||
// Rtts with depth must have the same depth
|
||||
assertSubtype(
|
||||
'(rtt 0 $0)',
|
||||
'(rtt 0 $0)',
|
||||
['(struct)']);
|
||||
assertSubtype(
|
||||
'(rtt 1 $0)',
|
||||
'(rtt 1 $0)',
|
||||
['(struct)']);
|
||||
assertNotSubtype(
|
||||
'(rtt 1 $0)',
|
||||
'(rtt 0 $0)',
|
||||
['(struct)']);
|
||||
assertNotSubtype(
|
||||
'(rtt 2 $0)',
|
||||
'(rtt 1 $0)',
|
||||
['(struct)']);
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
(func (export "set_null") (param i32)
|
||||
(table.set (local.get 0) (ref.null eq)))
|
||||
(func (export "set_ref") (param i32) (param eqref)
|
||||
(table.set (local.get 0) (ref.cast (local.get 1) (rtt.canon $dummy))))
|
||||
(table.set (local.get 0) (ref.cast $dummy (local.get 1))))
|
||||
(func (export "make_struct") (result eqref)
|
||||
(struct.new_with_rtt $dummy (i32.const 37) (rtt.canon $dummy))))`);
|
||||
(struct.new $dummy (i32.const 37))))`);
|
||||
let a = ins.exports.make_struct();
|
||||
ins.exports.set_eqref(3, a);
|
||||
assertEq(ins.exports.t.get(3), a);
|
||||
|
@ -39,7 +39,7 @@
|
|||
(type $S (struct (field i32) (field f64)))
|
||||
(table (export "t") 2 eqref)
|
||||
(func (export "f") (result i32)
|
||||
(table.grow (struct.new_with_rtt $S (i32.const 0) (f64.const 3.14) (rtt.canon $S)) (i32.const 1))))`);
|
||||
(table.grow (struct.new $S (i32.const 0) (f64.const 3.14)) (i32.const 1))))`);
|
||||
assertEq(ins.exports.t.length, 2);
|
||||
assertEq(ins.exports.f(), 2);
|
||||
assertEq(ins.exports.t.length, 3);
|
||||
|
|
|
@ -9347,7 +9347,6 @@ AttachDecision CallIRGenerator::tryAttachWasmCall(HandleFunction calleeFunc) {
|
|||
return AttachDecision::NoAction;
|
||||
}
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::V128:
|
||||
MOZ_CRASH("Function should not have a Wasm JitEntry");
|
||||
case wasm::ValType::Ref:
|
||||
|
|
|
@ -16795,7 +16795,6 @@ void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
|
|||
case wasm::ValType::F64:
|
||||
argMir = ToMIRType(sig.args()[i]);
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::V128:
|
||||
MOZ_CRASH("unexpected argument type when calling from ion to wasm");
|
||||
case wasm::ValType::Ref:
|
||||
|
@ -16870,7 +16869,6 @@ void CodeGenerator::emitIonToWasmCallBase(LIonToWasmCallBase<NumDefs>* lir) {
|
|||
MOZ_ASSERT(lir->mir()->type() == MIRType::Double);
|
||||
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::V128:
|
||||
MOZ_CRASH("unexpected return type when calling from ion to wasm");
|
||||
case wasm::ValType::Ref:
|
||||
|
|
|
@ -4985,7 +4985,6 @@ MDefinition* WarpCacheIRTranspiler::convertWasmArg(MDefinition* arg,
|
|||
case wasm::ValType::F64:
|
||||
conversion = MToDouble::New(alloc(), arg);
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::V128:
|
||||
MOZ_CRASH("Unexpected type for Wasm JitEntry");
|
||||
case wasm::ValType::Ref:
|
||||
|
|
|
@ -18,5 +18,5 @@ gluesmith = ['jsrust_shared/gluesmith']
|
|||
jsrust_shared = { path = "./shared" }
|
||||
# Workaround for https://github.com/rust-lang/rust/issues/58393
|
||||
mozglue-static = { path = "../../../mozglue/static/rust" }
|
||||
wast = { version = "41.0.0" }
|
||||
wasmparser = { version = "0.78.2" }
|
||||
wast = { version = "44.0.0" }
|
||||
wasmparser = { version = "0.87.0" }
|
||||
|
|
|
@ -51,20 +51,14 @@ void GeckoProfilerRuntime::setEventMarker(void (*fn)(const char*,
|
|||
}
|
||||
|
||||
// Get a pointer to the top-most profiling frame, given the exit frame pointer.
|
||||
static jit::JitFrameLayout* GetTopProfilingJitFrame(Activation* act) {
|
||||
if (!act || !act->isJit()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
jit::JitActivation* jitActivation = act->asJit();
|
||||
|
||||
static jit::JitFrameLayout* GetTopProfilingJitFrame(jit::JitActivation* act) {
|
||||
// If there is no exit frame set, just return.
|
||||
if (!jitActivation->hasExitFP()) {
|
||||
if (!act->hasExitFP()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Skip wasm frames that might be in the way.
|
||||
OnlyJSJitFrameIter iter(jitActivation);
|
||||
OnlyJSJitFrameIter iter(act);
|
||||
if (iter.done()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -118,16 +112,12 @@ void GeckoProfilerRuntime::enable(bool enabled) {
|
|||
// Walk through all activations, and set their lastProfilingFrame
|
||||
// appropriately.
|
||||
if (enabled) {
|
||||
Activation* act = cx->activation();
|
||||
auto* lastProfilingFrame = GetTopProfilingJitFrame(act);
|
||||
|
||||
jit::JitActivation* jitActivation = cx->jitActivation;
|
||||
while (jitActivation) {
|
||||
auto* lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
|
||||
jitActivation->setLastProfilingFrame(lastProfilingFrame);
|
||||
jitActivation->setLastProfilingCallSite(nullptr);
|
||||
|
||||
jitActivation = jitActivation->prevJitActivation();
|
||||
lastProfilingFrame = GetTopProfilingJitFrame(jitActivation);
|
||||
}
|
||||
} else {
|
||||
jit::JitActivation* jitActivation = cx->jitActivation;
|
||||
|
|
|
@ -6589,8 +6589,6 @@ static bool ValidateGlobalVariable(JSContext* cx, const AsmJSGlobal& global,
|
|||
MOZ_CRASH("int64");
|
||||
case ValType::V128:
|
||||
MOZ_CRASH("v128");
|
||||
case ValType::Rtt:
|
||||
MOZ_CRASH("rtt");
|
||||
case ValType::F32: {
|
||||
float f;
|
||||
if (!RoundFloat32(cx, v, &f)) {
|
||||
|
|
|
@ -1595,17 +1595,15 @@ struct BaseCompiler final {
|
|||
[[nodiscard]] bool emitTableSetAnyRef(uint32_t tableIndex);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
[[nodiscard]] bool emitStructNewWithRtt();
|
||||
[[nodiscard]] bool emitStructNewDefaultWithRtt();
|
||||
[[nodiscard]] bool emitStructNew();
|
||||
[[nodiscard]] bool emitStructNewDefault();
|
||||
[[nodiscard]] bool emitStructGet(FieldExtension extension);
|
||||
[[nodiscard]] bool emitStructSet();
|
||||
[[nodiscard]] bool emitArrayNewWithRtt();
|
||||
[[nodiscard]] bool emitArrayNewDefaultWithRtt();
|
||||
[[nodiscard]] bool emitArrayNew();
|
||||
[[nodiscard]] bool emitArrayNewDefault();
|
||||
[[nodiscard]] bool emitArrayGet(FieldExtension extension);
|
||||
[[nodiscard]] bool emitArraySet();
|
||||
[[nodiscard]] bool emitArrayLen();
|
||||
[[nodiscard]] bool emitRttCanon();
|
||||
[[nodiscard]] bool emitRttSub();
|
||||
[[nodiscard]] bool emitRefTest();
|
||||
[[nodiscard]] bool emitRefCast();
|
||||
[[nodiscard]] bool emitBrOnCast();
|
||||
|
|
|
@ -357,7 +357,6 @@ void BaseCompiler::needResultRegisters(ResultType type, ResultRegKind which) {
|
|||
needF64(RegF64(result.fpr()));
|
||||
}
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
needRef(RegRef(result.gpr()));
|
||||
break;
|
||||
|
@ -418,7 +417,6 @@ void BaseCompiler::freeResultRegisters(ResultType type, ResultRegKind which) {
|
|||
freeF64(RegF64(result.fpr()));
|
||||
}
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
freeRef(RegRef(result.gpr()));
|
||||
break;
|
||||
|
|
|
@ -151,7 +151,6 @@ struct Stk {
|
|||
case ValType::F64:
|
||||
k = Stk::MemF64;
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
k = Stk::MemRef;
|
||||
break;
|
||||
|
|
|
@ -814,7 +814,6 @@ void BaseCompiler::saveRegisterReturnValues(const ResultType& resultType) {
|
|||
case ValType::F32:
|
||||
masm.storeFloat32(RegF32(result.fpr()), dest);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
uint32_t flag =
|
||||
DebugFrame::hasSpilledRegisterRefResultBitMask(registerResultIdx);
|
||||
|
@ -867,7 +866,6 @@ void BaseCompiler::restoreRegisterReturnValues(const ResultType& resultType) {
|
|||
case ValType::F32:
|
||||
masm.loadFloat32(src, RegF32(result.fpr()));
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
masm.loadPtr(src, RegRef(result.gpr()));
|
||||
break;
|
||||
|
@ -934,7 +932,6 @@ void BaseCompiler::popRegisterResults(ABIResultIter& iter) {
|
|||
case ValType::F64:
|
||||
popF64(RegF64(result.fpr()));
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
popRef(RegRef(result.gpr()));
|
||||
break;
|
||||
|
@ -1201,7 +1198,6 @@ bool BaseCompiler::pushResults(ResultType type, StackHeight resultsBase) {
|
|||
case ValType::F64:
|
||||
pushF64(RegF64(result.fpr()));
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
pushRef(RegRef(result.gpr()));
|
||||
break;
|
||||
|
@ -1531,7 +1527,6 @@ void BaseCompiler::passArg(ValType type, const Stk& arg, FunctionCall* call) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
ABIArg argLoc = call->abi.next(MIRType::RefOrNull);
|
||||
if (argLoc.kind() == ABIArg::Stack) {
|
||||
|
@ -4026,7 +4021,6 @@ bool BaseCompiler::emitCatch() {
|
|||
MOZ_CRASH("No SIMD support");
|
||||
#endif
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
// TODO/AnyRef-boxing: With boxed immediates and strings, this may need
|
||||
// to handle other kinds of values.
|
||||
|
@ -4379,7 +4373,6 @@ bool BaseCompiler::emitThrow() {
|
|||
MOZ_CRASH("No SIMD support");
|
||||
#endif
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
RegPtr valueAddr(PreBarrierReg);
|
||||
needPtr(valueAddr);
|
||||
|
@ -5059,7 +5052,6 @@ bool BaseCompiler::emitGetLocal() {
|
|||
case ValType::F32:
|
||||
pushLocalF32(slot);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
pushLocalRef(slot);
|
||||
break;
|
||||
|
@ -5135,7 +5127,6 @@ bool BaseCompiler::emitSetOrTeeLocal(uint32_t slot) {
|
|||
MOZ_CRASH("No SIMD support");
|
||||
#endif
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
RegRef rv = popRef();
|
||||
syncLocal(slot);
|
||||
|
@ -5240,7 +5231,6 @@ bool BaseCompiler::emitGetGlobal() {
|
|||
pushF64(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
RegRef rv = needRef();
|
||||
ScratchPtr tmp(*this);
|
||||
|
@ -5306,7 +5296,6 @@ bool BaseCompiler::emitSetGlobal() {
|
|||
freeF64(rv);
|
||||
break;
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref: {
|
||||
RegPtr valueAddr(PreBarrierReg);
|
||||
needPtr(valueAddr);
|
||||
|
@ -6531,13 +6520,12 @@ bool BaseCompiler::emitGcArraySet(RegRef object, RegPtr data, RegI32 index,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitStructNewWithRtt() {
|
||||
bool BaseCompiler::emitStructNew() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
uint32_t typeIndex;
|
||||
Nothing rtt;
|
||||
BaseNothingVector args{};
|
||||
if (!iter_.readStructNewWithRtt(&typeIndex, &rtt, &args)) {
|
||||
if (!iter_.readStructNew(&typeIndex, &args)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6547,10 +6535,9 @@ bool BaseCompiler::emitStructNewWithRtt() {
|
|||
|
||||
const StructType& structType = (*moduleEnv_.types)[typeIndex].structType();
|
||||
|
||||
// Allocate zeroed storage. The parameter to StructNew is a rtt value that is
|
||||
// guaranteed to be at the top of the stack by validation.
|
||||
//
|
||||
// Traps on OOM.
|
||||
// Allocate a default initialized struct. This requires the rtt value for the
|
||||
// struct to be pushed on the stack. This will trap on OOM.
|
||||
emitGcCanon(typeIndex);
|
||||
if (!emitInstanceCall(lineOrBytecode, SASigStructNew)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6611,18 +6598,21 @@ bool BaseCompiler::emitStructNewWithRtt() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitStructNewDefaultWithRtt() {
|
||||
// Allocate zeroed storage. The parameter to StructNew is a rtt value that is
|
||||
// guaranteed to be at the top of the stack by validation.
|
||||
//
|
||||
// Traps on OOM.
|
||||
bool BaseCompiler::emitStructNewDefault() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
// (rtt) -> ref; the type index is just dropped on the floor
|
||||
return emitInstanceCallOp(SASigStructNew, [this]() -> bool {
|
||||
uint32_t unusedTypeIndex;
|
||||
Nothing unusedRtt;
|
||||
return iter_.readStructNewDefaultWithRtt(&unusedTypeIndex, &unusedRtt);
|
||||
});
|
||||
uint32_t typeIndex;
|
||||
if (!iter_.readStructNewDefault(&typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
if (deadCode_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate a default initialized struct. This requires the rtt value for the
|
||||
// struct to be pushed on the stack. This will trap on OOM.
|
||||
emitGcCanon(typeIndex);
|
||||
return emitInstanceCall(lineOrBytecode, SASigStructNew);
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitStructGet(FieldExtension extension) {
|
||||
|
@ -6743,12 +6733,12 @@ bool BaseCompiler::emitStructSet() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitArrayNewWithRtt() {
|
||||
bool BaseCompiler::emitArrayNew() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
uint32_t typeIndex;
|
||||
Nothing nothing;
|
||||
if (!iter_.readArrayNewWithRtt(&typeIndex, ¬hing, ¬hing, ¬hing)) {
|
||||
if (!iter_.readArrayNew(&typeIndex, ¬hing, ¬hing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6758,10 +6748,9 @@ bool BaseCompiler::emitArrayNewWithRtt() {
|
|||
|
||||
const ArrayType& arrayType = (*moduleEnv_.types)[typeIndex].arrayType();
|
||||
|
||||
// Allocate zeroed storage. The parameter to ArrayNew is a rtt value and
|
||||
// length that are guaranteed to be at the top of the stack by validation.
|
||||
//
|
||||
// Traps on OOM.
|
||||
// Allocate a default initialized array. This requires the rtt value for the
|
||||
// array to be pushed on the stack. This will trap on OOM.
|
||||
emitGcCanon(typeIndex);
|
||||
if (!emitInstanceCall(lineOrBytecode, SASigArrayNew)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6815,19 +6804,23 @@ bool BaseCompiler::emitArrayNewWithRtt() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitArrayNewDefaultWithRtt() {
|
||||
// Allocate zeroed storage. The parameter to ArrayNew is a rtt value that is
|
||||
// guaranteed to be at the top of the stack by validation.
|
||||
//
|
||||
// Traps on OOM.
|
||||
bool BaseCompiler::emitArrayNewDefault() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
// (rtt) -> ref; the type index is dropped on the floor.
|
||||
return emitInstanceCallOp(SASigArrayNew, [this]() -> bool {
|
||||
uint32_t unusedTypeIndex;
|
||||
Nothing nothing;
|
||||
return iter_.readArrayNewDefaultWithRtt(&unusedTypeIndex, ¬hing,
|
||||
¬hing);
|
||||
});
|
||||
uint32_t typeIndex;
|
||||
Nothing nothing;
|
||||
if (!iter_.readArrayNewDefault(&typeIndex, ¬hing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deadCode_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Allocate a default initialized array. This requires the rtt value for the
|
||||
// array to be pushed on the stack. This will trap on OOM.
|
||||
emitGcCanon(typeIndex);
|
||||
return emitInstanceCall(lineOrBytecode, SASigArrayNew);
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitArrayGet(FieldExtension extension) {
|
||||
|
@ -6969,26 +6962,12 @@ bool BaseCompiler::emitArrayLen() {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitRttCanon() {
|
||||
ValType rttType;
|
||||
if (!iter_.readRttCanon(&rttType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (deadCode_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
emitGcCanon(rttType.typeIndex());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitRttSub() {
|
||||
bool BaseCompiler::emitRefTest() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
Nothing nothing;
|
||||
uint32_t rttSubTypeIndex;
|
||||
if (!iter_.readRttSub(¬hing, &rttSubTypeIndex)) {
|
||||
uint32_t typeIndex;
|
||||
if (!iter_.readRefTest(&typeIndex, ¬hing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -6996,36 +6975,16 @@ bool BaseCompiler::emitRttSub() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// rtt.sub $t; [(rtt $t' _)] -> [(rtt $t _)]
|
||||
// Push (rtt.canon $t) so that we can cache the result and yield the
|
||||
// same rtt value for the same $t operand.
|
||||
emitGcCanon(rttSubTypeIndex);
|
||||
|
||||
if (!emitInstanceCall(lineOrBytecode, SASigRttSub)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitRefTest() {
|
||||
// refTest builtin has same signature as ref.test instruction, stack is
|
||||
// guaranteed to be in the right condition due to validation.
|
||||
return emitInstanceCallOp(SASigRefTest, [this]() -> bool {
|
||||
Nothing nothing;
|
||||
uint32_t unusedRttTypeIndex;
|
||||
uint32_t unusedRttDepth;
|
||||
return iter_.readRefTest(¬hing, &unusedRttTypeIndex, &unusedRttDepth,
|
||||
¬hing);
|
||||
});
|
||||
emitGcCanon(typeIndex);
|
||||
return emitInstanceCall(lineOrBytecode, SASigRefTest);
|
||||
}
|
||||
|
||||
bool BaseCompiler::emitRefCast() {
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
|
||||
Nothing nothing;
|
||||
uint32_t rttTypeIndex;
|
||||
uint32_t rttDepth;
|
||||
if (!iter_.readRefCast(¬hing, &rttTypeIndex, &rttDepth, ¬hing)) {
|
||||
uint32_t typeIndex;
|
||||
if (!iter_.readRefCast(&typeIndex, ¬hing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -7033,7 +6992,6 @@ bool BaseCompiler::emitRefCast() {
|
|||
return true;
|
||||
}
|
||||
|
||||
RegRef rttPtr = popRef();
|
||||
RegRef refPtr = popRef();
|
||||
|
||||
// 1. duplicate and shuffle from [ref, rtt] to [ref, ref, rtt]
|
||||
|
@ -7041,7 +6999,7 @@ bool BaseCompiler::emitRefCast() {
|
|||
moveRef(refPtr, castedPtr);
|
||||
pushRef(castedPtr);
|
||||
pushRef(refPtr);
|
||||
pushRef(rttPtr);
|
||||
emitGcCanon(typeIndex);
|
||||
|
||||
// 2. ref.test : [ref, rtt] -> [i32]
|
||||
if (!emitInstanceCall(lineOrBytecode, SASigRefTest)) {
|
||||
|
@ -7064,13 +7022,11 @@ bool BaseCompiler::emitBrOnCast() {
|
|||
|
||||
uint32_t lineOrBytecode = readCallSiteLineOrBytecode();
|
||||
uint32_t relativeDepth;
|
||||
Nothing unused{};
|
||||
BaseNothingVector unused_values{};
|
||||
uint32_t rttTypeIndex;
|
||||
uint32_t rttDepth;
|
||||
uint32_t typeIndex;
|
||||
ResultType branchTargetType;
|
||||
if (!iter_.readBrOnCast(&relativeDepth, &unused, &rttTypeIndex, &rttDepth,
|
||||
&branchTargetType, &unused_values)) {
|
||||
if (!iter_.readBrOnCast(&relativeDepth, &typeIndex, &branchTargetType,
|
||||
&unused_values)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -7081,7 +7037,6 @@ bool BaseCompiler::emitBrOnCast() {
|
|||
Control& target = controlItem(relativeDepth);
|
||||
target.bceSafeOnExit &= bceSafe_;
|
||||
|
||||
RegRef rttPtr = popRef();
|
||||
RegRef refPtr = popRef();
|
||||
|
||||
// 1. duplicate and shuffle from [T*, ref, rtt] to [T*, ref, ref, rtt]
|
||||
|
@ -7089,7 +7044,7 @@ bool BaseCompiler::emitBrOnCast() {
|
|||
moveRef(refPtr, castedPtr);
|
||||
pushRef(castedPtr);
|
||||
pushRef(refPtr);
|
||||
pushRef(rttPtr);
|
||||
emitGcCanon(typeIndex);
|
||||
|
||||
// 2. ref.test : [ref, rtt] -> [i32]
|
||||
if (!emitInstanceCall(lineOrBytecode, SASigRefTest)) {
|
||||
|
@ -9200,10 +9155,10 @@ bool BaseCompiler::emitBody() {
|
|||
return iter_.unrecognizedOpcode(&op);
|
||||
}
|
||||
switch (op.b1) {
|
||||
case uint32_t(GcOp::StructNewWithRtt):
|
||||
CHECK_NEXT(emitStructNewWithRtt());
|
||||
case uint32_t(GcOp::StructNewDefaultWithRtt):
|
||||
CHECK_NEXT(emitStructNewDefaultWithRtt());
|
||||
case uint32_t(GcOp::StructNew):
|
||||
CHECK_NEXT(emitStructNew());
|
||||
case uint32_t(GcOp::StructNewDefault):
|
||||
CHECK_NEXT(emitStructNewDefault());
|
||||
case uint32_t(GcOp::StructGet):
|
||||
CHECK_NEXT(emitStructGet(FieldExtension::None));
|
||||
case uint32_t(GcOp::StructGetS):
|
||||
|
@ -9212,10 +9167,10 @@ bool BaseCompiler::emitBody() {
|
|||
CHECK_NEXT(emitStructGet(FieldExtension::Unsigned));
|
||||
case uint32_t(GcOp::StructSet):
|
||||
CHECK_NEXT(emitStructSet());
|
||||
case uint32_t(GcOp::ArrayNewWithRtt):
|
||||
CHECK_NEXT(emitArrayNewWithRtt());
|
||||
case uint32_t(GcOp::ArrayNewDefaultWithRtt):
|
||||
CHECK_NEXT(emitArrayNewDefaultWithRtt());
|
||||
case uint32_t(GcOp::ArrayNew):
|
||||
CHECK_NEXT(emitArrayNew());
|
||||
case uint32_t(GcOp::ArrayNewDefault):
|
||||
CHECK_NEXT(emitArrayNewDefault());
|
||||
case uint32_t(GcOp::ArrayGet):
|
||||
CHECK_NEXT(emitArrayGet(FieldExtension::None));
|
||||
case uint32_t(GcOp::ArrayGetS):
|
||||
|
@ -9226,10 +9181,6 @@ bool BaseCompiler::emitBody() {
|
|||
CHECK_NEXT(emitArraySet());
|
||||
case uint32_t(GcOp::ArrayLen):
|
||||
CHECK_NEXT(emitArrayLen());
|
||||
case uint32_t(GcOp::RttCanon):
|
||||
CHECK_NEXT(emitRttCanon());
|
||||
case uint32_t(GcOp::RttSub):
|
||||
CHECK_NEXT(emitRttSub());
|
||||
case uint32_t(GcOp::RefTest):
|
||||
CHECK_NEXT(emitRefTest());
|
||||
case uint32_t(GcOp::RefCast):
|
||||
|
@ -10219,7 +10170,6 @@ void BaseCompiler::assertResultRegistersAvailable(ResultType type) {
|
|||
case ValType::F64:
|
||||
MOZ_ASSERT(isAvailableF64(RegF64(result.fpr())));
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
MOZ_ASSERT(isAvailableRef(RegRef(result.gpr())));
|
||||
break;
|
||||
|
|
|
@ -653,15 +653,6 @@ inline ValType Decoder::uncheckedReadValType() {
|
|||
case uint8_t(TypeCode::FuncRef):
|
||||
case uint8_t(TypeCode::ExternRef):
|
||||
return RefType::fromTypeCode(TypeCode(code), true);
|
||||
case uint8_t(TypeCode::RttWithDepth): {
|
||||
uint32_t rttDepth = uncheckedReadVarU32();
|
||||
int32_t typeIndex = uncheckedReadVarS32();
|
||||
return ValType::fromRtt(typeIndex, rttDepth);
|
||||
}
|
||||
case uint8_t(TypeCode::Rtt): {
|
||||
int32_t typeIndex = uncheckedReadVarS32();
|
||||
return ValType::fromRtt(typeIndex, RttDepthNone);
|
||||
}
|
||||
case uint8_t(TypeCode::Ref):
|
||||
case uint8_t(TypeCode::NullableRef): {
|
||||
bool nullable = code == uint8_t(TypeCode::NullableRef);
|
||||
|
@ -722,34 +713,6 @@ inline bool Decoder::readPackedType(uint32_t numTypes,
|
|||
return true;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
case uint8_t(TypeCode::Rtt):
|
||||
case uint8_t(TypeCode::RttWithDepth): {
|
||||
#ifdef ENABLE_WASM_GC
|
||||
if (!features.gc) {
|
||||
return fail("gc types not enabled");
|
||||
}
|
||||
|
||||
uint32_t rttDepth = RttDepthNone;
|
||||
if (code == uint8_t(TypeCode::RttWithDepth) &&
|
||||
(!readVarU32(&rttDepth) || uint32_t(rttDepth) >= MaxRttDepth)) {
|
||||
return fail("invalid rtt depth");
|
||||
}
|
||||
|
||||
RefType heapType;
|
||||
if (!readHeapType(numTypes, features, true, &heapType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!heapType.isTypeIndex()) {
|
||||
return fail("invalid heap type for rtt");
|
||||
}
|
||||
|
||||
*type = T::fromRtt(heapType.typeIndex(), rttDepth);
|
||||
return true;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
case uint8_t(TypeCode::EqRef): {
|
||||
|
|
|
@ -291,8 +291,6 @@ const SymbolicAddressSignature SASigArrayNew = {SymbolicAddress::ArrayNew,
|
|||
{_PTR, _I32, _RoN, _END}};
|
||||
const SymbolicAddressSignature SASigRefTest = {
|
||||
SymbolicAddress::RefTest, _I32, _Infallible, 3, {_PTR, _RoN, _RoN, _END}};
|
||||
const SymbolicAddressSignature SASigRttSub = {
|
||||
SymbolicAddress::RttSub, _RoN, _FailOnNullPtr, 3, {_PTR, _RoN, _RoN, _END}};
|
||||
#define DECL_SAS_FOR_INTRINSIC(op, export, sa_name, abitype, entry, idx) \
|
||||
const SymbolicAddressSignature SASig##sa_name = { \
|
||||
SymbolicAddress::sa_name, _VOID, _FailOnNegI32, \
|
||||
|
@ -1267,10 +1265,6 @@ void* wasm::AddressOf(SymbolicAddress imm, ABIFunctionType* abiType) {
|
|||
*abiType = Args_Int32_GeneralGeneralGeneral;
|
||||
MOZ_ASSERT(*abiType == ToABIType(SASigRefTest));
|
||||
return FuncCast(Instance::refTest, *abiType);
|
||||
case SymbolicAddress::RttSub:
|
||||
*abiType = Args_General3;
|
||||
MOZ_ASSERT(*abiType == ToABIType(SASigRttSub));
|
||||
return FuncCast(Instance::rttSub, *abiType);
|
||||
case SymbolicAddress::InlineTypedObjectClass:
|
||||
// The ABI type is not used here, but assigning one to avoid garbage.
|
||||
*abiType = Args_General1;
|
||||
|
@ -1453,7 +1447,6 @@ bool wasm::NeedsBuiltinThunk(SymbolicAddress sym) {
|
|||
case SymbolicAddress::ThrowException:
|
||||
case SymbolicAddress::ArrayNew:
|
||||
case SymbolicAddress::RefTest:
|
||||
case SymbolicAddress::RttSub:
|
||||
#define OP(op, export, sa_name, abitype, entry, idx) \
|
||||
case SymbolicAddress::sa_name:
|
||||
FOR_EACH_INTRINSIC(OP)
|
||||
|
|
|
@ -119,7 +119,6 @@ enum class SymbolicAddress {
|
|||
TableSize,
|
||||
RefFunc,
|
||||
RefTest,
|
||||
RttSub,
|
||||
PreBarrierFiltering,
|
||||
PostBarrier,
|
||||
PostBarrierPrecise,
|
||||
|
@ -250,7 +249,6 @@ extern const SymbolicAddressSignature SASigExceptionNew;
|
|||
extern const SymbolicAddressSignature SASigThrowException;
|
||||
extern const SymbolicAddressSignature SASigArrayNew;
|
||||
extern const SymbolicAddressSignature SASigRefTest;
|
||||
extern const SymbolicAddressSignature SASigRttSub;
|
||||
#define EXT_INTR_SA_DECL(op, export, sa_name, abitype, entry, idx) \
|
||||
extern const SymbolicAddressSignature SASig##sa_name;
|
||||
FOR_EACH_INTRINSIC(EXT_INTR_SA_DECL)
|
||||
|
|
|
@ -81,10 +81,6 @@ enum class TypeCode {
|
|||
// Type constructor for non-nullable reference types.
|
||||
Ref = 0x6b, // SLEB128(-0x15)
|
||||
|
||||
// Type constructors for rtt types.
|
||||
RttWithDepth = 0x69, // SLEB128(-0x17)
|
||||
Rtt = 0x68, // SLEB128(-0x18)
|
||||
|
||||
// Type constructor for function types
|
||||
Func = 0x60, // SLEB128(-0x20)
|
||||
|
||||
|
@ -116,11 +112,6 @@ static constexpr TypeCode AbstractReferenceTypeCode = TypeCode::ExternRef;
|
|||
|
||||
static constexpr TypeCode AbstractReferenceTypeIndexCode = TypeCode::Ref;
|
||||
|
||||
// A type code used to represent (rtt depth? typeindex) whether or not the type
|
||||
// is encoded with 'Rtt' or 'RttWithDepth'.
|
||||
|
||||
static constexpr TypeCode AbstractRttCode = TypeCode::Rtt;
|
||||
|
||||
enum class TypeIdDescKind { None, Immediate, Global };
|
||||
|
||||
// A wasm::Trap represents a wasm-defined trap that can occur during execution
|
||||
|
@ -458,30 +449,26 @@ inline bool IsPrefixByte(uint8_t b) { return b >= uint8_t(Op::FirstPrefix); }
|
|||
// Opcodes in the GC opcode space.
|
||||
enum class GcOp {
|
||||
// Structure operations
|
||||
StructNewWithRtt = 0x1,
|
||||
StructNewDefaultWithRtt = 0x2,
|
||||
StructNew = 0x7,
|
||||
StructNewDefault = 0x8,
|
||||
StructGet = 0x03,
|
||||
StructGetS = 0x04,
|
||||
StructGetU = 0x05,
|
||||
StructSet = 0x06,
|
||||
|
||||
// Array operations
|
||||
ArrayNewWithRtt = 0x11,
|
||||
ArrayNewDefaultWithRtt = 0x12,
|
||||
ArrayNew = 0x1b,
|
||||
ArrayNewDefault = 0x1c,
|
||||
ArrayGet = 0x13,
|
||||
ArrayGetS = 0x14,
|
||||
ArrayGetU = 0x15,
|
||||
ArraySet = 0x16,
|
||||
ArrayLen = 0x17,
|
||||
|
||||
// Rtt operations
|
||||
RttCanon = 0x30,
|
||||
RttSub = 0x31,
|
||||
|
||||
// Ref operations
|
||||
RefTest = 0x40,
|
||||
RefCast = 0x41,
|
||||
BrOnCast = 0x42,
|
||||
RefTest = 0x44,
|
||||
RefCast = 0x45,
|
||||
BrOnCast = 0x46,
|
||||
|
||||
Limit
|
||||
};
|
||||
|
@ -1019,10 +1006,8 @@ static const unsigned MaxFunctionBytes = 7654321;
|
|||
// platform
|
||||
#ifdef JS_64BIT
|
||||
static const unsigned MaxTypeIndex = 1000000;
|
||||
static const unsigned MaxRttDepth = 1000;
|
||||
#else
|
||||
static const unsigned MaxTypeIndex = 15000;
|
||||
static const unsigned MaxRttDepth = 100;
|
||||
#endif
|
||||
|
||||
static const unsigned MaxTags = 1000000;
|
||||
|
@ -1043,10 +1028,6 @@ static const unsigned MaxCodeSectionBytes = MaxModuleBytes;
|
|||
|
||||
static const unsigned MaxFrameSize = 512 * 1024;
|
||||
|
||||
// A magic value of rtt depth to signify that it was not specified.
|
||||
|
||||
static const uint32_t RttDepthNone = MaxRttDepth + 1;
|
||||
|
||||
// Asserted by Decoder::readVarU32.
|
||||
|
||||
static const unsigned MaxVarU32DecodedBytes = 5;
|
||||
|
|
|
@ -69,7 +69,6 @@ class DebugFrame {
|
|||
case ValType::F32:
|
||||
case ValType::F64:
|
||||
case ValType::V128:
|
||||
case ValType::Rtt:
|
||||
return;
|
||||
case ValType::Ref:
|
||||
switch (type.refTypeKind()) {
|
||||
|
|
|
@ -1620,8 +1620,6 @@ static const char* ThunkedNativeToDescription(SymbolicAddress func) {
|
|||
return "call to native array.new (in wasm)";
|
||||
case SymbolicAddress::RefTest:
|
||||
return "call to native ref.test (in wasm)";
|
||||
case SymbolicAddress::RttSub:
|
||||
return "call to native rtt.sub (in wasm)";
|
||||
case SymbolicAddress::InlineTypedObjectClass:
|
||||
MOZ_CRASH();
|
||||
#define OP(op, export, sa_name, abitype, entry, idx) \
|
||||
|
|
|
@ -175,35 +175,6 @@ static bool ValidateInitExpr(Decoder& d, ModuleEnvironment* env,
|
|||
*literal = Nothing();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case uint16_t(Op::GcPrefix): {
|
||||
if (!env->gcEnabled()) {
|
||||
return iter.unrecognizedOpcode(&op);
|
||||
}
|
||||
switch (op.b1) {
|
||||
case uint16_t(GcOp::RttCanon): {
|
||||
ValType unusedTy;
|
||||
if (!iter.readRttCanon(&unusedTy)) {
|
||||
return false;
|
||||
}
|
||||
*literal = Nothing();
|
||||
break;
|
||||
}
|
||||
case uint16_t(GcOp::RttSub): {
|
||||
uint32_t unusedRttTypeIndex;
|
||||
if (!iter.readRttSub(¬hing, &unusedRttTypeIndex)) {
|
||||
return false;
|
||||
}
|
||||
*literal = Nothing();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
return iter.unrecognizedOpcode(&op);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
return iter.unrecognizedOpcode(&op);
|
||||
|
@ -248,10 +219,6 @@ class MOZ_STACK_CLASS InitExprInterpreter {
|
|||
bool pushFuncRef(HandleFuncRef ref) {
|
||||
return stack.append(Val(RefType::func(), ref));
|
||||
}
|
||||
bool pushRtt(Handle<RttValue*> rtt) {
|
||||
// The exact rtt type is not important, evaluation won't use it
|
||||
return stack.append(Val(ValType::fromRtt(0, 0), AnyRef::fromJSObject(rtt)));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_EXTENDED_CONST
|
||||
int32_t popI32() {
|
||||
|
@ -265,13 +232,6 @@ class MOZ_STACK_CLASS InitExprInterpreter {
|
|||
return int64_t(result);
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_GC
|
||||
RttValue* popRtt(JSContext* cx) {
|
||||
RootedAnyRef result(cx, stack.back().ref());
|
||||
stack.popBack();
|
||||
return &result.get().asJSObject()->as<RttValue>();
|
||||
}
|
||||
#endif
|
||||
|
||||
bool evalGetGlobal(uint32_t index) {
|
||||
return stack.append(globalImportValues[index]);
|
||||
|
@ -327,23 +287,6 @@ class MOZ_STACK_CLASS InitExprInterpreter {
|
|||
return true;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_GC
|
||||
bool evalRttCanon(JSContext* cx, uint32_t typeIndex) {
|
||||
Rooted<RttValue*> result(cx, nullptr);
|
||||
if (!instance().constantRttCanon(cx, typeIndex, &result)) {
|
||||
return false;
|
||||
}
|
||||
return pushRtt(result);
|
||||
}
|
||||
bool evalRttSub(JSContext* cx, uint32_t typeIndex) {
|
||||
Rooted<RttValue*> parentRtt(cx, popRtt(cx));
|
||||
Rooted<RttValue*> result(cx, nullptr);
|
||||
if (!instance().constantRttSub(cx, parentRtt, typeIndex, &result)) {
|
||||
return false;
|
||||
}
|
||||
return pushRtt(result);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
bool InitExprInterpreter::evaluate(JSContext* cx, Decoder& d) {
|
||||
|
@ -457,32 +400,6 @@ bool InitExprInterpreter::evaluate(JSContext* cx, Decoder& d) {
|
|||
}
|
||||
CHECK(evalI64Mul());
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case uint16_t(Op::GcPrefix): {
|
||||
switch (op.b1) {
|
||||
case uint16_t(GcOp::RttCanon): {
|
||||
uint32_t typeIndex;
|
||||
if (!d.readTypeIndex(&typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
CHECK(evalRttCanon(cx, typeIndex));
|
||||
break;
|
||||
}
|
||||
case uint16_t(GcOp::RttSub): {
|
||||
uint32_t typeIndex;
|
||||
if (!d.readTypeIndex(&typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
CHECK(evalRttSub(cx, typeIndex));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default: {
|
||||
MOZ_CRASH();
|
||||
|
|
|
@ -1266,22 +1266,6 @@ bool Instance::initElems(uint32_t tableIndex, const ElemSegment& seg,
|
|||
return int32_t(ref->isRuntimeSubtype(rtt));
|
||||
}
|
||||
|
||||
/* static */ void* Instance::rttSub(Instance* instance, void* rttParentPtr,
|
||||
void* rttSubCanonPtr) {
|
||||
MOZ_ASSERT(SASigRttSub.failureMode == FailureMode::FailOnNullPtr);
|
||||
JSContext* cx = instance->cx();
|
||||
|
||||
ASSERT_ANYREF_IS_JSOBJECT;
|
||||
Rooted<RttValue*> parentRtt(
|
||||
cx, &AnyRef::fromCompiledCode(rttParentPtr).asJSObject()->as<RttValue>());
|
||||
Rooted<RttValue*> subCanonRtt(
|
||||
cx,
|
||||
&AnyRef::fromCompiledCode(rttSubCanonPtr).asJSObject()->as<RttValue>());
|
||||
|
||||
Rooted<RttValue*> subRtt(cx, RttValue::rttSub(cx, parentRtt, subCanonRtt));
|
||||
return AnyRef::fromJSObject(subRtt.get()).forCompiledCode();
|
||||
}
|
||||
|
||||
/* static */ int32_t Instance::intrI8VecMul(Instance* instance, uint32_t dest,
|
||||
uint32_t src1, uint32_t src2,
|
||||
uint32_t len, uint8_t* memBase) {
|
||||
|
@ -2241,38 +2225,6 @@ bool Instance::constantRefFunc(uint32_t funcIndex,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Instance::constantRttCanon(JSContext* cx, uint32_t sourceTypeIndex,
|
||||
MutableHandle<RttValue*> result) {
|
||||
// Get the renumbered type index from the source type index
|
||||
uint32_t renumberedTypeIndex = metadata().typesRenumbering[sourceTypeIndex];
|
||||
// The original type definition cannot have been a function type, so it
|
||||
// could not have been an immediate type
|
||||
MOZ_ASSERT(renumberedTypeIndex != UINT32_MAX);
|
||||
// Get the TypeIdDesc to find the canonical RttValue
|
||||
const TypeDefWithId& typeDef = metadata().types[renumberedTypeIndex];
|
||||
MOZ_ASSERT(typeDef.isStructType() || typeDef.isArrayType());
|
||||
// Cast from untyped storage to RttValue
|
||||
result.set(*(RttValue**)addressOfTypeId(typeDef.id));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Instance::constantRttSub(JSContext* cx, Handle<RttValue*> parentRtt,
|
||||
uint32_t sourceChildTypeIndex,
|
||||
MutableHandle<RttValue*> result) {
|
||||
Rooted<RttValue*> subCanonRtt(cx, nullptr);
|
||||
// Get the canonical rtt value from the child type index, this is used to
|
||||
// memoize results of rtt.sub
|
||||
if (!constantRttCanon(cx, sourceChildTypeIndex, &subCanonRtt)) {
|
||||
return false;
|
||||
}
|
||||
result.set(RttValue::rttSub(cx, parentRtt, subCanonRtt));
|
||||
if (!result) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSAtom* Instance::getFuncDisplayAtom(JSContext* cx, uint32_t funcIndex) const {
|
||||
// The "display name" of a function is primarily shown in Error.stack which
|
||||
// also includes location, so use getFuncNameBeforeLocation.
|
||||
|
|
|
@ -339,11 +339,6 @@ class alignas(16) Instance {
|
|||
|
||||
[[nodiscard]] bool constantRefFunc(uint32_t funcIndex,
|
||||
MutableHandleFuncRef result);
|
||||
[[nodiscard]] bool constantRttCanon(JSContext* cx, uint32_t sourceTypeIndex,
|
||||
MutableHandle<RttValue*> result);
|
||||
[[nodiscard]] bool constantRttSub(JSContext* cx, Handle<RttValue*> parentRtt,
|
||||
uint32_t sourceChildTypeIndex,
|
||||
MutableHandle<RttValue*> result);
|
||||
|
||||
// Return the name associated with a given function index, or generate one
|
||||
// if none was given by the module.
|
||||
|
@ -455,8 +450,6 @@ class alignas(16) Instance {
|
|||
static int32_t throwException(Instance* instance, JSObject* exn);
|
||||
static void* arrayNew(Instance* instance, uint32_t length, void* arrayDescr);
|
||||
static int32_t refTest(Instance* instance, void* refPtr, void* rttPtr);
|
||||
static void* rttSub(Instance* instance, void* rttParentPtr,
|
||||
void* rttSubCanonPtr);
|
||||
static int32_t intrI8VecMul(Instance* instance, uint32_t dest, uint32_t src1,
|
||||
uint32_t src2, uint32_t len, uint8_t* memBase);
|
||||
};
|
||||
|
|
|
@ -337,7 +337,6 @@ class FunctionCompiler {
|
|||
case ValType::F64:
|
||||
ins = MConstant::New(alloc(), DoubleValue(0.0), MIRType::Double);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
ins = MWasmNullConstant::New(alloc());
|
||||
break;
|
||||
|
@ -1939,7 +1938,6 @@ class FunctionCompiler {
|
|||
def = MWasmFloatRegisterResult::New(alloc(), MIRType::Double,
|
||||
result.fpr());
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::Ref:
|
||||
def = MWasmRegisterResult::New(alloc(), MIRType::RefOrNull,
|
||||
result.gpr());
|
||||
|
|
|
@ -297,20 +297,20 @@ OpKind wasm::Classify(OpBytes op) {
|
|||
case GcOp::Limit:
|
||||
// Reject Limit for GcPrefix encoding
|
||||
break;
|
||||
case GcOp::StructNewWithRtt:
|
||||
WASM_GC_OP(OpKind::StructNewWithRtt);
|
||||
case GcOp::StructNewDefaultWithRtt:
|
||||
WASM_GC_OP(OpKind::StructNewDefaultWithRtt);
|
||||
case GcOp::StructNew:
|
||||
WASM_GC_OP(OpKind::StructNew);
|
||||
case GcOp::StructNewDefault:
|
||||
WASM_GC_OP(OpKind::StructNewDefault);
|
||||
case GcOp::StructGet:
|
||||
case GcOp::StructGetS:
|
||||
case GcOp::StructGetU:
|
||||
WASM_GC_OP(OpKind::StructGet);
|
||||
case GcOp::StructSet:
|
||||
WASM_GC_OP(OpKind::StructSet);
|
||||
case GcOp::ArrayNewWithRtt:
|
||||
WASM_GC_OP(OpKind::ArrayNewWithRtt);
|
||||
case GcOp::ArrayNewDefaultWithRtt:
|
||||
WASM_GC_OP(OpKind::ArrayNewDefaultWithRtt);
|
||||
case GcOp::ArrayNew:
|
||||
WASM_GC_OP(OpKind::ArrayNew);
|
||||
case GcOp::ArrayNewDefault:
|
||||
WASM_GC_OP(OpKind::ArrayNewDefault);
|
||||
case GcOp::ArrayGet:
|
||||
case GcOp::ArrayGetS:
|
||||
case GcOp::ArrayGetU:
|
||||
|
@ -319,10 +319,6 @@ OpKind wasm::Classify(OpBytes op) {
|
|||
WASM_GC_OP(OpKind::ArraySet);
|
||||
case GcOp::ArrayLen:
|
||||
WASM_GC_OP(OpKind::ArrayLen);
|
||||
case GcOp::RttCanon:
|
||||
WASM_GC_OP(OpKind::RttCanon);
|
||||
case GcOp::RttSub:
|
||||
WASM_GC_OP(OpKind::RttSub);
|
||||
case GcOp::RefTest:
|
||||
WASM_GC_OP(OpKind::RefTest);
|
||||
case GcOp::RefCast:
|
||||
|
|
|
@ -180,17 +180,15 @@ enum class OpKind {
|
|||
RefFunc,
|
||||
RefAsNonNull,
|
||||
BrOnNull,
|
||||
StructNewWithRtt,
|
||||
StructNewDefaultWithRtt,
|
||||
StructNew,
|
||||
StructNewDefault,
|
||||
StructGet,
|
||||
StructSet,
|
||||
ArrayNewWithRtt,
|
||||
ArrayNewDefaultWithRtt,
|
||||
ArrayNew,
|
||||
ArrayNewDefault,
|
||||
ArrayGet,
|
||||
ArraySet,
|
||||
ArrayLen,
|
||||
RttCanon,
|
||||
RttSub,
|
||||
RefTest,
|
||||
RefCast,
|
||||
BrOnCast,
|
||||
|
@ -368,10 +366,6 @@ class MOZ_STACK_CLASS OpIter : private Policy {
|
|||
[[nodiscard]] bool popWithTypes(ValTypeSpanT expected, ValueVector* values);
|
||||
[[nodiscard]] bool popWithRefType(Value* value, StackType* type);
|
||||
[[nodiscard]] bool popWithFuncType(Value* value, FuncType** funcType);
|
||||
[[nodiscard]] bool popWithRttType(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth);
|
||||
[[nodiscard]] bool popWithRttType(Value* rtt, uint32_t rttTypeIndex,
|
||||
uint32_t* rttDepth);
|
||||
[[nodiscard]] bool popThenPushType(ResultType expected, ValueVector* values);
|
||||
[[nodiscard]] bool topWithTypeAndPush(ResultType expected,
|
||||
ValueVector* values);
|
||||
|
@ -612,31 +606,23 @@ class MOZ_STACK_CLASS OpIter : private Policy {
|
|||
[[nodiscard]] bool readTableSize(uint32_t* tableIndex);
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
[[nodiscard]] bool readStructNewWithRtt(uint32_t* typeIndex, Value* rtt,
|
||||
ValueVector* argValues);
|
||||
[[nodiscard]] bool readStructNewDefaultWithRtt(uint32_t* typeIndex,
|
||||
Value* rtt);
|
||||
[[nodiscard]] bool readStructNew(uint32_t* typeIndex, ValueVector* argValues);
|
||||
[[nodiscard]] bool readStructNewDefault(uint32_t* typeIndex);
|
||||
[[nodiscard]] bool readStructGet(uint32_t* typeIndex, uint32_t* fieldIndex,
|
||||
FieldExtension extension, Value* ptr);
|
||||
[[nodiscard]] bool readStructSet(uint32_t* typeIndex, uint32_t* fieldIndex,
|
||||
Value* ptr, Value* val);
|
||||
[[nodiscard]] bool readArrayNewWithRtt(uint32_t* typeIndex, Value* rtt,
|
||||
Value* length, Value* argValue);
|
||||
[[nodiscard]] bool readArrayNewDefaultWithRtt(uint32_t* typeIndex, Value* rtt,
|
||||
Value* length);
|
||||
[[nodiscard]] bool readArrayNew(uint32_t* typeIndex, Value* length,
|
||||
Value* argValue);
|
||||
[[nodiscard]] bool readArrayNewDefault(uint32_t* typeIndex, Value* length);
|
||||
[[nodiscard]] bool readArrayGet(uint32_t* typeIndex, FieldExtension extension,
|
||||
Value* index, Value* ptr);
|
||||
[[nodiscard]] bool readArraySet(uint32_t* typeIndex, Value* val, Value* index,
|
||||
Value* ptr);
|
||||
[[nodiscard]] bool readArrayLen(uint32_t* typeIndex, Value* ptr);
|
||||
[[nodiscard]] bool readRttCanon(ValType* rttType);
|
||||
[[nodiscard]] bool readRttSub(Value* parentRtt, uint32_t* rttSubTypeIndex);
|
||||
[[nodiscard]] bool readRefTest(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth, Value* ref);
|
||||
[[nodiscard]] bool readRefCast(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth, Value* ref);
|
||||
[[nodiscard]] bool readBrOnCast(uint32_t* relativeDepth, Value* rtt,
|
||||
uint32_t* rttTypeIndex, uint32_t* rttDepth,
|
||||
[[nodiscard]] bool readRefTest(uint32_t* typeIndex, Value* ref);
|
||||
[[nodiscard]] bool readRefCast(uint32_t* typeIndex, Value* ref);
|
||||
[[nodiscard]] bool readBrOnCast(uint32_t* relativeDepth, uint32_t* typeIndex,
|
||||
ResultType* branchTargetType,
|
||||
ValueVector* values);
|
||||
#endif
|
||||
|
@ -942,41 +928,6 @@ inline bool OpIter<Policy>::popWithFuncType(Value* value, FuncType** funcType) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// This function pops exactly one value from the stack, checking that it is an
|
||||
// rtt type with any type index or depth value.
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::popWithRttType(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth) {
|
||||
StackType type;
|
||||
if (!popStackType(&type, rtt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type.isBottom()) {
|
||||
return fail("gc instruction temporarily not allowed in dead code");
|
||||
}
|
||||
|
||||
if (type.valType().isRtt()) {
|
||||
*rttTypeIndex = type.valType().typeIndex();
|
||||
*rttDepth = type.valType().rttDepth();
|
||||
return true;
|
||||
}
|
||||
|
||||
UniqueChars actualText = ToString(type.valType());
|
||||
if (!actualText) {
|
||||
return false;
|
||||
}
|
||||
|
||||
UniqueChars error(
|
||||
JS_smprintf("type mismatch: expression has type %s but expected (rtt _)",
|
||||
actualText.get()));
|
||||
if (!error) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return fail(error.get());
|
||||
}
|
||||
|
||||
// This function is an optimization of the sequence:
|
||||
// popWithType(ResultType, tmp)
|
||||
// push(ResultType, tmp)
|
||||
|
@ -2979,21 +2930,15 @@ inline bool OpIter<Policy>::readFieldIndex(uint32_t* fieldIndex,
|
|||
#ifdef ENABLE_WASM_GC
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readStructNewWithRtt(uint32_t* typeIndex,
|
||||
Value* rtt,
|
||||
ValueVector* argValues) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::StructNewWithRtt);
|
||||
inline bool OpIter<Policy>::readStructNew(uint32_t* typeIndex,
|
||||
ValueVector* argValues) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::StructNew);
|
||||
|
||||
if (!readStructTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const StructType& str = env_.types->structType(*typeIndex);
|
||||
const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
|
||||
|
||||
if (!popWithType(rttType, rtt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!argValues->resize(str.fields_.length())) {
|
||||
return false;
|
||||
|
@ -3011,20 +2956,14 @@ inline bool OpIter<Policy>::readStructNewWithRtt(uint32_t* typeIndex,
|
|||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readStructNewDefaultWithRtt(uint32_t* typeIndex,
|
||||
Value* rtt) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::StructNewDefaultWithRtt);
|
||||
inline bool OpIter<Policy>::readStructNewDefault(uint32_t* typeIndex) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::StructNewDefault);
|
||||
|
||||
if (!readStructTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const StructType& str = env_.types->structType(*typeIndex);
|
||||
const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
|
||||
|
||||
if (!popWithType(rttType, rtt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!str.isDefaultable()) {
|
||||
return fail("struct must be defaultable");
|
||||
|
@ -3102,21 +3041,15 @@ inline bool OpIter<Policy>::readStructSet(uint32_t* typeIndex,
|
|||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readArrayNewWithRtt(uint32_t* typeIndex, Value* rtt,
|
||||
Value* length,
|
||||
Value* argValue) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewWithRtt);
|
||||
inline bool OpIter<Policy>::readArrayNew(uint32_t* typeIndex, Value* length,
|
||||
Value* argValue) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ArrayNew);
|
||||
|
||||
if (!readArrayTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ArrayType& arr = env_.types->arrayType(*typeIndex);
|
||||
const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
|
||||
|
||||
if (!popWithType(rttType, rtt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!popWithType(ValType::I32, length)) {
|
||||
return false;
|
||||
|
@ -3130,21 +3063,15 @@ inline bool OpIter<Policy>::readArrayNewWithRtt(uint32_t* typeIndex, Value* rtt,
|
|||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readArrayNewDefaultWithRtt(uint32_t* typeIndex,
|
||||
Value* rtt,
|
||||
Value* length) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewDefaultWithRtt);
|
||||
inline bool OpIter<Policy>::readArrayNewDefault(uint32_t* typeIndex,
|
||||
Value* length) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::ArrayNewDefault);
|
||||
|
||||
if (!readArrayTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const ArrayType& arr = env_.types->arrayType(*typeIndex);
|
||||
const ValType rttType = ValType::fromRtt(*typeIndex, RttDepthNone);
|
||||
|
||||
if (!popWithType(rttType, rtt)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!popWithType(ValType::I32, length)) {
|
||||
return false;
|
||||
|
@ -3236,81 +3163,38 @@ inline bool OpIter<Policy>::readArrayLen(uint32_t* typeIndex, Value* ptr) {
|
|||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readRttCanon(ValType* rttType) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::RttCanon);
|
||||
|
||||
uint32_t typeIndex;
|
||||
if (!readGcTypeIndex(&typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*rttType = ValType::fromRtt(typeIndex, 0);
|
||||
return push(*rttType);
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readRttSub(Value* parentRtt,
|
||||
uint32_t* rttSubTypeIndex) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::RttSub);
|
||||
|
||||
if (!readGcTypeIndex(rttSubTypeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t rttParentTypeIndex;
|
||||
uint32_t rttParentDepth;
|
||||
if (!popWithRttType(parentRtt, &rttParentTypeIndex, &rttParentDepth)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!checkIsSubtypeOf(*rttSubTypeIndex, rttParentTypeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t subRttDepth;
|
||||
if (rttParentDepth == RttDepthNone) {
|
||||
subRttDepth = RttDepthNone;
|
||||
} else {
|
||||
if (rttParentDepth >= MaxRttDepth) {
|
||||
return fail("rtt depth is too deep");
|
||||
}
|
||||
subRttDepth = rttParentDepth + 1;
|
||||
}
|
||||
return push(ValType::fromRtt(*rttSubTypeIndex, subRttDepth));
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readRefTest(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth, Value* ref) {
|
||||
inline bool OpIter<Policy>::readRefTest(uint32_t* typeIndex, Value* ref) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::RefTest);
|
||||
|
||||
if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
|
||||
if (!readGcTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!popWithType(RefType::eq(), ref)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return push(ValType(ValType::I32));
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readRefCast(Value* rtt, uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth, Value* ref) {
|
||||
inline bool OpIter<Policy>::readRefCast(uint32_t* typeIndex, Value* ref) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::RefCast);
|
||||
|
||||
if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
|
||||
if (!readGcTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!popWithType(RefType::eq(), ref)) {
|
||||
return false;
|
||||
}
|
||||
return push(RefType::fromTypeIndex(*rttTypeIndex, false));
|
||||
|
||||
return push(RefType::fromTypeIndex(*typeIndex, false));
|
||||
}
|
||||
|
||||
template <typename Policy>
|
||||
inline bool OpIter<Policy>::readBrOnCast(uint32_t* relativeDepth, Value* rtt,
|
||||
uint32_t* rttTypeIndex,
|
||||
uint32_t* rttDepth,
|
||||
inline bool OpIter<Policy>::readBrOnCast(uint32_t* relativeDepth,
|
||||
uint32_t* typeIndex,
|
||||
ResultType* branchTargetType,
|
||||
ValueVector* values) {
|
||||
MOZ_ASSERT(Classify(op_) == OpKind::BrOnCast);
|
||||
|
@ -3319,16 +3203,16 @@ inline bool OpIter<Policy>::readBrOnCast(uint32_t* relativeDepth, Value* rtt,
|
|||
return fail("unable to read br_on_cast depth");
|
||||
}
|
||||
|
||||
if (!popWithRttType(rtt, rttTypeIndex, rttDepth)) {
|
||||
if (!readGcTypeIndex(typeIndex)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The casted from type is any subtype of eqref
|
||||
// The casted from type is any subtype of eqref.
|
||||
ValType castedFromType(RefType::eq());
|
||||
|
||||
// The casted to type is a non-nullable reference to the type index specified
|
||||
// by the input rtt on the stack
|
||||
ValType castedToType(RefType::fromTypeIndex(*rttTypeIndex, false));
|
||||
// The casted to type is a non-nullable reference to the type index
|
||||
// specified as an immediate.
|
||||
ValType castedToType(RefType::fromTypeIndex(*typeIndex, false));
|
||||
|
||||
return checkCastedBranchValueAndPush(*relativeDepth, castedFromType,
|
||||
castedToType, branchTargetType, values);
|
||||
|
|
|
@ -718,7 +718,7 @@ template <CoderMode mode>
|
|||
CoderResult CodeSymbolicLinkArray(
|
||||
Coder<mode>& coder,
|
||||
CoderArg<mode, wasm::LinkData::SymbolicLinkArray> item) {
|
||||
WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::LinkData::SymbolicLinkArray, 6984);
|
||||
WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::LinkData::SymbolicLinkArray, 6912);
|
||||
for (SymbolicAddress address :
|
||||
mozilla::MakeEnumeratedRange(SymbolicAddress::Limit)) {
|
||||
MOZ_TRY(CodePodVector(coder, &(*item)[address]));
|
||||
|
@ -729,7 +729,7 @@ CoderResult CodeSymbolicLinkArray(
|
|||
template <CoderMode mode>
|
||||
CoderResult CodeLinkData(Coder<mode>& coder,
|
||||
CoderArg<mode, wasm::LinkData> item) {
|
||||
WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::LinkData, 7032);
|
||||
WASM_VERIFY_SERIALIZATION_FOR_SIZE(wasm::LinkData, 6960);
|
||||
if constexpr (mode == MODE_ENCODE) {
|
||||
MOZ_ASSERT(item->tier == Tier::Serialized);
|
||||
}
|
||||
|
|
|
@ -112,7 +112,6 @@ void ABIResultIter::settleRegister(ValType type) {
|
|||
case ValType::F64:
|
||||
cur_ = ABIResult(type, ReturnDoubleReg);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
cur_ = ABIResult(type, ReturnReg);
|
||||
break;
|
||||
|
@ -519,7 +518,6 @@ static void StoreRegisterResult(MacroAssembler& masm, const FuncExport& fe,
|
|||
masm.canonicalizeDouble(result.fpr());
|
||||
masm.storeDouble(result.fpr(), Address(loc, 0));
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
masm.storePtr(result.gpr(), Address(loc, 0));
|
||||
break;
|
||||
|
@ -1344,7 +1342,6 @@ static bool GenerateJitEntry(MacroAssembler& masm, size_t funcExportIndex,
|
|||
masm.setFramePushed(0);
|
||||
break;
|
||||
}
|
||||
case ValType::Rtt:
|
||||
case ValType::V128: {
|
||||
MOZ_CRASH("unexpected return type when calling from ion to wasm");
|
||||
}
|
||||
|
@ -1647,7 +1644,6 @@ void wasm::GenerateDirectCallFromJit(MacroAssembler& masm, const FuncExport& fe,
|
|||
MOZ_CRASH("unexpected return type when calling from ion to wasm");
|
||||
}
|
||||
break;
|
||||
case wasm::ValType::Rtt:
|
||||
case wasm::ValType::V128:
|
||||
MOZ_CRASH("unexpected return type when calling from ion to wasm");
|
||||
}
|
||||
|
@ -2173,7 +2169,6 @@ static bool GenerateImportInterpExit(MacroAssembler& masm, const FuncImport& fi,
|
|||
funcImportIndex);
|
||||
GenPrintI64(DebugChannel::Import, masm, ReturnReg64);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::V128:
|
||||
// Note, CallImport_Rtt/V128 currently always throws, so we should never
|
||||
// reach this point.
|
||||
|
@ -2383,7 +2378,6 @@ static bool GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi,
|
|||
// No fastpath for now, go immediately to ool case
|
||||
masm.jump(&oolConvert);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::V128:
|
||||
// Unreachable as callImport should not call the stub.
|
||||
masm.breakpoint();
|
||||
|
|
|
@ -60,7 +60,6 @@ class ABIResult {
|
|||
case ValType::F64:
|
||||
MOZ_ASSERT(loc_ == Location::Fpr);
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
MOZ_ASSERT(loc_ == Location::Gpr);
|
||||
break;
|
||||
|
|
|
@ -465,8 +465,6 @@ static bool IsImmediateType(ValType vt) {
|
|||
return false;
|
||||
}
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
return false;
|
||||
}
|
||||
MOZ_CRASH("bad ValType");
|
||||
}
|
||||
|
@ -496,8 +494,6 @@ static unsigned EncodeImmediateType(ValType vt) {
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case ValType::Rtt:
|
||||
break;
|
||||
}
|
||||
MOZ_CRASH("bad ValType");
|
||||
}
|
||||
|
|
|
@ -653,22 +653,6 @@ class TypeContext : public AtomicRefCounted<TypeContext> {
|
|||
return isRefEquivalent(first.refType(), second.refType(), cache);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_WASM_GC
|
||||
// An rtt may be a equal to another rtt
|
||||
if (first.isRtt() && second.isRtt()) {
|
||||
// Equivalent rtts must both have depths or not have depths
|
||||
if (first.hasRttDepth() != second.hasRttDepth()) {
|
||||
return TypeResult::False;
|
||||
}
|
||||
// Equivalent rtts must have the same depth, if any
|
||||
if (second.hasRttDepth() && first.rttDepth() != second.rttDepth()) {
|
||||
return TypeResult::False;
|
||||
}
|
||||
return isTypeIndexEquivalent(first.typeIndex(), second.typeIndex(),
|
||||
cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
return TypeResult::False;
|
||||
}
|
||||
|
||||
|
@ -705,23 +689,6 @@ class TypeContext : public AtomicRefCounted<TypeContext> {
|
|||
return isRefSubtypeOf(subType.refType(), superType.refType(), cache);
|
||||
}
|
||||
|
||||
// An rtt may be a subtype of another rtt
|
||||
#ifdef ENABLE_WASM_GC
|
||||
if (subType.isRtt() && superType.isRtt()) {
|
||||
// A subtype must have a depth if the supertype has depth
|
||||
if (!subType.hasRttDepth() && superType.hasRttDepth()) {
|
||||
return TypeResult::False;
|
||||
}
|
||||
// A subtype must have the same depth as the supertype, if it has any
|
||||
if (superType.hasRttDepth() &&
|
||||
subType.rttDepth() != superType.rttDepth()) {
|
||||
return TypeResult::False;
|
||||
}
|
||||
return isTypeIndexEquivalent(subType.typeIndex(), superType.typeIndex(),
|
||||
cache);
|
||||
}
|
||||
#endif
|
||||
|
||||
return TypeResult::False;
|
||||
}
|
||||
|
||||
|
|
|
@ -145,11 +145,6 @@ UniqueChars wasm::ToString(ValType type) {
|
|||
break;
|
||||
case ValType::Ref:
|
||||
return ToString(type.refType());
|
||||
case ValType::Rtt:
|
||||
if (!type.hasRttDepth()) {
|
||||
return JS_smprintf("(rtt %d)", type.typeIndex());
|
||||
}
|
||||
return JS_smprintf("(rtt %d %d)", type.rttDepth(), type.typeIndex());
|
||||
}
|
||||
return DuplicateString(literal);
|
||||
}
|
||||
|
|
|
@ -43,30 +43,24 @@ union PackedTypeCode {
|
|||
static constexpr size_t TypeCodeBits = 8;
|
||||
static constexpr size_t TypeIndexBits = 21;
|
||||
static constexpr size_t NullableBits = 1;
|
||||
static constexpr size_t RttDepthBits = 10;
|
||||
static constexpr size_t PointerTagBits = 2;
|
||||
#else
|
||||
static constexpr size_t TypeCodeBits = 8;
|
||||
static constexpr size_t TypeIndexBits = 14;
|
||||
static constexpr size_t NullableBits = 1;
|
||||
static constexpr size_t RttDepthBits = 7;
|
||||
static constexpr size_t PointerTagBits = 2;
|
||||
#endif
|
||||
|
||||
static_assert(TypeCodeBits + TypeIndexBits + NullableBits + RttDepthBits +
|
||||
PointerTagBits <=
|
||||
static_assert(TypeCodeBits + TypeIndexBits + NullableBits + PointerTagBits <=
|
||||
(sizeof(PackedRepr) * 8),
|
||||
"enough bits");
|
||||
static_assert(MaxTypeIndex < (1 << TypeIndexBits), "enough bits");
|
||||
static_assert(MaxRttDepth < (1 << RttDepthBits), "enough bits");
|
||||
static_assert(RttDepthNone < (1 << RttDepthBits), "enough bits");
|
||||
|
||||
PackedRepr bits_;
|
||||
struct {
|
||||
PackedRepr typeCode_ : TypeCodeBits;
|
||||
PackedRepr typeIndex_ : TypeIndexBits;
|
||||
PackedRepr nullable_ : NullableBits;
|
||||
PackedRepr rttDepth_ : RttDepthBits;
|
||||
PackedRepr pointerTag_ : PointerTagBits;
|
||||
};
|
||||
|
||||
|
@ -89,29 +83,25 @@ union PackedTypeCode {
|
|||
}
|
||||
|
||||
static constexpr PackedTypeCode pack(TypeCode tc, uint32_t refTypeIndex,
|
||||
bool isNullable, uint32_t rttDepth) {
|
||||
bool isNullable) {
|
||||
MOZ_ASSERT(uint32_t(tc) <= ((1 << TypeCodeBits) - 1));
|
||||
MOZ_ASSERT_IF(tc != AbstractReferenceTypeIndexCode && tc != AbstractRttCode,
|
||||
MOZ_ASSERT_IF(tc != AbstractReferenceTypeIndexCode,
|
||||
refTypeIndex == NoTypeIndex);
|
||||
MOZ_ASSERT_IF(tc == AbstractReferenceTypeIndexCode || tc == AbstractRttCode,
|
||||
MOZ_ASSERT_IF(tc == AbstractReferenceTypeIndexCode,
|
||||
refTypeIndex <= MaxTypeIndex);
|
||||
MOZ_ASSERT_IF(tc != AbstractRttCode, rttDepth == 0);
|
||||
MOZ_ASSERT_IF(tc == AbstractRttCode,
|
||||
rttDepth <= MaxRttDepth || rttDepth == RttDepthNone);
|
||||
PackedTypeCode ptc = {};
|
||||
ptc.typeCode_ = PackedRepr(tc);
|
||||
ptc.typeIndex_ = refTypeIndex;
|
||||
ptc.nullable_ = isNullable;
|
||||
ptc.rttDepth_ = rttDepth;
|
||||
return ptc;
|
||||
}
|
||||
|
||||
static constexpr PackedTypeCode pack(TypeCode tc, bool nullable) {
|
||||
return pack(tc, PackedTypeCode::NoTypeIndex, nullable, 0);
|
||||
return pack(tc, PackedTypeCode::NoTypeIndex, nullable);
|
||||
}
|
||||
|
||||
static constexpr PackedTypeCode pack(TypeCode tc) {
|
||||
return pack(tc, PackedTypeCode::NoTypeIndex, false, 0);
|
||||
return pack(tc, PackedTypeCode::NoTypeIndex, false);
|
||||
}
|
||||
|
||||
bool isValid() const { return typeCode_ != NoTypeCode; }
|
||||
|
@ -136,14 +126,9 @@ union PackedTypeCode {
|
|||
// what ValType needs, so that this decoding step is not necessary, but that
|
||||
// moves complexity elsewhere, and the perf gain here would be only about 1%
|
||||
// for baseline compilation throughput.
|
||||
//
|
||||
// TODO: with rtt types this is no longer a simple comparison, we should
|
||||
// re-evaluate the performance of this function.
|
||||
TypeCode typeCodeAbstracted() const {
|
||||
TypeCode tc = typeCode();
|
||||
return (tc < LowestPrimitiveTypeCode && tc != AbstractRttCode)
|
||||
? AbstractReferenceTypeCode
|
||||
: tc;
|
||||
return tc < LowestPrimitiveTypeCode ? AbstractReferenceTypeCode : tc;
|
||||
}
|
||||
|
||||
// Return whether this type is a reference type.
|
||||
|
@ -151,8 +136,7 @@ union PackedTypeCode {
|
|||
return typeCodeAbstracted() == AbstractReferenceTypeCode;
|
||||
}
|
||||
|
||||
// Return whether this type is represented by a reference at runtime. This is
|
||||
// any reference type along with rtts.
|
||||
// Return whether this type is represented by a reference at runtime.
|
||||
bool isRefRepr() const { return typeCode() < LowestPrimitiveTypeCode; }
|
||||
|
||||
uint32_t typeIndex() const {
|
||||
|
@ -170,16 +154,6 @@ union PackedTypeCode {
|
|||
return bool(nullable_);
|
||||
}
|
||||
|
||||
bool hasRttDepth() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return uint32_t(rttDepth_) != RttDepthNone;
|
||||
}
|
||||
|
||||
uint32_t rttDepth() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return uint32_t(rttDepth_);
|
||||
}
|
||||
|
||||
PackedTypeCode asNonNullable() const {
|
||||
MOZ_ASSERT(isRefType());
|
||||
PackedTypeCode mutated = *this;
|
||||
|
@ -246,7 +220,7 @@ class RefType {
|
|||
|
||||
RefType(uint32_t refTypeIndex, bool nullable)
|
||||
: ptc_(PackedTypeCode::pack(AbstractReferenceTypeIndexCode, refTypeIndex,
|
||||
nullable, 0)) {
|
||||
nullable)) {
|
||||
MOZ_ASSERT(isValid());
|
||||
}
|
||||
|
||||
|
@ -310,7 +284,6 @@ class FieldTypeTraits {
|
|||
F32 = uint8_t(TypeCode::F32),
|
||||
F64 = uint8_t(TypeCode::F64),
|
||||
V128 = uint8_t(TypeCode::V128),
|
||||
Rtt = uint8_t(AbstractRttCode),
|
||||
Ref = uint8_t(AbstractReferenceTypeCode),
|
||||
};
|
||||
|
||||
|
@ -331,7 +304,6 @@ class FieldTypeTraits {
|
|||
case TypeCode::ExternRef:
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case TypeCode::EqRef:
|
||||
case AbstractRttCode:
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
case AbstractReferenceTypeIndexCode:
|
||||
|
@ -351,7 +323,6 @@ class ValTypeTraits {
|
|||
F32 = uint8_t(TypeCode::F32),
|
||||
F64 = uint8_t(TypeCode::F64),
|
||||
V128 = uint8_t(TypeCode::V128),
|
||||
Rtt = uint8_t(AbstractRttCode),
|
||||
Ref = uint8_t(AbstractReferenceTypeCode),
|
||||
};
|
||||
|
||||
|
@ -368,7 +339,6 @@ class ValTypeTraits {
|
|||
case TypeCode::ExternRef:
|
||||
#ifdef ENABLE_WASM_GC
|
||||
case TypeCode::EqRef:
|
||||
case AbstractRttCode:
|
||||
#endif
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
case AbstractReferenceTypeIndexCode:
|
||||
|
@ -458,11 +428,6 @@ class PackedType : public T {
|
|||
return PackedType(tc);
|
||||
}
|
||||
|
||||
static PackedType fromRtt(uint32_t typeIndex, uint32_t rttDepth) {
|
||||
return PackedType(
|
||||
PackedTypeCode::pack(AbstractRttCode, typeIndex, false, rttDepth));
|
||||
}
|
||||
|
||||
static PackedType fromBitsUnsafe(uint64_t bits) {
|
||||
return PackedType(PackedTypeCode::fromBits(bits));
|
||||
}
|
||||
|
@ -492,8 +457,6 @@ class PackedType : public T {
|
|||
return tc_.bits();
|
||||
}
|
||||
|
||||
bool isRtt() const { return tc_.typeCode() == AbstractRttCode; }
|
||||
|
||||
bool isRefType() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return tc_.isRefType();
|
||||
|
@ -518,14 +481,14 @@ class PackedType : public T {
|
|||
// Returns whether the type has a default value.
|
||||
bool isDefaultable() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return !(isRtt() || (isRefType() && !isNullable()));
|
||||
return !(isRefType() && !isNullable());
|
||||
}
|
||||
|
||||
// Returns whether the type has a representation in JS.
|
||||
bool isExposable() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
#if defined(ENABLE_WASM_SIMD) || defined(ENABLE_WASM_GC)
|
||||
return !(kind() == Kind::V128 || isRtt() || isTypeIndex());
|
||||
return !(kind() == Kind::V128 || isTypeIndex());
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
|
@ -541,16 +504,6 @@ class PackedType : public T {
|
|||
return tc_.typeIndex();
|
||||
}
|
||||
|
||||
bool hasRttDepth() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return tc_.hasRttDepth();
|
||||
}
|
||||
|
||||
uint32_t rttDepth() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return tc_.rttDepth();
|
||||
}
|
||||
|
||||
Kind kind() const {
|
||||
MOZ_ASSERT(isValid());
|
||||
return Kind(tc_.typeCodeAbstracted());
|
||||
|
@ -607,7 +560,6 @@ class PackedType : public T {
|
|||
return 8;
|
||||
case TypeCode::V128:
|
||||
return 16;
|
||||
case AbstractRttCode:
|
||||
case AbstractReferenceTypeCode:
|
||||
return sizeof(void*);
|
||||
default:
|
||||
|
@ -701,7 +653,6 @@ static inline unsigned SizeOf(ValType vt) {
|
|||
return 8;
|
||||
case ValType::V128:
|
||||
return 16;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
return sizeof(intptr_t);
|
||||
}
|
||||
|
@ -725,7 +676,6 @@ static inline jit::MIRType ToMIRType(ValType vt) {
|
|||
return jit::MIRType::Double;
|
||||
case ValType::V128:
|
||||
return jit::MIRType::Simd128;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
return jit::MIRType::RefOrNull;
|
||||
}
|
||||
|
|
|
@ -555,15 +555,14 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
return iter.unrecognizedOpcode(&op);
|
||||
}
|
||||
switch (op.b1) {
|
||||
case uint32_t(GcOp::StructNewWithRtt): {
|
||||
case uint32_t(GcOp::StructNew): {
|
||||
uint32_t unusedUint;
|
||||
NothingVector unusedArgs{};
|
||||
CHECK(
|
||||
iter.readStructNewWithRtt(&unusedUint, ¬hing, &unusedArgs));
|
||||
CHECK(iter.readStructNew(&unusedUint, &unusedArgs));
|
||||
}
|
||||
case uint32_t(GcOp::StructNewDefaultWithRtt): {
|
||||
case uint32_t(GcOp::StructNewDefault): {
|
||||
uint32_t unusedUint;
|
||||
CHECK(iter.readStructNewDefaultWithRtt(&unusedUint, ¬hing));
|
||||
CHECK(iter.readStructNewDefault(&unusedUint));
|
||||
}
|
||||
case uint32_t(GcOp::StructGet): {
|
||||
uint32_t unusedUint1, unusedUint2;
|
||||
|
@ -585,15 +584,13 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
CHECK(iter.readStructSet(&unusedUint1, &unusedUint2, ¬hing,
|
||||
¬hing));
|
||||
}
|
||||
case uint32_t(GcOp::ArrayNewWithRtt): {
|
||||
case uint32_t(GcOp::ArrayNew): {
|
||||
uint32_t unusedUint;
|
||||
CHECK(iter.readArrayNewWithRtt(&unusedUint, ¬hing, ¬hing,
|
||||
¬hing));
|
||||
CHECK(iter.readArrayNew(&unusedUint, ¬hing, ¬hing));
|
||||
}
|
||||
case uint32_t(GcOp::ArrayNewDefaultWithRtt): {
|
||||
case uint32_t(GcOp::ArrayNewDefault): {
|
||||
uint32_t unusedUint;
|
||||
CHECK(iter.readArrayNewDefaultWithRtt(&unusedUint, ¬hing,
|
||||
¬hing));
|
||||
CHECK(iter.readArrayNewDefault(&unusedUint, ¬hing));
|
||||
}
|
||||
case uint32_t(GcOp::ArrayGet): {
|
||||
uint32_t unusedUint1;
|
||||
|
@ -619,32 +616,18 @@ static bool DecodeFunctionBodyExprs(const ModuleEnvironment& env,
|
|||
uint32_t unusedUint1;
|
||||
CHECK(iter.readArrayLen(&unusedUint1, ¬hing));
|
||||
}
|
||||
case uint16_t(GcOp::RttCanon): {
|
||||
ValType unusedTy;
|
||||
CHECK(iter.readRttCanon(&unusedTy));
|
||||
}
|
||||
case uint16_t(GcOp::RttSub): {
|
||||
uint32_t unusedRttTypeIndex;
|
||||
CHECK(iter.readRttSub(¬hing, &unusedRttTypeIndex));
|
||||
}
|
||||
case uint16_t(GcOp::RefTest): {
|
||||
uint32_t unusedRttTypeIndex;
|
||||
uint32_t unusedRttDepth;
|
||||
CHECK(iter.readRefTest(¬hing, &unusedRttTypeIndex,
|
||||
&unusedRttDepth, ¬hing));
|
||||
uint32_t typeIndex;
|
||||
CHECK(iter.readRefTest(&typeIndex, ¬hing));
|
||||
}
|
||||
case uint16_t(GcOp::RefCast): {
|
||||
uint32_t unusedRttTypeIndex;
|
||||
uint32_t unusedRttDepth;
|
||||
CHECK(iter.readRefCast(¬hing, &unusedRttTypeIndex,
|
||||
&unusedRttDepth, ¬hing));
|
||||
uint32_t typeIndex;
|
||||
CHECK(iter.readRefCast(&typeIndex, ¬hing));
|
||||
}
|
||||
case uint16_t(GcOp::BrOnCast): {
|
||||
uint32_t unusedRelativeDepth;
|
||||
uint32_t unusedRttTypeIndex;
|
||||
uint32_t unusedRttDepth;
|
||||
CHECK(iter.readBrOnCast(&unusedRelativeDepth, ¬hing,
|
||||
&unusedRttTypeIndex, &unusedRttDepth,
|
||||
uint32_t typeIndex;
|
||||
CHECK(iter.readBrOnCast(&unusedRelativeDepth, &typeIndex,
|
||||
&unusedType, ¬hings));
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -53,7 +53,6 @@ Val::Val(const LitVal& val) {
|
|||
case ValType::V128:
|
||||
cell_.v128_ = val.v128();
|
||||
return;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
cell_.ref_ = val.ref();
|
||||
return;
|
||||
|
@ -370,8 +369,6 @@ bool wasm::ToWebAssemblyValue(JSContext* cx, HandleValue val, FieldType type,
|
|||
return ToWebAssemblyValue_f64<Debug>(cx, val, (double*)loc, mustWrite64);
|
||||
case FieldType::V128:
|
||||
break;
|
||||
case FieldType::Rtt:
|
||||
break;
|
||||
case FieldType::Ref:
|
||||
#ifdef ENABLE_WASM_FUNCTION_REFERENCES
|
||||
if (!type.isNullable() && val.isNull()) {
|
||||
|
@ -507,8 +504,6 @@ bool wasm::ToJSValue(JSContext* cx, const void* src, FieldType type,
|
|||
dst);
|
||||
case FieldType::V128:
|
||||
break;
|
||||
case FieldType::Rtt:
|
||||
break;
|
||||
case FieldType::Ref:
|
||||
switch (type.refTypeKind()) {
|
||||
case RefType::Func:
|
||||
|
|
|
@ -321,9 +321,6 @@ class LitVal {
|
|||
cell_.ref_ = AnyRef::null();
|
||||
break;
|
||||
}
|
||||
case ValType::Kind::Rtt: {
|
||||
MOZ_CRASH("not defaultable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -416,7 +413,6 @@ class MOZ_NON_PARAM Val : public LitVal {
|
|||
return cell_.f64_ == rhs.cell_.f64_;
|
||||
case ValType::V128:
|
||||
return cell_.v128_ == rhs.cell_.v128_;
|
||||
case ValType::Rtt:
|
||||
case ValType::Ref:
|
||||
return cell_.ref_ == rhs.cell_.ref_;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "Http2Push.h"
|
||||
#include "nsHttp.h"
|
||||
#include "nsHttpHandler.h"
|
||||
#include "nsHttpTransaction.h"
|
||||
#include "nsIHttpPushListener.h"
|
||||
|
@ -83,7 +84,7 @@ Http2PushedStreamWrapper::~Http2PushedStreamWrapper() {
|
|||
Http2PushedStream* Http2PushedStreamWrapper::GetStream() {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
if (mStream) {
|
||||
Http2Stream* stream = mStream;
|
||||
Http2StreamBase* stream = mStream;
|
||||
return static_cast<Http2PushedStream*>(stream);
|
||||
}
|
||||
return nullptr;
|
||||
|
@ -92,7 +93,7 @@ Http2PushedStream* Http2PushedStreamWrapper::GetStream() {
|
|||
void Http2PushedStreamWrapper::OnPushFailed() {
|
||||
if (OnSocketThread()) {
|
||||
if (mStream) {
|
||||
Http2Stream* stream = mStream;
|
||||
Http2StreamBase* stream = mStream;
|
||||
static_cast<Http2PushedStream*>(stream)->OnPushFailed();
|
||||
}
|
||||
} else {
|
||||
|
@ -109,10 +110,10 @@ void Http2PushedStreamWrapper::OnPushFailed() {
|
|||
|
||||
Http2PushedStream::Http2PushedStream(
|
||||
Http2PushTransactionBuffer* aTransaction, Http2Session* aSession,
|
||||
Http2Stream* aAssociatedStream, uint32_t aID,
|
||||
Http2StreamBase* aAssociatedStream, uint32_t aID,
|
||||
uint64_t aCurrentForegroundTabOuterContentWindowId)
|
||||
: Http2Stream(aTransaction, aSession, 0,
|
||||
aCurrentForegroundTabOuterContentWindowId),
|
||||
: Http2StreamBase(aTransaction, aSession, 0,
|
||||
aCurrentForegroundTabOuterContentWindowId),
|
||||
mAssociatedTransaction(aAssociatedStream->Transaction()),
|
||||
mBufferedPush(aTransaction) {
|
||||
LOG3(("Http2PushedStream ctor this=%p 0x%X\n", this, aID));
|
||||
|
@ -140,7 +141,7 @@ bool Http2PushedStream::GetPushComplete() { return mPushCompleted; }
|
|||
nsresult Http2PushedStream::WriteSegments(nsAHttpSegmentWriter* writer,
|
||||
uint32_t count,
|
||||
uint32_t* countWritten) {
|
||||
nsresult rv = Http2Stream::WriteSegments(writer, count, countWritten);
|
||||
nsresult rv = Http2StreamBase::WriteSegments(writer, count, countWritten);
|
||||
if (NS_SUCCEEDED(rv) && *countWritten) {
|
||||
mLastRead = TimeStamp::Now();
|
||||
}
|
||||
|
@ -196,9 +197,9 @@ bool Http2PushedStream::TryOnPush() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// side effect free static method to determine if Http2Stream implements
|
||||
// side effect free static method to determine if Http2StreamBase implements
|
||||
// nsIHttpPushListener
|
||||
bool Http2PushedStream::TestOnPush(Http2Stream* stream) {
|
||||
bool Http2PushedStream::TestOnPush(Http2StreamBase* stream) {
|
||||
if (!stream) {
|
||||
return false;
|
||||
}
|
||||
|
@ -234,9 +235,9 @@ nsresult Http2PushedStream::ReadSegments(nsAHttpSegmentReader* reader, uint32_t,
|
|||
// the write side of a pushed transaction just involves manipulating a
|
||||
// little state
|
||||
SetSentFin(true);
|
||||
Http2Stream::mRequestHeadersDone = 1;
|
||||
Http2Stream::mOpenGenerated = 1;
|
||||
Http2Stream::ChangeState(UPSTREAM_COMPLETE);
|
||||
Http2StreamBase::mRequestHeadersDone = 1;
|
||||
Http2StreamBase::mOpenGenerated = 1;
|
||||
Http2StreamBase::ChangeState(UPSTREAM_COMPLETE);
|
||||
} break;
|
||||
|
||||
case UPSTREAM_COMPLETE:
|
||||
|
@ -265,7 +266,7 @@ void Http2PushedStream::AdjustInitialWindow() {
|
|||
("Http2PushStream::AdjustInitialWindow %p 0x%X "
|
||||
"calling super consumer %p 0x%X\n",
|
||||
this, mStreamID, mConsumerStream, mConsumerStream->StreamID()));
|
||||
Http2Stream::AdjustInitialWindow();
|
||||
Http2StreamBase::AdjustInitialWindow();
|
||||
// Http2PushedStream::ReadSegments is needed to call TransmitFrame()
|
||||
// and actually get this information into the session bytestream
|
||||
RefPtr<Http2Session> session = Session();
|
||||
|
@ -275,7 +276,7 @@ void Http2PushedStream::AdjustInitialWindow() {
|
|||
// anyway, so we're good to go.
|
||||
}
|
||||
|
||||
void Http2PushedStream::SetConsumerStream(Http2Stream* consumer) {
|
||||
void Http2PushedStream::SetConsumerStream(Http2StreamBase* consumer) {
|
||||
LOG3(("Http2PushedStream::SetConsumerStream this=%p consumer=%p", this,
|
||||
consumer));
|
||||
|
||||
|
@ -290,7 +291,7 @@ bool Http2PushedStream::GetHashKey(nsCString& key) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Http2PushedStream::ConnectPushedStream(Http2Stream* stream) {
|
||||
void Http2PushedStream::ConnectPushedStream(Http2StreamBase* stream) {
|
||||
RefPtr<Http2Session> session = Session();
|
||||
session->ConnectPushedStream(stream);
|
||||
}
|
||||
|
@ -359,6 +360,50 @@ void Http2PushedStream::TopBrowsingContextIdChanged(uint64_t id) {
|
|||
}
|
||||
}
|
||||
|
||||
// ConvertPushHeaders is used to convert the pushed request headers
|
||||
// into HTTP/1 format and report some telemetry
|
||||
nsresult Http2PushedStream::ConvertPushHeaders(Http2Decompressor* decompressor,
|
||||
nsACString& aHeadersIn,
|
||||
nsACString& aHeadersOut) {
|
||||
nsresult rv = decompressor->DecodeHeaderBlock(
|
||||
reinterpret_cast<const uint8_t*>(aHeadersIn.BeginReading()),
|
||||
aHeadersIn.Length(), aHeadersOut, true);
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG3(("Http2PushedStream::ConvertPushHeaders %p Error\n", this));
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCString method;
|
||||
decompressor->GetHost(mHeaderHost);
|
||||
decompressor->GetScheme(mHeaderScheme);
|
||||
decompressor->GetPath(mHeaderPath);
|
||||
|
||||
if (mHeaderHost.IsEmpty() || mHeaderScheme.IsEmpty() ||
|
||||
mHeaderPath.IsEmpty()) {
|
||||
LOG3(
|
||||
("Http2PushedStream::ConvertPushHeaders %p Error - missing required "
|
||||
"host=%s scheme=%s path=%s\n",
|
||||
this, mHeaderHost.get(), mHeaderScheme.get(), mHeaderPath.get()));
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
decompressor->GetMethod(method);
|
||||
if (!method.EqualsLiteral("GET")) {
|
||||
LOG3(
|
||||
("Http2PushedStream::ConvertPushHeaders %p Error - method not "
|
||||
"supported: "
|
||||
"%s\n",
|
||||
this, method.get()));
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
aHeadersIn.Truncate();
|
||||
LOG(("id 0x%X decoded push headers %s %s %s are:\n%s", mStreamID,
|
||||
mHeaderScheme.get(), mHeaderHost.get(), mHeaderPath.get(),
|
||||
aHeadersOut.BeginReading()));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
// Http2PushTransactionBuffer
|
||||
// This is the nsAHttpTransction owned by the stream when the pushed
|
||||
|
@ -434,7 +479,7 @@ nsresult Http2PushTransactionBuffer::WriteSegments(nsAHttpSegmentWriter* writer,
|
|||
}
|
||||
|
||||
if (Available() || mIsDone) {
|
||||
Http2Stream* consumer = mPushStream->GetConsumerStream();
|
||||
Http2StreamBase* consumer = mPushStream->GetConsumerStream();
|
||||
|
||||
if (consumer) {
|
||||
LOG3(
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
// https://www.rfc-editor.org/rfc/rfc7540.txt
|
||||
|
||||
#include "Http2Session.h"
|
||||
#include "Http2Stream.h"
|
||||
#include "Http2StreamBase.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
@ -25,22 +25,23 @@ namespace net {
|
|||
|
||||
class Http2PushTransactionBuffer;
|
||||
|
||||
class Http2PushedStream final : public Http2Stream {
|
||||
class Http2PushedStream final : public Http2StreamBase {
|
||||
public:
|
||||
Http2PushedStream(Http2PushTransactionBuffer* aTransaction,
|
||||
Http2Session* aSession, Http2Stream* aAssociatedStream,
|
||||
Http2Session* aSession, Http2StreamBase* aAssociatedStream,
|
||||
uint32_t aID,
|
||||
uint64_t aCurrentForegroundTabOuterContentWindowId);
|
||||
|
||||
Http2PushedStream* GetHttp2PushedStream() override { return this; }
|
||||
bool GetPushComplete();
|
||||
|
||||
// The consumer stream is the synthetic pull stream hooked up to this push
|
||||
virtual Http2Stream* GetConsumerStream() override { return mConsumerStream; };
|
||||
Http2StreamBase* GetConsumerStream() { return mConsumerStream; };
|
||||
|
||||
void SetConsumerStream(Http2Stream* consumer);
|
||||
void SetConsumerStream(Http2StreamBase* consumer);
|
||||
[[nodiscard]] bool GetHashKey(nsCString& key);
|
||||
|
||||
// override of Http2Stream
|
||||
// override of Http2StreamBase
|
||||
[[nodiscard]] nsresult ReadSegments(nsAHttpSegmentReader*, uint32_t,
|
||||
uint32_t*) override;
|
||||
[[nodiscard]] nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
|
||||
|
@ -48,10 +49,10 @@ class Http2PushedStream final : public Http2Stream {
|
|||
void AdjustInitialWindow() override;
|
||||
|
||||
nsIRequestContext* RequestContext() override { return mRequestContext; };
|
||||
void ConnectPushedStream(Http2Stream* stream);
|
||||
void ConnectPushedStream(Http2StreamBase* stream);
|
||||
|
||||
[[nodiscard]] bool TryOnPush();
|
||||
[[nodiscard]] static bool TestOnPush(Http2Stream* stream);
|
||||
[[nodiscard]] static bool TestOnPush(Http2StreamBase* stream);
|
||||
|
||||
virtual bool DeferCleanup(nsresult status) override;
|
||||
void SetDeferCleanupOnSuccess(bool val) { mDeferCleanupOnSuccess = val; }
|
||||
|
@ -65,19 +66,22 @@ class Http2PushedStream final : public Http2Stream {
|
|||
[[nodiscard]] nsresult GetBufferedData(char* buf, uint32_t count,
|
||||
uint32_t* countWritten);
|
||||
|
||||
// overload of Http2Stream
|
||||
// overload of Http2StreamBase
|
||||
virtual bool HasSink() override { return !!mConsumerStream; }
|
||||
virtual void SetPushComplete() override { mPushCompleted = true; }
|
||||
void SetPushComplete() { mPushCompleted = true; }
|
||||
virtual void TopBrowsingContextIdChanged(uint64_t) override;
|
||||
|
||||
nsCString& GetRequestString() { return mRequestString; }
|
||||
nsCString& GetResourceUrl() { return mResourceUrl; }
|
||||
|
||||
nsresult ConvertPushHeaders(Http2Decompressor* decompressor,
|
||||
nsACString& aHeadersIn, nsACString& aHeadersOut);
|
||||
|
||||
private:
|
||||
virtual ~Http2PushedStream() = default;
|
||||
// paired request stream that consumes from real http/2 one.. null until a
|
||||
// match is made.
|
||||
Http2Stream* mConsumerStream{nullptr};
|
||||
Http2StreamBase* mConsumerStream{nullptr};
|
||||
|
||||
nsCOMPtr<nsIRequestContext> mRequestContext;
|
||||
|
||||
|
@ -152,7 +156,7 @@ class Http2PushedStreamWrapper : public nsISupports {
|
|||
nsCString mRequestString;
|
||||
nsCString mResourceUrl;
|
||||
uint32_t mStreamID;
|
||||
WeakPtr<Http2Stream> mStream;
|
||||
WeakPtr<Http2StreamBase> mStream;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
#include "AltServiceChild.h"
|
||||
#include "Http2Session.h"
|
||||
#include "Http2Stream.h"
|
||||
#include "Http2StreamBase.h"
|
||||
#include "Http2StreamTunnel.h"
|
||||
#include "Http2StreamWebSocket.h"
|
||||
#include "Http2Push.h"
|
||||
|
||||
#include "mozilla/EndianUtils.h"
|
||||
|
@ -56,8 +59,8 @@ NS_INTERFACE_MAP_BEGIN(Http2Session)
|
|||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsAHttpConnection)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
static void RemoveStreamFromQueue(Http2Stream* aStream,
|
||||
nsTArray<WeakPtr<Http2Stream>>& queue) {
|
||||
static void RemoveStreamFromQueue(Http2StreamBase* aStream,
|
||||
nsTArray<WeakPtr<Http2StreamBase>>& queue) {
|
||||
for (const auto& stream : Reversed(queue)) {
|
||||
if (stream == aStream) {
|
||||
queue.RemoveElement(stream);
|
||||
|
@ -65,15 +68,15 @@ static void RemoveStreamFromQueue(Http2Stream* aStream,
|
|||
}
|
||||
}
|
||||
|
||||
static void AddStreamToQueue(Http2Stream* aStream,
|
||||
nsTArray<WeakPtr<Http2Stream>>& queue) {
|
||||
static void AddStreamToQueue(Http2StreamBase* aStream,
|
||||
nsTArray<WeakPtr<Http2StreamBase>>& queue) {
|
||||
if (!queue.Contains(aStream)) {
|
||||
queue.AppendElement(aStream);
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<Http2Stream> GetNextStreamFromQueue(
|
||||
nsTArray<WeakPtr<Http2Stream>>& queue) {
|
||||
static already_AddRefed<Http2StreamBase> GetNextStreamFromQueue(
|
||||
nsTArray<WeakPtr<Http2StreamBase>>& queue) {
|
||||
while (!queue.IsEmpty() && !queue[0]) {
|
||||
MOZ_ASSERT(false);
|
||||
queue.RemoveElementAt(0);
|
||||
|
@ -82,7 +85,7 @@ static already_AddRefed<Http2Stream> GetNextStreamFromQueue(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<Http2Stream> stream = queue[0].get();
|
||||
RefPtr<Http2StreamBase> stream = queue[0].get();
|
||||
queue.RemoveElementAt(0);
|
||||
return stream.forget();
|
||||
}
|
||||
|
@ -257,7 +260,7 @@ inline nsresult Http2Session::SessionError(enum errorType reason) {
|
|||
return NS_ERROR_NET_HTTP2_SENT_GOAWAY;
|
||||
}
|
||||
|
||||
void Http2Session::LogIO(Http2Session* self, Http2Stream* stream,
|
||||
void Http2Session::LogIO(Http2Session* self, Http2StreamBase* stream,
|
||||
const char* label, const char* data,
|
||||
uint32_t datalen) {
|
||||
if (!LOG5_ENABLED()) return;
|
||||
|
@ -401,7 +404,8 @@ uint32_t Http2Session::ReadTimeoutTick(PRIntervalTime now) {
|
|||
return 1; // run the tick aggressively while ping is outstanding
|
||||
}
|
||||
|
||||
uint32_t Http2Session::RegisterStreamID(Http2Stream* stream, uint32_t aNewID) {
|
||||
uint32_t Http2Session::RegisterStreamID(Http2StreamBase* stream,
|
||||
uint32_t aNewID) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(mNextStreamID < 0xfffffff0,
|
||||
"should have stopped admitting streams");
|
||||
|
@ -568,14 +572,37 @@ bool Http2Session::AddStream(nsAHttpTransaction* aHttpTransaction,
|
|||
return true;
|
||||
}
|
||||
|
||||
RefPtr<Http2Stream> refStream = new Http2Stream(
|
||||
aHttpTransaction, this, aPriority, mCurrentTopBrowsingContextId);
|
||||
CreateStream(aHttpTransaction, aPriority, Http2StreamBaseType::Normal);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Http2Session::CreateStream(nsAHttpTransaction* aHttpTransaction,
|
||||
int32_t aPriority,
|
||||
Http2StreamBaseType streamType) {
|
||||
RefPtr<Http2StreamBase> refStream;
|
||||
switch (streamType) {
|
||||
case Http2StreamBaseType::Normal:
|
||||
refStream = new Http2Stream(aHttpTransaction, this, aPriority,
|
||||
mCurrentTopBrowsingContextId);
|
||||
break;
|
||||
case Http2StreamBaseType::Tunnel:
|
||||
refStream = new Http2StreamTunnel(aHttpTransaction, this, aPriority,
|
||||
mCurrentTopBrowsingContextId);
|
||||
break;
|
||||
case Http2StreamBaseType::WebSocket:
|
||||
refStream = new Http2StreamWebSocket(aHttpTransaction, this, aPriority,
|
||||
mCurrentTopBrowsingContextId);
|
||||
break;
|
||||
case Http2StreamBaseType::ServerPush:
|
||||
MOZ_RELEASE_ASSERT(false);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG3(("Http2Session::AddStream session=%p stream=%p serial=%" PRIu64 " "
|
||||
"NextID=0x%X (tentative)",
|
||||
this, refStream.get(), mSerial, mNextStreamID));
|
||||
|
||||
RefPtr<Http2Stream> stream = refStream;
|
||||
RefPtr<Http2StreamBase> stream = refStream;
|
||||
mStreamTransactionHash.InsertOrUpdate(aHttpTransaction, std::move(refStream));
|
||||
|
||||
AddStreamToQueue(stream, mReadyForWrite);
|
||||
|
@ -595,11 +622,9 @@ bool Http2Session::AddStream(nsAHttpTransaction* aHttpTransaction,
|
|||
this, aHttpTransaction));
|
||||
DontReuse();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Http2Session::QueueStream(Http2Stream* stream) {
|
||||
void Http2Session::QueueStream(Http2StreamBase* stream) {
|
||||
// will be removed via processpending or a shutdown path
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(!stream->CountAsActive());
|
||||
|
@ -621,7 +646,7 @@ void Http2Session::QueueStream(Http2Stream* stream) {
|
|||
void Http2Session::ProcessPending() {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
|
||||
RefPtr<Http2Stream> stream;
|
||||
RefPtr<Http2StreamBase> stream;
|
||||
while (RoomForMoreConcurrent() &&
|
||||
(stream = GetNextStreamFromQueue(mQueuedStreams))) {
|
||||
LOG3(("Http2Session::ProcessPending %p stream %p woken from queue.", this,
|
||||
|
@ -765,7 +790,7 @@ void Http2Session::ResetDownstreamState() {
|
|||
|
||||
// return true if activated (and counted against max)
|
||||
// otherwise return false and queue
|
||||
bool Http2Session::TryToActivate(Http2Stream* aStream) {
|
||||
bool Http2Session::TryToActivate(Http2StreamBase* aStream) {
|
||||
if (aStream->Queued()) {
|
||||
LOG3(("Http2Session::TryToActivate %p stream=%p already queued.\n", this,
|
||||
aStream));
|
||||
|
@ -788,7 +813,7 @@ bool Http2Session::TryToActivate(Http2Stream* aStream) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void Http2Session::IncrementConcurrent(Http2Stream* stream) {
|
||||
void Http2Session::IncrementConcurrent(Http2StreamBase* stream) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MOZ_ASSERT(!stream->StreamID() || (stream->StreamID() & 1),
|
||||
"Do not activate pushed streams");
|
||||
|
@ -849,7 +874,7 @@ template void Http2Session::CreateFrameHeader(uint8_t* dest,
|
|||
uint8_t frameFlags,
|
||||
uint32_t streamID);
|
||||
|
||||
void Http2Session::MaybeDecrementConcurrent(Http2Stream* aStream) {
|
||||
void Http2Session::MaybeDecrementConcurrent(Http2StreamBase* aStream) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG3(("MaybeDecrementConcurrent %p id=0x%X concurrent=%d active=%d\n", this,
|
||||
aStream->StreamID(), mConcurrent, aStream->CountAsActive()));
|
||||
|
@ -928,7 +953,7 @@ void Http2Session::GenerateRstStream(uint32_t aStatusCode, uint32_t aID) {
|
|||
|
||||
// make sure we don't do this twice for the same stream (at least if we
|
||||
// have a stream entry for it)
|
||||
Http2Stream* stream = mStreamIDHash.Get(aID);
|
||||
Http2StreamBase* stream = mStreamIDHash.Get(aID);
|
||||
if (stream) {
|
||||
if (stream->SentReset()) return;
|
||||
stream->SetSentReset(true);
|
||||
|
@ -1143,7 +1168,7 @@ void Http2Session::CreatePriorityNode(uint32_t streamID, uint32_t dependsOn,
|
|||
|
||||
// perform a bunch of integrity checks on the stream.
|
||||
// returns true if passed, false (plus LOG and ABORT) if failed.
|
||||
bool Http2Session::VerifyStream(Http2Stream* aStream,
|
||||
bool Http2Session::VerifyStream(Http2StreamBase* aStream,
|
||||
uint32_t aOptionalID = 0) {
|
||||
// This is annoying, but at least it is O(1)
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
|
@ -1169,7 +1194,7 @@ bool Http2Session::VerifyStream(Http2Stream* aStream,
|
|||
if (mStreamTransactionHash.GetWeak(trans) != aStream) break;
|
||||
|
||||
if (aStream->StreamID()) {
|
||||
Http2Stream* idStream = mStreamIDHash.Get(aStream->StreamID());
|
||||
Http2StreamBase* idStream = mStreamIDHash.Get(aStream->StreamID());
|
||||
|
||||
test++;
|
||||
if (idStream != aStream) break;
|
||||
|
@ -1195,7 +1220,7 @@ bool Http2Session::VerifyStream(Http2Stream* aStream,
|
|||
#endif // DEBUG
|
||||
}
|
||||
|
||||
void Http2Session::CleanupStream(Http2Stream* aStream, nsresult aResult,
|
||||
void Http2Session::CleanupStream(Http2StreamBase* aStream, nsresult aResult,
|
||||
errorType aResetCode) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG3(("Http2Session::CleanupStream %p %p 0x%X %" PRIX32 "\n", this, aStream,
|
||||
|
@ -1204,13 +1229,17 @@ void Http2Session::CleanupStream(Http2Stream* aStream, nsresult aResult,
|
|||
return;
|
||||
}
|
||||
|
||||
Http2PushedStream* pushSource = aStream->PushSource();
|
||||
if (pushSource) {
|
||||
// aStream is a synthetic attached to an even push
|
||||
MOZ_ASSERT(pushSource->GetConsumerStream() == aStream);
|
||||
MOZ_ASSERT(!aStream->StreamID());
|
||||
MOZ_ASSERT(!(pushSource->StreamID() & 0x1));
|
||||
aStream->ClearPushSource();
|
||||
Http2PushedStream* pushSource = nullptr;
|
||||
Http2Stream* h2Stream = aStream->GetHttp2Stream();
|
||||
if (h2Stream) {
|
||||
pushSource = h2Stream->PushSource();
|
||||
if (pushSource) {
|
||||
// aStream is a synthetic attached to an even push
|
||||
MOZ_ASSERT(pushSource->GetConsumerStream() == aStream);
|
||||
MOZ_ASSERT(!aStream->StreamID());
|
||||
MOZ_ASSERT(!(pushSource->StreamID() & 0x1));
|
||||
h2Stream->ClearPushSource();
|
||||
}
|
||||
}
|
||||
|
||||
if (aStream->DeferCleanup(aResult)) {
|
||||
|
@ -1265,7 +1294,7 @@ void Http2Session::CleanupStream(Http2Stream* aStream, nsresult aResult,
|
|||
RemoveStreamFromQueues(aStream);
|
||||
|
||||
// removing from the stream transaction hash will
|
||||
// delete the Http2Stream and drop the reference to
|
||||
// delete the Http2StreamBase and drop the reference to
|
||||
// its transaction
|
||||
mStreamTransactionHash.Remove(aStream->Transaction());
|
||||
|
||||
|
@ -1280,7 +1309,7 @@ void Http2Session::CleanupStream(Http2Stream* aStream, nsresult aResult,
|
|||
void Http2Session::CleanupStream(uint32_t aID, nsresult aResult,
|
||||
errorType aResetCode) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
Http2Stream* stream = mStreamIDHash.Get(aID);
|
||||
Http2StreamBase* stream = mStreamIDHash.Get(aID);
|
||||
LOG3(("Http2Session::CleanupStream %p by ID 0x%X to stream %p\n", this, aID,
|
||||
stream));
|
||||
if (!stream) {
|
||||
|
@ -1289,14 +1318,14 @@ void Http2Session::CleanupStream(uint32_t aID, nsresult aResult,
|
|||
CleanupStream(stream, aResult, aResetCode);
|
||||
}
|
||||
|
||||
void Http2Session::RemoveStreamFromQueues(Http2Stream* aStream) {
|
||||
void Http2Session::RemoveStreamFromQueues(Http2StreamBase* aStream) {
|
||||
RemoveStreamFromQueue(aStream, mReadyForWrite);
|
||||
RemoveStreamFromQueue(aStream, mQueuedStreams);
|
||||
RemoveStreamFromQueue(aStream, mPushesReadyForRead);
|
||||
RemoveStreamFromQueue(aStream, mSlowConsumersReadyForRead);
|
||||
}
|
||||
|
||||
void Http2Session::CloseStream(Http2Stream* aStream, nsresult aResult) {
|
||||
void Http2Session::CloseStream(Http2StreamBase* aStream, nsresult aResult) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG3(("Http2Session::CloseStream %p %p 0x%x %" PRIX32 "\n", this, aStream,
|
||||
aStream->StreamID(), static_cast<uint32_t>(aResult)));
|
||||
|
@ -1313,7 +1342,7 @@ void Http2Session::CloseStream(Http2Stream* aStream, nsresult aResult) {
|
|||
RemoveStreamFromQueues(aStream);
|
||||
|
||||
if (aStream->IsTunnel()) {
|
||||
UnRegisterTunnel(aStream);
|
||||
UnRegisterTunnel(static_cast<Http2StreamTunnel*>(aStream));
|
||||
}
|
||||
|
||||
// Send the stream the close() indication
|
||||
|
@ -1533,7 +1562,7 @@ nsresult Http2Session::ResponseHeadersComplete() {
|
|||
|
||||
// The stream needs to see flattened http headers
|
||||
// Uncompressed http/2 format headers currently live in
|
||||
// Http2Stream::mDecompressBuffer - convert that to HTTP format in
|
||||
// Http2StreamBase::mDecompressBuffer - convert that to HTTP format in
|
||||
// mFlatHTTPResponseHeaders via ConvertHeaders()
|
||||
|
||||
nsresult rv;
|
||||
|
@ -1822,7 +1851,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) {
|
|||
nsresult rv = self->SetInputFrameDataStream(associatedID);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
Http2Stream* associatedStream = self->mInputFrameDataStream;
|
||||
Http2StreamBase* associatedStream = self->mInputFrameDataStream;
|
||||
++(self->mServerPushedResources);
|
||||
|
||||
// Anytime we start using the high bit of stream ID (either client or server)
|
||||
|
@ -1964,7 +1993,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) {
|
|||
// is for a client initiated stream. Errors that aren't fatal to the
|
||||
// whole session must call cleanupStream() after this point in order
|
||||
// to remove the stream from that hash.
|
||||
WeakPtr<Http2Stream> pushedWeak = pushedStream.get();
|
||||
WeakPtr<Http2StreamBase> pushedWeak = pushedStream.get();
|
||||
self->mStreamTransactionHash.InsertOrUpdate(transactionBuffer,
|
||||
std::move(pushedStream));
|
||||
self->mPushedStreams.AppendElement(
|
||||
|
@ -1999,7 +2028,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) {
|
|||
LOG3(("Http2Session::RecvPushPromise %p origin check %s", self,
|
||||
pushedWeak->Origin().get()));
|
||||
nsCOMPtr<nsIURI> pushedOrigin;
|
||||
rv = Http2Stream::MakeOriginURL(pushedWeak->Origin(), pushedOrigin);
|
||||
rv = MakeOriginURL(pushedWeak->Origin(), pushedOrigin);
|
||||
nsAutoCString pushedHostName;
|
||||
int32_t pushedPort = -1;
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
|
@ -2060,7 +2089,7 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) {
|
|||
// generally ok off the main thread), since we're not using the protocol
|
||||
// handler to create any URIs, this will work just fine here. Don't try this
|
||||
// at home, though, kids. I'm a trained professional.
|
||||
if (NS_SUCCEEDED(Http2Stream::MakeOriginURL(spec, pushedURL))) {
|
||||
if (NS_SUCCEEDED(MakeOriginURL(spec, pushedURL))) {
|
||||
LOG3(("Http2Session::RecvPushPromise %p check disk cache for entry",
|
||||
self));
|
||||
mozilla::OriginAttributes oa;
|
||||
|
@ -2094,8 +2123,8 @@ nsresult Http2Session::RecvPushPromise(Http2Session* self) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
pushedWeak->SetHTTPState(Http2Stream::RESERVED_BY_REMOTE);
|
||||
static_assert(Http2Stream::kWorstPriority >= 0,
|
||||
pushedWeak->SetHTTPState(Http2StreamBase::RESERVED_BY_REMOTE);
|
||||
static_assert(Http2StreamBase::kWorstPriority >= 0,
|
||||
"kWorstPriority out of range");
|
||||
uint32_t priorityDependency = pushedWeak->PriorityDependency();
|
||||
uint8_t priorityWeight = pushedWeak->PriorityWeight();
|
||||
|
@ -2177,8 +2206,8 @@ nsresult Http2Session::RecvGoAway(Http2Session* self) {
|
|||
// Process the streams marked for deletion and restart.
|
||||
size_t size = self->mGoAwayStreamsToRestart.GetSize();
|
||||
for (size_t count = 0; count < size; ++count) {
|
||||
Http2Stream* stream =
|
||||
static_cast<Http2Stream*>(self->mGoAwayStreamsToRestart.PopFront());
|
||||
Http2StreamBase* stream =
|
||||
static_cast<Http2StreamBase*>(self->mGoAwayStreamsToRestart.PopFront());
|
||||
|
||||
if (self->mPeerGoAwayReason == HTTP_1_1_REQUIRED) {
|
||||
stream->Transaction()->DisableSpdy();
|
||||
|
@ -2639,7 +2668,7 @@ nsresult Http2Session::RecvOrigin(Http2Session* self) {
|
|||
self->mInputFrameBuffer.get() + kFrameHeaderBytes + offset + 2,
|
||||
originLen);
|
||||
offset += originLen + 2;
|
||||
if (NS_FAILED(Http2Stream::MakeOriginURL(originString, originURL))) {
|
||||
if (NS_FAILED(MakeOriginURL(originString, originURL))) {
|
||||
LOG3(
|
||||
("Http2Session::RecvOrigin %p origin frame string %s failed to "
|
||||
"parse\n",
|
||||
|
@ -2732,13 +2761,13 @@ void Http2Session::OnTransportStatus(nsITransport* aTransport, nsresult aStatus,
|
|||
//
|
||||
// There is no good way to map it to the right transaction in http/2,
|
||||
// so it is ignored here and generated separately when the request
|
||||
// is sent from Http2Stream::TransmitFrame
|
||||
// is sent from Http2StreamBase::TransmitFrame
|
||||
|
||||
// NS_NET_STATUS_WAITING_FOR:
|
||||
// Created by nsHttpConnection when the request has been totally sent.
|
||||
// There is no good way to map it to the right transaction in http/2,
|
||||
// so it is ignored here and generated separately when the same
|
||||
// condition is complete in Http2Stream when there is no more
|
||||
// condition is complete in Http2StreamBase when there is no more
|
||||
// request body left to be transmitted.
|
||||
|
||||
// NS_NET_STATUS_RECEIVING_FROM
|
||||
|
@ -2781,7 +2810,7 @@ nsresult Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
|
|||
|
||||
LOG3(("Http2Session::ReadSegments %p", this));
|
||||
|
||||
RefPtr<Http2Stream> stream = GetNextStreamFromQueue(mReadyForWrite);
|
||||
RefPtr<Http2StreamBase> stream = GetNextStreamFromQueue(mReadyForWrite);
|
||||
|
||||
if (!stream) {
|
||||
LOG3(("Http2Session %p could not identify a stream to write; suspending.",
|
||||
|
@ -2807,8 +2836,10 @@ nsresult Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
|
|||
uint32_t earlyDataUsed = 0;
|
||||
if (mAttemptingEarlyData) {
|
||||
if (!stream->Do0RTT()) {
|
||||
LOG3(("Http2Session %p will not get early data from Http2Stream %p 0x%X",
|
||||
this, stream.get(), stream->StreamID()));
|
||||
LOG3(
|
||||
("Http2Session %p will not get early data from Http2StreamBase %p "
|
||||
"0x%X",
|
||||
this, stream.get(), stream->StreamID()));
|
||||
FlushOutputQueue();
|
||||
SetWriteCallbacks();
|
||||
if (!mCannotDo0RTTStreams.Contains(stream)) {
|
||||
|
@ -2829,7 +2860,7 @@ nsresult Http2Session::ReadSegmentsAgain(nsAHttpSegmentReader* reader,
|
|||
}
|
||||
|
||||
LOG3(
|
||||
("Http2Session %p will write from Http2Stream %p 0x%X "
|
||||
("Http2Session %p will write from Http2StreamBase %p 0x%X "
|
||||
"block-input=%d block-output=%d\n",
|
||||
this, stream.get(), stream->StreamID(), stream->RequestBlockedOnRead(),
|
||||
stream->BlockedOnRwin()));
|
||||
|
@ -3034,7 +3065,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
|
|||
// If there are http transactions attached to a push stream with filled
|
||||
// buffers trigger that data pump here. This only reads from buffers (not the
|
||||
// network) so mDownstreamState doesn't matter.
|
||||
RefPtr<Http2Stream> pushConnectedStream =
|
||||
RefPtr<Http2StreamBase> pushConnectedStream =
|
||||
GetNextStreamFromQueue(mPushesReadyForRead);
|
||||
if (pushConnectedStream) {
|
||||
return ProcessConnectedPush(pushConnectedStream, writer, count,
|
||||
|
@ -3043,7 +3074,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
|
|||
|
||||
// feed gecko channels that previously stopped consuming data
|
||||
// only take data from stored buffers
|
||||
RefPtr<Http2Stream> slowConsumer =
|
||||
RefPtr<Http2StreamBase> slowConsumer =
|
||||
GetNextStreamFromQueue(mSlowConsumersReadyForRead);
|
||||
if (slowConsumer) {
|
||||
internalStateType savedState = mDownstreamState;
|
||||
|
@ -3274,7 +3305,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
|
|||
}
|
||||
|
||||
// mInputFrameDataStream is reset by ChangeDownstreamState
|
||||
Http2Stream* stream = mInputFrameDataStream;
|
||||
Http2StreamBase* stream = mInputFrameDataStream;
|
||||
ResetDownstreamState();
|
||||
LOG3(
|
||||
("Http2Session::WriteSegments cleanup stream on recv of rst "
|
||||
|
@ -3382,7 +3413,7 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
|
|||
mInputFrameDataRead += *countWritten;
|
||||
|
||||
if (mInputFrameDataRead == mInputFrameDataSize) {
|
||||
Http2Stream* streamToCleanup = nullptr;
|
||||
Http2StreamBase* streamToCleanup = nullptr;
|
||||
if (mInputFrameFinal) {
|
||||
streamToCleanup = mInputFrameDataStream;
|
||||
}
|
||||
|
@ -3392,11 +3423,12 @@ nsresult Http2Session::WriteSegmentsAgain(nsAHttpSegmentWriter* writer,
|
|||
ResetDownstreamState();
|
||||
|
||||
if (streamToCleanup) {
|
||||
if (discardedPadding && !(streamToCleanup->StreamID() & 1)) {
|
||||
Http2PushedStream* pushed = streamToCleanup->GetHttp2PushedStream();
|
||||
if (discardedPadding && pushed) {
|
||||
// Pushed streams are special on padding-only final data frames.
|
||||
// See bug 1409570 comments 6-8 for details.
|
||||
streamToCleanup->SetPushComplete();
|
||||
Http2Stream* pushSink = streamToCleanup->GetConsumerStream();
|
||||
pushed->SetPushComplete();
|
||||
Http2StreamBase* pushSink = pushed->GetConsumerStream();
|
||||
if (pushSink) {
|
||||
bool enqueueSink = true;
|
||||
for (const auto& s : mPushesReadyForRead) {
|
||||
|
@ -3528,10 +3560,9 @@ nsresult Http2Session::Finish0RTT(bool aRestart, bool aAlpnChanged) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult Http2Session::ProcessConnectedPush(Http2Stream* pushConnectedStream,
|
||||
nsAHttpSegmentWriter* writer,
|
||||
uint32_t count,
|
||||
uint32_t* countWritten) {
|
||||
nsresult Http2Session::ProcessConnectedPush(
|
||||
Http2StreamBase* pushConnectedStream, nsAHttpSegmentWriter* writer,
|
||||
uint32_t count, uint32_t* countWritten) {
|
||||
LOG3(("Http2Session::ProcessConnectedPush %p 0x%X\n", this,
|
||||
pushConnectedStream->StreamID()));
|
||||
mSegmentWriter = writer;
|
||||
|
@ -3540,8 +3571,10 @@ nsresult Http2Session::ProcessConnectedPush(Http2Stream* pushConnectedStream,
|
|||
|
||||
// The pipe in nsHttpTransaction rewrites CLOSED error codes into OK
|
||||
// so we need this check to determine the truth.
|
||||
if (NS_SUCCEEDED(rv) && !*countWritten && pushConnectedStream->PushSource() &&
|
||||
pushConnectedStream->PushSource()->GetPushComplete()) {
|
||||
Http2Stream* h2Stream = pushConnectedStream->GetHttp2Stream();
|
||||
MOZ_ASSERT(h2Stream);
|
||||
if (NS_SUCCEEDED(rv) && !*countWritten && h2Stream &&
|
||||
h2Stream->PushSource() && h2Stream->PushSource()->GetPushComplete()) {
|
||||
rv = NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
|
||||
|
@ -3560,7 +3593,7 @@ nsresult Http2Session::ProcessConnectedPush(Http2Stream* pushConnectedStream,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult Http2Session::ProcessSlowConsumer(Http2Stream* slowConsumer,
|
||||
nsresult Http2Session::ProcessSlowConsumer(Http2StreamBase* slowConsumer,
|
||||
nsAHttpSegmentWriter* writer,
|
||||
uint32_t count,
|
||||
uint32_t* countWritten) {
|
||||
|
@ -3593,7 +3626,7 @@ nsresult Http2Session::ProcessSlowConsumer(Http2Stream* slowConsumer,
|
|||
return rv;
|
||||
}
|
||||
|
||||
void Http2Session::UpdateLocalStreamWindow(Http2Stream* stream,
|
||||
void Http2Session::UpdateLocalStreamWindow(Http2StreamBase* stream,
|
||||
uint32_t bytes) {
|
||||
if (!stream) { // this is ok - it means there was a data frame for a rst
|
||||
// stream
|
||||
|
@ -3701,7 +3734,7 @@ void Http2Session::UpdateLocalSessionWindow(uint32_t bytes) {
|
|||
// dont flush here, this write can commonly be coalesced with others
|
||||
}
|
||||
|
||||
void Http2Session::UpdateLocalRwin(Http2Stream* stream, uint32_t bytes) {
|
||||
void Http2Session::UpdateLocalRwin(Http2StreamBase* stream, uint32_t bytes) {
|
||||
// make sure there is room for 2 window updates even though
|
||||
// we may not generate any.
|
||||
EnsureOutputBuffer(2 * (kFrameHeaderBytes + 4));
|
||||
|
@ -3792,7 +3825,7 @@ void Http2Session::CloseTransaction(nsAHttpTransaction* aTransaction,
|
|||
// Generally this arrives as a cancel event from the connection manager.
|
||||
|
||||
// need to find the stream and call CleanupStream() on it.
|
||||
RefPtr<Http2Stream> stream = mStreamTransactionHash.Get(aTransaction);
|
||||
RefPtr<Http2StreamBase> stream = mStreamTransactionHash.Get(aTransaction);
|
||||
if (!stream) {
|
||||
LOG3(("Http2Session::CloseTransaction %p %p %" PRIx32 " - not found.", this,
|
||||
aTransaction, static_cast<uint32_t>(aResult)));
|
||||
|
@ -4018,12 +4051,12 @@ void Http2Session::SetNeedsCleanup() {
|
|||
ResetDownstreamState();
|
||||
}
|
||||
|
||||
void Http2Session::ConnectPushedStream(Http2Stream* stream) {
|
||||
void Http2Session::ConnectPushedStream(Http2StreamBase* stream) {
|
||||
AddStreamToQueue(stream, mPushesReadyForRead);
|
||||
Unused << ForceRecv();
|
||||
}
|
||||
|
||||
void Http2Session::ConnectSlowConsumer(Http2Stream* stream) {
|
||||
void Http2Session::ConnectSlowConsumer(Http2StreamBase* stream) {
|
||||
LOG3(("Http2Session::ConnectSlowConsumer %p 0x%X\n", this,
|
||||
stream->StreamID()));
|
||||
AddStreamToQueue(stream, mSlowConsumersReadyForRead);
|
||||
|
@ -4039,15 +4072,15 @@ uint32_t Http2Session::FindTunnelCount(nsCString const& aHashKey) {
|
|||
return rv;
|
||||
}
|
||||
|
||||
void Http2Session::RegisterTunnel(Http2Stream* aTunnel) {
|
||||
void Http2Session::RegisterTunnel(Http2StreamTunnel* aTunnel) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
nsCString const& regKey = aTunnel->RegistrationKey();
|
||||
const uint32_t newcount = ++mTunnelHash.LookupOrInsert(regKey, 0);
|
||||
LOG3(("Http2Stream::RegisterTunnel %p stream=%p tunnels=%d [%s]", this,
|
||||
LOG3(("Http2StreamBase::RegisterTunnel %p stream=%p tunnels=%d [%s]", this,
|
||||
aTunnel, newcount, regKey.get()));
|
||||
}
|
||||
|
||||
void Http2Session::UnRegisterTunnel(Http2Stream* aTunnel) {
|
||||
void Http2Session::UnRegisterTunnel(Http2StreamTunnel* aTunnel) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
nsCString const& regKey = aTunnel->RegistrationKey();
|
||||
auto entry = mTunnelHash.Lookup(regKey);
|
||||
|
@ -4071,13 +4104,12 @@ void Http2Session::CreateTunnel(nsHttpTransaction* trans,
|
|||
RefPtr<nsHttpConnectionInfo> clone(ci->Clone());
|
||||
RefPtr<Http2ConnectTransaction> connectTrans = new Http2ConnectTransaction(
|
||||
clone, aCallbacks, trans->Caps(), trans, this, false);
|
||||
DebugOnly<bool> rv =
|
||||
AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL, false,
|
||||
false, nullptr);
|
||||
MOZ_ASSERT(rv);
|
||||
RefPtr<Http2Stream> tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
|
||||
CreateStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL,
|
||||
Http2StreamBaseType::Tunnel);
|
||||
RefPtr<Http2StreamBase> tunnel = mStreamTransactionHash.Get(connectTrans);
|
||||
MOZ_ASSERT(tunnel);
|
||||
RegisterTunnel(tunnel);
|
||||
RegisterTunnel(static_cast<Http2StreamTunnel*>(tunnel.get()));
|
||||
}
|
||||
|
||||
void Http2Session::DispatchOnTunnel(nsAHttpTransaction* aHttpTransaction,
|
||||
|
@ -4279,7 +4311,7 @@ void Http2Session::TransactionHasDataToWrite(nsAHttpTransaction* caller) {
|
|||
// a trapped signal from the http transaction to the connection that
|
||||
// it is no longer blocked on read.
|
||||
|
||||
RefPtr<Http2Stream> stream = mStreamTransactionHash.Get(caller);
|
||||
RefPtr<Http2StreamBase> stream = mStreamTransactionHash.Get(caller);
|
||||
if (!stream || !VerifyStream(stream)) {
|
||||
LOG3(("Http2Session::TransactionHasDataToWrite %p caller %p not found",
|
||||
this, caller));
|
||||
|
@ -4311,7 +4343,7 @@ void Http2Session::TransactionHasDataToRecv(nsAHttpTransaction* caller) {
|
|||
|
||||
// a signal from the http transaction to the connection that it will consume
|
||||
// more
|
||||
RefPtr<Http2Stream> stream = mStreamTransactionHash.Get(caller);
|
||||
RefPtr<Http2StreamBase> stream = mStreamTransactionHash.Get(caller);
|
||||
if (!stream || !VerifyStream(stream)) {
|
||||
LOG3(("Http2Session::TransactionHasDataToRecv %p caller %p not found", this,
|
||||
caller));
|
||||
|
@ -4323,7 +4355,7 @@ void Http2Session::TransactionHasDataToRecv(nsAHttpTransaction* caller) {
|
|||
ConnectSlowConsumer(stream);
|
||||
}
|
||||
|
||||
void Http2Session::TransactionHasDataToWrite(Http2Stream* stream) {
|
||||
void Http2Session::TransactionHasDataToWrite(Http2StreamBase* stream) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
LOG3(("Http2Session::TransactionHasDataToWrite %p stream=%p ID=0x%x", this,
|
||||
stream, stream->StreamID()));
|
||||
|
@ -4605,10 +4637,9 @@ void Http2Session::CreateWebsocketStream(
|
|||
RefPtr<nsHttpConnectionInfo> clone(ci->Clone());
|
||||
RefPtr<Http2ConnectTransaction> connectTrans = new Http2ConnectTransaction(
|
||||
clone, aCallbacks, trans->Caps(), trans, this, true);
|
||||
DebugOnly<bool> rv =
|
||||
AddStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL, false,
|
||||
false, nullptr);
|
||||
MOZ_ASSERT(rv);
|
||||
|
||||
CreateStream(connectTrans, nsISupportsPriority::PRIORITY_NORMAL,
|
||||
Http2StreamBaseType::WebSocket);
|
||||
}
|
||||
|
||||
void Http2Session::ProcessWaitingWebsockets() {
|
||||
|
|
|
@ -30,9 +30,12 @@ namespace mozilla {
|
|||
namespace net {
|
||||
|
||||
class Http2PushedStream;
|
||||
class Http2Stream;
|
||||
class Http2StreamBase;
|
||||
class Http2StreamTunnel;
|
||||
class nsHttpTransaction;
|
||||
|
||||
enum Http2StreamBaseType { Normal, WebSocket, Tunnel, ServerPush };
|
||||
|
||||
// b23b147c-c4f8-4d6e-841a-09f29a010de7
|
||||
#define NS_HTTP2SESSION_IID \
|
||||
{ \
|
||||
|
@ -78,7 +81,7 @@ class Http2Session final : public ASpdySession,
|
|||
PRIntervalTime IdleTime() override;
|
||||
|
||||
// Registering with a newID of 0 means pick the next available odd ID
|
||||
uint32_t RegisterStreamID(Http2Stream*, uint32_t aNewID = 0);
|
||||
uint32_t RegisterStreamID(Http2StreamBase*, uint32_t aNewID = 0);
|
||||
|
||||
/*
|
||||
HTTP/2 framing
|
||||
|
@ -224,15 +227,15 @@ class Http2Session final : public ASpdySession,
|
|||
uint8_t frameFlags, uint32_t streamID);
|
||||
|
||||
// For writing the data stream to LOG4
|
||||
static void LogIO(Http2Session*, Http2Stream*, const char*, const char*,
|
||||
static void LogIO(Http2Session*, Http2StreamBase*, const char*, const char*,
|
||||
uint32_t);
|
||||
|
||||
// overload of nsAHttpConnection
|
||||
void TransactionHasDataToWrite(nsAHttpTransaction*) override;
|
||||
void TransactionHasDataToRecv(nsAHttpTransaction*) override;
|
||||
|
||||
// a similar version for Http2Stream
|
||||
void TransactionHasDataToWrite(Http2Stream*);
|
||||
// a similar version for Http2StreamBase
|
||||
void TransactionHasDataToWrite(Http2StreamBase*);
|
||||
|
||||
// an overload of nsAHttpSegementReader
|
||||
[[nodiscard]] virtual nsresult CommitToSegmentSize(
|
||||
|
@ -245,9 +248,9 @@ class Http2Session final : public ASpdySession,
|
|||
|
||||
uint32_t GetServerInitialStreamWindow() { return mServerInitialStreamWindow; }
|
||||
|
||||
[[nodiscard]] bool TryToActivate(Http2Stream* stream);
|
||||
void ConnectPushedStream(Http2Stream* stream);
|
||||
void ConnectSlowConsumer(Http2Stream* stream);
|
||||
[[nodiscard]] bool TryToActivate(Http2StreamBase* stream);
|
||||
void ConnectPushedStream(Http2StreamBase* stream);
|
||||
void ConnectSlowConsumer(Http2StreamBase* stream);
|
||||
|
||||
[[nodiscard]] nsresult ConfirmTLSProfile();
|
||||
[[nodiscard]] static bool ALPNCallback(nsISupports* securityInfo);
|
||||
|
@ -309,6 +312,9 @@ class Http2Session final : public ASpdySession,
|
|||
|
||||
static const uint8_t kMagicHello[24];
|
||||
|
||||
void CreateStream(nsAHttpTransaction* aHttpTransaction, int32_t aPriority,
|
||||
Http2StreamBaseType streamType);
|
||||
|
||||
[[nodiscard]] nsresult ResponseHeadersComplete();
|
||||
uint32_t GetWriteQueueSize();
|
||||
void ChangeDownstreamState(enum internalStateType);
|
||||
|
@ -320,38 +326,38 @@ class Http2Session final : public ASpdySession,
|
|||
void GeneratePriority(uint32_t, uint8_t);
|
||||
void GenerateRstStream(uint32_t, uint32_t);
|
||||
void GenerateGoAway(uint32_t);
|
||||
void CleanupStream(Http2Stream*, nsresult, errorType);
|
||||
void CleanupStream(Http2StreamBase*, nsresult, errorType);
|
||||
void CleanupStream(uint32_t, nsresult, errorType);
|
||||
void CloseStream(Http2Stream*, nsresult);
|
||||
void CloseStream(Http2StreamBase*, nsresult);
|
||||
void SendHello();
|
||||
void RemoveStreamFromQueues(Http2Stream*);
|
||||
void RemoveStreamFromQueues(Http2StreamBase*);
|
||||
[[nodiscard]] nsresult ParsePadding(uint8_t&, uint16_t&);
|
||||
|
||||
void SetWriteCallbacks();
|
||||
void RealignOutputQueue();
|
||||
|
||||
void ProcessPending();
|
||||
[[nodiscard]] nsresult ProcessConnectedPush(Http2Stream*,
|
||||
[[nodiscard]] nsresult ProcessConnectedPush(Http2StreamBase*,
|
||||
nsAHttpSegmentWriter*, uint32_t,
|
||||
uint32_t*);
|
||||
[[nodiscard]] nsresult ProcessSlowConsumer(Http2Stream*,
|
||||
[[nodiscard]] nsresult ProcessSlowConsumer(Http2StreamBase*,
|
||||
nsAHttpSegmentWriter*, uint32_t,
|
||||
uint32_t*);
|
||||
|
||||
[[nodiscard]] nsresult SetInputFrameDataStream(uint32_t);
|
||||
void CreatePriorityNode(uint32_t, uint32_t, uint8_t, const char*);
|
||||
char* CreatePriorityFrame(uint32_t, uint32_t, uint8_t);
|
||||
bool VerifyStream(Http2Stream*, uint32_t);
|
||||
bool VerifyStream(Http2StreamBase*, uint32_t);
|
||||
void SetNeedsCleanup();
|
||||
|
||||
void UpdateLocalRwin(Http2Stream* stream, uint32_t bytes);
|
||||
void UpdateLocalStreamWindow(Http2Stream* stream, uint32_t bytes);
|
||||
void UpdateLocalRwin(Http2StreamBase* stream, uint32_t bytes);
|
||||
void UpdateLocalStreamWindow(Http2StreamBase* stream, uint32_t bytes);
|
||||
void UpdateLocalSessionWindow(uint32_t bytes);
|
||||
|
||||
void MaybeDecrementConcurrent(Http2Stream* stream);
|
||||
void MaybeDecrementConcurrent(Http2StreamBase* stream);
|
||||
bool RoomForMoreConcurrent();
|
||||
void IncrementConcurrent(Http2Stream* stream);
|
||||
void QueueStream(Http2Stream* stream);
|
||||
void IncrementConcurrent(Http2StreamBase* stream);
|
||||
void QueueStream(Http2StreamBase* stream);
|
||||
|
||||
// a wrapper for all calls to the nshttpconnection level segment writer. Used
|
||||
// to track network I/O for timeout purposes
|
||||
|
@ -388,14 +394,14 @@ class Http2Session final : public ASpdySession,
|
|||
// There are also several lists of streams: ready to write, queued due to
|
||||
// max parallelism, streams that need to force a read for push, and the full
|
||||
// set of pushed streams.
|
||||
nsTHashMap<nsUint32HashKey, Http2Stream*> mStreamIDHash;
|
||||
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http2Stream>
|
||||
nsTHashMap<nsUint32HashKey, Http2StreamBase*> mStreamIDHash;
|
||||
nsRefPtrHashtable<nsPtrHashKey<nsAHttpTransaction>, Http2StreamBase>
|
||||
mStreamTransactionHash;
|
||||
|
||||
nsTArray<WeakPtr<Http2Stream>> mReadyForWrite;
|
||||
nsTArray<WeakPtr<Http2Stream>> mQueuedStreams;
|
||||
nsTArray<WeakPtr<Http2Stream>> mPushesReadyForRead;
|
||||
nsTArray<WeakPtr<Http2Stream>> mSlowConsumersReadyForRead;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> mReadyForWrite;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> mQueuedStreams;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> mPushesReadyForRead;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> mSlowConsumersReadyForRead;
|
||||
nsTArray<Http2PushedStream*> mPushedStreams;
|
||||
|
||||
// Compression contexts for header transport.
|
||||
|
@ -430,14 +436,14 @@ class Http2Session final : public ASpdySession,
|
|||
// When a frame has been received that is addressed to a particular stream
|
||||
// (e.g. a data frame after the stream-id has been decoded), this points
|
||||
// to the stream.
|
||||
Http2Stream* mInputFrameDataStream;
|
||||
Http2StreamBase* mInputFrameDataStream;
|
||||
|
||||
// mNeedsCleanup is a state variable to defer cleanup of a closed stream
|
||||
// If needed, It is set in session::OnWriteSegments() and acted on and
|
||||
// cleared when the stack returns to session::WriteSegments(). The stream
|
||||
// cannot be destroyed directly out of OnWriteSegments because
|
||||
// stream::writeSegments() is on the stack at that time.
|
||||
Http2Stream* mNeedsCleanup;
|
||||
Http2StreamBase* mNeedsCleanup;
|
||||
|
||||
// This reason code in the last processed RESET frame
|
||||
uint32_t mDownstreamRstReason;
|
||||
|
@ -538,7 +544,7 @@ class Http2Session final : public ASpdySession,
|
|||
bool mPreviousUsed; // true when backup is used
|
||||
|
||||
// used as a temporary buffer while enumerating the stream hash during GoAway
|
||||
nsDeque<Http2Stream> mGoAwayStreamsToRestart;
|
||||
nsDeque<Http2StreamBase> mGoAwayStreamsToRestart;
|
||||
|
||||
// Each session gets a unique serial number because the push cache is
|
||||
// correlated by the load group and the serial number can be used as part of
|
||||
|
@ -559,10 +565,10 @@ class Http2Session final : public ASpdySession,
|
|||
|
||||
bool mAttemptingEarlyData;
|
||||
// The ID(s) of the stream(s) that we are getting 0RTT data from.
|
||||
nsTArray<WeakPtr<Http2Stream>> m0RTTStreams;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> m0RTTStreams;
|
||||
// The ID(s) of the stream(s) that are not able to send 0RTT data. We need to
|
||||
// remember them put them into mReadyForWrite queue when 0RTT finishes.
|
||||
nsTArray<WeakPtr<Http2Stream>> mCannotDo0RTTStreams;
|
||||
nsTArray<WeakPtr<Http2StreamBase>> mCannotDo0RTTStreams;
|
||||
|
||||
bool RealJoinConnection(const nsACString& hostname, int32_t port,
|
||||
bool justKidding);
|
||||
|
@ -589,8 +595,8 @@ class Http2Session final : public ASpdySession,
|
|||
void DispatchOnTunnel(nsAHttpTransaction*, nsIInterfaceRequestor*);
|
||||
void CreateTunnel(nsHttpTransaction*, nsHttpConnectionInfo*,
|
||||
nsIInterfaceRequestor*);
|
||||
void RegisterTunnel(Http2Stream*);
|
||||
void UnRegisterTunnel(Http2Stream*);
|
||||
void RegisterTunnel(Http2StreamTunnel*);
|
||||
void UnRegisterTunnel(Http2StreamTunnel*);
|
||||
uint32_t FindTunnelCount(nsHttpConnectionInfo*);
|
||||
uint32_t FindTunnelCount(nsCString const&);
|
||||
nsTHashMap<nsCStringHashKey, uint32_t> mTunnelHash;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
@ -6,387 +7,35 @@
|
|||
#ifndef mozilla_net_Http2Stream_h
|
||||
#define mozilla_net_Http2Stream_h
|
||||
|
||||
// HTTP/2 - RFC7540
|
||||
// https://www.rfc-editor.org/rfc/rfc7540.txt
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "SimpleBuffer.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributes;
|
||||
}
|
||||
#include "Http2StreamBase.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
class nsStandardURL;
|
||||
class Http2Session;
|
||||
class Http2Decompressor;
|
||||
|
||||
class Http2Stream : public nsAHttpSegmentReader,
|
||||
public nsAHttpSegmentWriter,
|
||||
public SupportsWeakPtr {
|
||||
class Http2Stream : public Http2StreamBase {
|
||||
public:
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
NS_DECL_NSAHTTPSEGMENTWRITER
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http2Stream, override)
|
||||
Http2Stream(nsAHttpTransaction* httpTransaction, Http2Session* session,
|
||||
int32_t priority, uint64_t bcId)
|
||||
: Http2StreamBase(httpTransaction, session, priority, bcId) {}
|
||||
|
||||
enum stateType {
|
||||
IDLE,
|
||||
RESERVED_BY_REMOTE,
|
||||
OPEN,
|
||||
CLOSED_BY_LOCAL,
|
||||
CLOSED_BY_REMOTE,
|
||||
CLOSED
|
||||
};
|
||||
void Close(nsresult reason) override;
|
||||
Http2Stream* GetHttp2Stream() override { return this; }
|
||||
uint32_t GetWireStreamId() override;
|
||||
|
||||
const static int32_t kNormalPriority = 0x1000;
|
||||
const static int32_t kWorstPriority =
|
||||
kNormalPriority + nsISupportsPriority::PRIORITY_LOWEST;
|
||||
const static int32_t kBestPriority =
|
||||
kNormalPriority + nsISupportsPriority::PRIORITY_HIGHEST;
|
||||
nsresult OnWriteSegment(char* buf, uint32_t count,
|
||||
uint32_t* countWritten) override;
|
||||
|
||||
Http2Stream(nsAHttpTransaction*, Http2Session*, int32_t, uint64_t);
|
||||
|
||||
uint32_t StreamID() { return mStreamID; }
|
||||
nsresult CheckPushCache();
|
||||
Http2PushedStream* PushSource() { return mPushSource; }
|
||||
bool IsReadingFromPushStream();
|
||||
void ClearPushSource();
|
||||
|
||||
stateType HTTPState() { return mState; }
|
||||
void SetHTTPState(stateType val) { mState = val; }
|
||||
|
||||
[[nodiscard]] virtual nsresult ReadSegments(nsAHttpSegmentReader*, uint32_t,
|
||||
uint32_t*);
|
||||
[[nodiscard]] virtual nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
|
||||
uint32_t*);
|
||||
virtual bool DeferCleanup(nsresult status);
|
||||
|
||||
// The consumer stream is the synthetic pull stream hooked up to this stream
|
||||
// http2PushedStream overrides it
|
||||
virtual Http2Stream* GetConsumerStream() { return nullptr; };
|
||||
|
||||
const nsCString& Origin() const { return mOrigin; }
|
||||
const nsCString& Host() const { return mHeaderHost; }
|
||||
const nsCString& Path() const { return mHeaderPath; }
|
||||
|
||||
bool RequestBlockedOnRead() {
|
||||
return static_cast<bool>(mRequestBlockedOnRead);
|
||||
}
|
||||
|
||||
bool HasRegisteredID() { return mStreamID != 0; }
|
||||
|
||||
nsAHttpTransaction* Transaction() { return mTransaction; }
|
||||
virtual nsIRequestContext* RequestContext() {
|
||||
return mTransaction ? mTransaction->RequestContext() : nullptr;
|
||||
}
|
||||
|
||||
void Close(nsresult reason);
|
||||
void SetResponseIsComplete();
|
||||
|
||||
void SetRecvdFin(bool aStatus);
|
||||
bool RecvdFin() { return mRecvdFin; }
|
||||
|
||||
void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
|
||||
bool RecvdData() { return mReceivedData; }
|
||||
|
||||
void SetSentFin(bool aStatus);
|
||||
bool SentFin() { return mSentFin; }
|
||||
|
||||
void SetRecvdReset(bool aStatus);
|
||||
bool RecvdReset() { return mRecvdReset; }
|
||||
|
||||
void SetSentReset(bool aStatus);
|
||||
bool SentReset() { return mSentReset; }
|
||||
|
||||
void SetQueued(bool aStatus) { mQueued = aStatus ? 1 : 0; }
|
||||
bool Queued() { return mQueued; }
|
||||
|
||||
void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; }
|
||||
bool CountAsActive() { return mCountAsActive; }
|
||||
|
||||
void SetAllHeadersReceived();
|
||||
void UnsetAllHeadersReceived() { mAllHeadersReceived = 0; }
|
||||
bool AllHeadersReceived() { return mAllHeadersReceived; }
|
||||
|
||||
void UpdateTransportSendEvents(uint32_t count);
|
||||
void UpdateTransportReadEvents(uint32_t count);
|
||||
|
||||
// NS_ERROR_ABORT terminates stream, other failure terminates session
|
||||
[[nodiscard]] nsresult ConvertResponseHeaders(Http2Decompressor*, nsACString&,
|
||||
nsACString&, int32_t&);
|
||||
[[nodiscard]] nsresult ConvertPushHeaders(Http2Decompressor*, nsACString&,
|
||||
nsACString&);
|
||||
[[nodiscard]] nsresult ConvertResponseTrailers(Http2Decompressor*,
|
||||
nsACString&);
|
||||
|
||||
bool AllowFlowControlledWrite();
|
||||
void UpdateServerReceiveWindow(int32_t delta);
|
||||
int64_t ServerReceiveWindow() { return mServerReceiveWindow; }
|
||||
|
||||
void DecrementClientReceiveWindow(uint32_t delta) {
|
||||
mClientReceiveWindow -= delta;
|
||||
mLocalUnacked += delta;
|
||||
}
|
||||
|
||||
void IncrementClientReceiveWindow(uint32_t delta) {
|
||||
mClientReceiveWindow += delta;
|
||||
mLocalUnacked -= delta;
|
||||
}
|
||||
|
||||
uint64_t LocalUnAcked();
|
||||
int64_t ClientReceiveWindow() { return mClientReceiveWindow; }
|
||||
|
||||
bool BlockedOnRwin() { return mBlockedOnRwin; }
|
||||
|
||||
uint32_t Priority() { return mPriority; }
|
||||
uint32_t PriorityDependency() { return mPriorityDependency; }
|
||||
uint8_t PriorityWeight() { return mPriorityWeight; }
|
||||
void SetPriority(uint32_t);
|
||||
void SetPriorityDependency(uint32_t, uint32_t);
|
||||
void UpdatePriorityDependency();
|
||||
|
||||
uint64_t TransactionTabId() { return mTransactionTabId; }
|
||||
|
||||
// A pull stream has an implicit sink, a pushed stream has a sink
|
||||
// once it is matched to a pull stream.
|
||||
virtual bool HasSink() { return true; }
|
||||
|
||||
// This is a no-op on pull streams. Pushed streams override this.
|
||||
virtual void SetPushComplete(){};
|
||||
|
||||
already_AddRefed<Http2Session> Session();
|
||||
|
||||
[[nodiscard]] static nsresult MakeOriginURL(const nsACString& origin,
|
||||
nsCOMPtr<nsIURI>& url);
|
||||
|
||||
[[nodiscard]] static nsresult MakeOriginURL(const nsACString& scheme,
|
||||
const nsACString& origin,
|
||||
nsCOMPtr<nsIURI>& url);
|
||||
|
||||
// Mirrors nsAHttpTransaction
|
||||
bool Do0RTT();
|
||||
nsresult Finish0RTT(bool aRestart, bool aAlpnChanged);
|
||||
|
||||
nsresult GetOriginAttributes(mozilla::OriginAttributes* oa);
|
||||
|
||||
virtual void TopBrowsingContextIdChanged(uint64_t id);
|
||||
void TopBrowsingContextIdChangedInternal(
|
||||
uint64_t id); // For use by pushed streams only
|
||||
|
||||
protected:
|
||||
virtual ~Http2Stream();
|
||||
static void CreatePushHashKey(
|
||||
const nsCString& scheme, const nsCString& hostHeader,
|
||||
const mozilla::OriginAttributes& originAttributes, uint64_t serial,
|
||||
const nsACString& pathInfo, nsCString& outOrigin, nsCString& outKey);
|
||||
|
||||
// These internal states track request generation
|
||||
enum upstreamStateType {
|
||||
GENERATING_HEADERS,
|
||||
GENERATING_BODY,
|
||||
SENDING_BODY,
|
||||
SENDING_FIN_STREAM,
|
||||
UPSTREAM_COMPLETE
|
||||
};
|
||||
|
||||
uint32_t mStreamID;
|
||||
|
||||
// The session that this stream is a subset of
|
||||
nsWeakPtr mSession;
|
||||
|
||||
// These are temporary state variables to hold the argument to
|
||||
// Read/WriteSegments so it can be accessed by On(read/write)segment
|
||||
// further up the stack.
|
||||
RefPtr<nsAHttpSegmentReader> mSegmentReader;
|
||||
nsAHttpSegmentWriter* mSegmentWriter;
|
||||
|
||||
nsCString mOrigin;
|
||||
nsCString mHeaderHost;
|
||||
nsCString mHeaderScheme;
|
||||
nsCString mHeaderPath;
|
||||
|
||||
// Each stream goes from generating_headers to upstream_complete, perhaps
|
||||
// looping on multiple instances of generating_body and
|
||||
// sending_body for each frame in the upload.
|
||||
enum upstreamStateType mUpstreamState;
|
||||
|
||||
// The HTTP/2 state for the stream from section 5.1
|
||||
enum stateType mState;
|
||||
|
||||
// Flag is set when all http request headers have been read ID is not stable
|
||||
uint32_t mRequestHeadersDone : 1;
|
||||
|
||||
// Flag is set when ID is stable and concurrency limits are met
|
||||
uint32_t mOpenGenerated : 1;
|
||||
|
||||
// Flag is set when all http response headers have been read
|
||||
uint32_t mAllHeadersReceived : 1;
|
||||
|
||||
// Flag is set when stream is queued inside the session due to
|
||||
// concurrency limits being exceeded
|
||||
uint32_t mQueued : 1;
|
||||
|
||||
void ChangeState(enum upstreamStateType);
|
||||
|
||||
virtual void AdjustInitialWindow();
|
||||
[[nodiscard]] nsresult TransmitFrame(const char*, uint32_t*,
|
||||
bool forceCommitment);
|
||||
|
||||
// The underlying socket transport object is needed to propogate some events
|
||||
nsISocketTransport* mSocketTransport;
|
||||
|
||||
uint8_t mPriorityWeight = 0; // h2 weight
|
||||
uint32_t mPriorityDependency = 0; // h2 stream id this one depends on
|
||||
uint64_t mCurrentTopBrowsingContextId;
|
||||
uint64_t mTransactionTabId;
|
||||
~Http2Stream();
|
||||
|
||||
private:
|
||||
friend class mozilla::DefaultDelete<Http2Stream>;
|
||||
|
||||
[[nodiscard]] nsresult ParseHttpRequestHeaders(const char*, uint32_t,
|
||||
uint32_t*);
|
||||
[[nodiscard]] nsresult GenerateOpen();
|
||||
|
||||
void AdjustPushedPriority();
|
||||
void GenerateDataFrameHeader(uint32_t, bool);
|
||||
|
||||
[[nodiscard]] nsresult BufferInput(uint32_t, uint32_t*);
|
||||
|
||||
// The underlying HTTP transaction. This pointer is used as the key
|
||||
// in the Http2Session mStreamTransactionHash so it is important to
|
||||
// keep a reference to it as long as this stream is a member of that hash.
|
||||
// (i.e. don't change it or release it after it is set in the ctor).
|
||||
RefPtr<nsAHttpTransaction> mTransaction;
|
||||
|
||||
// The quanta upstream data frames are chopped into
|
||||
uint32_t mChunkSize;
|
||||
|
||||
// Flag is set when the HTTP processor has more data to send
|
||||
// but has blocked in doing so.
|
||||
uint32_t mRequestBlockedOnRead : 1;
|
||||
|
||||
// Flag is set after the response frame bearing the fin bit has
|
||||
// been processed. (i.e. after the server has closed).
|
||||
uint32_t mRecvdFin : 1;
|
||||
|
||||
// Flag is set after 1st DATA frame has been passed to stream
|
||||
uint32_t mReceivedData : 1;
|
||||
|
||||
// Flag is set after RST_STREAM has been received for this stream
|
||||
uint32_t mRecvdReset : 1;
|
||||
|
||||
// Flag is set after RST_STREAM has been generated for this stream
|
||||
uint32_t mSentReset : 1;
|
||||
|
||||
// Flag is set when stream is counted towards MAX_CONCURRENT streams in
|
||||
// session
|
||||
uint32_t mCountAsActive : 1;
|
||||
|
||||
// Flag is set when a FIN has been placed on a data or header frame
|
||||
// (i.e after the client has closed)
|
||||
uint32_t mSentFin : 1;
|
||||
|
||||
// Flag is set after the WAITING_FOR Transport event has been generated
|
||||
uint32_t mSentWaitingFor : 1;
|
||||
|
||||
// Flag is set after TCP send autotuning has been disabled
|
||||
uint32_t mSetTCPSocketBuffer : 1;
|
||||
|
||||
// Flag is set when OnWriteSegment is being called directly from stream
|
||||
// instead of transaction
|
||||
uint32_t mBypassInputBuffer : 1;
|
||||
|
||||
// The InlineFrame and associated data is used for composing control
|
||||
// frames and data frame headers.
|
||||
UniquePtr<uint8_t[]> mTxInlineFrame;
|
||||
uint32_t mTxInlineFrameSize;
|
||||
uint32_t mTxInlineFrameUsed;
|
||||
|
||||
// mTxStreamFrameSize tracks the progress of
|
||||
// transmitting a request body data frame. The data frame itself
|
||||
// is never copied into the spdy layer.
|
||||
uint32_t mTxStreamFrameSize;
|
||||
|
||||
// Buffer for request header compression.
|
||||
nsCString mFlatHttpRequestHeaders;
|
||||
|
||||
// Track the content-length of a request body so that we can
|
||||
// place the fin flag on the last data packet instead of waiting
|
||||
// for a stream closed indication. Relying on stream close results
|
||||
// in an extra 0-length runt packet and seems to have some interop
|
||||
// problems with the google servers. Connect does rely on stream
|
||||
// close by setting this to the max value.
|
||||
int64_t mRequestBodyLenRemaining;
|
||||
|
||||
uint32_t mPriority = 0; // geckoish weight
|
||||
|
||||
// mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow
|
||||
// control. *window are signed because the race conditions in asynchronous
|
||||
// SETTINGS messages can force them temporarily negative.
|
||||
|
||||
// mClientReceiveWindow is how much data the server will send without getting
|
||||
// a
|
||||
// window update
|
||||
int64_t mClientReceiveWindow;
|
||||
|
||||
// mServerReceiveWindow is how much data the client is allowed to send without
|
||||
// getting a window update
|
||||
int64_t mServerReceiveWindow;
|
||||
|
||||
// LocalUnacked is the number of bytes received by the client but not
|
||||
// yet reflected in a window update. Sending that update will increment
|
||||
// ClientReceiveWindow
|
||||
uint64_t mLocalUnacked;
|
||||
|
||||
// True when sending is suspended becuase the server receive window is
|
||||
// <= 0
|
||||
bool mBlockedOnRwin;
|
||||
|
||||
// For Progress Events
|
||||
uint64_t mTotalSent;
|
||||
uint64_t mTotalRead;
|
||||
|
||||
// For Http2Push
|
||||
Http2PushedStream* mPushSource;
|
||||
|
||||
// Used to store stream data when the transaction channel cannot keep up
|
||||
// and flow control has not yet kicked in.
|
||||
SimpleBuffer mSimpleBuffer;
|
||||
|
||||
bool mAttempting0RTT;
|
||||
|
||||
/// connect tunnels
|
||||
public:
|
||||
bool IsTunnel() { return mIsTunnel; }
|
||||
// TODO - remove as part of bug 1564120 fix?
|
||||
// This method saves the key the tunnel was registered under, so that when the
|
||||
// associated transaction connection info hash key changes, we still find it
|
||||
// and decrement the correct item in the session's tunnel hash table.
|
||||
nsCString& RegistrationKey();
|
||||
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
void MapStreamToPlainText();
|
||||
bool MapStreamToHttpConnection(const nsACString& aFlat407Headers,
|
||||
int32_t aHttpResponseCode = -1);
|
||||
|
||||
bool mIsTunnel;
|
||||
bool mPlainTextTunnel;
|
||||
nsCString mRegistrationKey;
|
||||
|
||||
/// websockets
|
||||
public:
|
||||
bool IsWebsocket() { return mIsWebsocket; }
|
||||
|
||||
private:
|
||||
bool mIsWebsocket;
|
||||
void AdjustPushedPriority();
|
||||
Http2PushedStream* mPushSource{nullptr};
|
||||
};
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,357 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_Http2StreamBase_h
|
||||
#define mozilla_net_Http2StreamBase_h
|
||||
|
||||
// HTTP/2 - RFC7540
|
||||
// https://www.rfc-editor.org/rfc/rfc7540.txt
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "nsAHttpTransaction.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "SimpleBuffer.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIURI.h"
|
||||
|
||||
class nsISocketTransport;
|
||||
class nsIInputStream;
|
||||
class nsIOutputStream;
|
||||
|
||||
namespace mozilla {
|
||||
class OriginAttributes;
|
||||
}
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
class nsStandardURL;
|
||||
class Http2Session;
|
||||
class Http2Stream;
|
||||
class Http2PushedStream;
|
||||
class Http2Decompressor;
|
||||
|
||||
class Http2StreamBase : public nsAHttpSegmentReader,
|
||||
public nsAHttpSegmentWriter,
|
||||
public SupportsWeakPtr {
|
||||
public:
|
||||
NS_DECL_NSAHTTPSEGMENTREADER
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http2StreamBase, override)
|
||||
|
||||
enum stateType {
|
||||
IDLE,
|
||||
RESERVED_BY_REMOTE,
|
||||
OPEN,
|
||||
CLOSED_BY_LOCAL,
|
||||
CLOSED_BY_REMOTE,
|
||||
CLOSED
|
||||
};
|
||||
|
||||
const static int32_t kNormalPriority = 0x1000;
|
||||
const static int32_t kWorstPriority =
|
||||
kNormalPriority + nsISupportsPriority::PRIORITY_LOWEST;
|
||||
const static int32_t kBestPriority =
|
||||
kNormalPriority + nsISupportsPriority::PRIORITY_HIGHEST;
|
||||
|
||||
Http2StreamBase(nsAHttpTransaction*, Http2Session*, int32_t, uint64_t);
|
||||
|
||||
uint32_t StreamID() { return mStreamID; }
|
||||
|
||||
stateType HTTPState() { return mState; }
|
||||
void SetHTTPState(stateType val) { mState = val; }
|
||||
|
||||
[[nodiscard]] virtual nsresult ReadSegments(nsAHttpSegmentReader*, uint32_t,
|
||||
uint32_t*);
|
||||
[[nodiscard]] virtual nsresult WriteSegments(nsAHttpSegmentWriter*, uint32_t,
|
||||
uint32_t*);
|
||||
virtual bool DeferCleanup(nsresult status);
|
||||
|
||||
const nsCString& Origin() const { return mOrigin; }
|
||||
const nsCString& Host() const { return mHeaderHost; }
|
||||
const nsCString& Path() const { return mHeaderPath; }
|
||||
|
||||
bool RequestBlockedOnRead() {
|
||||
return static_cast<bool>(mRequestBlockedOnRead);
|
||||
}
|
||||
|
||||
bool HasRegisteredID() { return mStreamID != 0; }
|
||||
|
||||
nsAHttpTransaction* Transaction() { return mTransaction; }
|
||||
virtual nsIRequestContext* RequestContext() {
|
||||
return mTransaction ? mTransaction->RequestContext() : nullptr;
|
||||
}
|
||||
|
||||
virtual void Close(nsresult reason);
|
||||
void SetResponseIsComplete();
|
||||
|
||||
void SetRecvdFin(bool aStatus);
|
||||
bool RecvdFin() { return mRecvdFin; }
|
||||
|
||||
void SetRecvdData(bool aStatus) { mReceivedData = aStatus ? 1 : 0; }
|
||||
bool RecvdData() { return mReceivedData; }
|
||||
|
||||
void SetSentFin(bool aStatus);
|
||||
bool SentFin() { return mSentFin; }
|
||||
|
||||
void SetRecvdReset(bool aStatus);
|
||||
bool RecvdReset() { return mRecvdReset; }
|
||||
|
||||
void SetSentReset(bool aStatus);
|
||||
bool SentReset() { return mSentReset; }
|
||||
|
||||
void SetQueued(bool aStatus) { mQueued = aStatus ? 1 : 0; }
|
||||
bool Queued() { return mQueued; }
|
||||
|
||||
void SetCountAsActive(bool aStatus) { mCountAsActive = aStatus ? 1 : 0; }
|
||||
bool CountAsActive() { return mCountAsActive; }
|
||||
|
||||
void SetAllHeadersReceived();
|
||||
void UnsetAllHeadersReceived() { mAllHeadersReceived = 0; }
|
||||
bool AllHeadersReceived() { return mAllHeadersReceived; }
|
||||
|
||||
void UpdateTransportSendEvents(uint32_t count);
|
||||
void UpdateTransportReadEvents(uint32_t count);
|
||||
|
||||
// NS_ERROR_ABORT terminates stream, other failure terminates session
|
||||
[[nodiscard]] nsresult ConvertResponseHeaders(Http2Decompressor*, nsACString&,
|
||||
nsACString&, int32_t&);
|
||||
[[nodiscard]] nsresult ConvertResponseTrailers(Http2Decompressor*,
|
||||
nsACString&);
|
||||
|
||||
bool AllowFlowControlledWrite();
|
||||
void UpdateServerReceiveWindow(int32_t delta);
|
||||
int64_t ServerReceiveWindow() { return mServerReceiveWindow; }
|
||||
|
||||
void DecrementClientReceiveWindow(uint32_t delta) {
|
||||
mClientReceiveWindow -= delta;
|
||||
mLocalUnacked += delta;
|
||||
}
|
||||
|
||||
void IncrementClientReceiveWindow(uint32_t delta) {
|
||||
mClientReceiveWindow += delta;
|
||||
mLocalUnacked -= delta;
|
||||
}
|
||||
|
||||
uint64_t LocalUnAcked();
|
||||
int64_t ClientReceiveWindow() { return mClientReceiveWindow; }
|
||||
|
||||
bool BlockedOnRwin() { return mBlockedOnRwin; }
|
||||
|
||||
uint32_t Priority() { return mPriority; }
|
||||
uint32_t PriorityDependency() { return mPriorityDependency; }
|
||||
uint8_t PriorityWeight() { return mPriorityWeight; }
|
||||
void SetPriority(uint32_t);
|
||||
void SetPriorityDependency(uint32_t, uint32_t);
|
||||
void UpdatePriorityDependency();
|
||||
|
||||
uint64_t TransactionTabId() { return mTransactionTabId; }
|
||||
|
||||
// A pull stream has an implicit sink, a pushed stream has a sink
|
||||
// once it is matched to a pull stream.
|
||||
virtual bool HasSink() { return true; }
|
||||
|
||||
already_AddRefed<Http2Session> Session();
|
||||
|
||||
// Mirrors nsAHttpTransaction
|
||||
bool Do0RTT();
|
||||
nsresult Finish0RTT(bool aRestart, bool aAlpnChanged);
|
||||
|
||||
nsresult GetOriginAttributes(mozilla::OriginAttributes* oa);
|
||||
|
||||
virtual void TopBrowsingContextIdChanged(uint64_t id);
|
||||
void TopBrowsingContextIdChangedInternal(
|
||||
uint64_t id); // For use by pushed streams only
|
||||
|
||||
virtual bool IsTunnel() { return false; }
|
||||
|
||||
virtual uint32_t GetWireStreamId() { return mStreamID; }
|
||||
virtual Http2Stream* GetHttp2Stream() { return nullptr; }
|
||||
virtual Http2PushedStream* GetHttp2PushedStream() { return nullptr; }
|
||||
|
||||
[[nodiscard]] virtual nsresult OnWriteSegment(char*, uint32_t,
|
||||
uint32_t*) override;
|
||||
|
||||
protected:
|
||||
virtual ~Http2StreamBase();
|
||||
|
||||
virtual void HandleResponseHeaders(nsACString& aHeadersOut,
|
||||
int32_t httpResponseCode) {}
|
||||
|
||||
// These internal states track request generation
|
||||
enum upstreamStateType {
|
||||
GENERATING_HEADERS,
|
||||
GENERATING_BODY,
|
||||
SENDING_BODY,
|
||||
SENDING_FIN_STREAM,
|
||||
UPSTREAM_COMPLETE
|
||||
};
|
||||
|
||||
uint32_t mStreamID{0};
|
||||
|
||||
// The session that this stream is a subset of
|
||||
nsWeakPtr mSession;
|
||||
|
||||
// These are temporary state variables to hold the argument to
|
||||
// Read/WriteSegments so it can be accessed by On(read/write)segment
|
||||
// further up the stack.
|
||||
RefPtr<nsAHttpSegmentReader> mSegmentReader;
|
||||
nsAHttpSegmentWriter* mSegmentWriter{nullptr};
|
||||
|
||||
nsCString mOrigin;
|
||||
nsCString mHeaderHost;
|
||||
nsCString mHeaderScheme;
|
||||
nsCString mHeaderPath;
|
||||
|
||||
// Each stream goes from generating_headers to upstream_complete, perhaps
|
||||
// looping on multiple instances of generating_body and
|
||||
// sending_body for each frame in the upload.
|
||||
enum upstreamStateType mUpstreamState { GENERATING_HEADERS };
|
||||
|
||||
// The HTTP/2 state for the stream from section 5.1
|
||||
enum stateType mState { IDLE };
|
||||
|
||||
// Flag is set when all http request headers have been read ID is not stable
|
||||
uint32_t mRequestHeadersDone : 1;
|
||||
|
||||
// Flag is set when ID is stable and concurrency limits are met
|
||||
uint32_t mOpenGenerated : 1;
|
||||
|
||||
// Flag is set when all http response headers have been read
|
||||
uint32_t mAllHeadersReceived : 1;
|
||||
|
||||
// Flag is set when stream is queued inside the session due to
|
||||
// concurrency limits being exceeded
|
||||
uint32_t mQueued : 1;
|
||||
|
||||
void ChangeState(enum upstreamStateType);
|
||||
|
||||
virtual void AdjustInitialWindow();
|
||||
[[nodiscard]] nsresult TransmitFrame(const char*, uint32_t*,
|
||||
bool forceCommitment);
|
||||
|
||||
// The underlying socket transport object is needed to propogate some events
|
||||
nsISocketTransport* mSocketTransport;
|
||||
|
||||
uint8_t mPriorityWeight = 0; // h2 weight
|
||||
uint32_t mPriorityDependency = 0; // h2 stream id this one depends on
|
||||
uint64_t mCurrentTopBrowsingContextId;
|
||||
uint64_t mTransactionTabId{0};
|
||||
|
||||
// The underlying HTTP transaction. This pointer is used as the key
|
||||
// in the Http2Session mStreamTransactionHash so it is important to
|
||||
// keep a reference to it as long as this stream is a member of that hash.
|
||||
// (i.e. don't change it or release it after it is set in the ctor).
|
||||
RefPtr<nsAHttpTransaction> mTransaction;
|
||||
|
||||
// The InlineFrame and associated data is used for composing control
|
||||
// frames and data frame headers.
|
||||
UniquePtr<uint8_t[]> mTxInlineFrame;
|
||||
uint32_t mTxInlineFrameSize{0};
|
||||
uint32_t mTxInlineFrameUsed{0};
|
||||
|
||||
uint32_t mPriority = 0; // geckoish weight
|
||||
|
||||
private:
|
||||
friend class mozilla::DefaultDelete<Http2StreamBase>;
|
||||
|
||||
[[nodiscard]] nsresult ParseHttpRequestHeaders(const char*, uint32_t,
|
||||
uint32_t*);
|
||||
[[nodiscard]] nsresult GenerateOpen();
|
||||
|
||||
void GenerateDataFrameHeader(uint32_t, bool);
|
||||
|
||||
[[nodiscard]] nsresult BufferInput(uint32_t, uint32_t*);
|
||||
|
||||
// The quanta upstream data frames are chopped into
|
||||
uint32_t mChunkSize;
|
||||
|
||||
// Flag is set when the HTTP processor has more data to send
|
||||
// but has blocked in doing so.
|
||||
uint32_t mRequestBlockedOnRead : 1;
|
||||
|
||||
// Flag is set after the response frame bearing the fin bit has
|
||||
// been processed. (i.e. after the server has closed).
|
||||
uint32_t mRecvdFin : 1;
|
||||
|
||||
// Flag is set after 1st DATA frame has been passed to stream
|
||||
uint32_t mReceivedData : 1;
|
||||
|
||||
// Flag is set after RST_STREAM has been received for this stream
|
||||
uint32_t mRecvdReset : 1;
|
||||
|
||||
// Flag is set after RST_STREAM has been generated for this stream
|
||||
uint32_t mSentReset : 1;
|
||||
|
||||
// Flag is set when stream is counted towards MAX_CONCURRENT streams in
|
||||
// session
|
||||
uint32_t mCountAsActive : 1;
|
||||
|
||||
// Flag is set when a FIN has been placed on a data or header frame
|
||||
// (i.e after the client has closed)
|
||||
uint32_t mSentFin : 1;
|
||||
|
||||
// Flag is set after the WAITING_FOR Transport event has been generated
|
||||
uint32_t mSentWaitingFor : 1;
|
||||
|
||||
// Flag is set after TCP send autotuning has been disabled
|
||||
uint32_t mSetTCPSocketBuffer : 1;
|
||||
|
||||
// Flag is set when OnWriteSegment is being called directly from stream
|
||||
// instead of transaction
|
||||
uint32_t mBypassInputBuffer : 1;
|
||||
|
||||
// mTxStreamFrameSize tracks the progress of
|
||||
// transmitting a request body data frame. The data frame itself
|
||||
// is never copied into the spdy layer.
|
||||
uint32_t mTxStreamFrameSize{0};
|
||||
|
||||
// Buffer for request header compression.
|
||||
nsCString mFlatHttpRequestHeaders;
|
||||
|
||||
// Track the content-length of a request body so that we can
|
||||
// place the fin flag on the last data packet instead of waiting
|
||||
// for a stream closed indication. Relying on stream close results
|
||||
// in an extra 0-length runt packet and seems to have some interop
|
||||
// problems with the google servers. Connect does rely on stream
|
||||
// close by setting this to the max value.
|
||||
int64_t mRequestBodyLenRemaining{0};
|
||||
|
||||
// mClientReceiveWindow, mServerReceiveWindow, and mLocalUnacked are for flow
|
||||
// control. *window are signed because the race conditions in asynchronous
|
||||
// SETTINGS messages can force them temporarily negative.
|
||||
|
||||
// mClientReceiveWindow is how much data the server will send without getting
|
||||
// a
|
||||
// window update
|
||||
int64_t mClientReceiveWindow;
|
||||
|
||||
// mServerReceiveWindow is how much data the client is allowed to send without
|
||||
// getting a window update
|
||||
int64_t mServerReceiveWindow;
|
||||
|
||||
// LocalUnacked is the number of bytes received by the client but not
|
||||
// yet reflected in a window update. Sending that update will increment
|
||||
// ClientReceiveWindow
|
||||
uint64_t mLocalUnacked{0};
|
||||
|
||||
// True when sending is suspended becuase the server receive window is
|
||||
// <= 0
|
||||
bool mBlockedOnRwin{false};
|
||||
|
||||
// For Progress Events
|
||||
uint64_t mTotalSent{0};
|
||||
uint64_t mTotalRead{0};
|
||||
|
||||
// Used to store stream data when the transaction channel cannot keep up
|
||||
// and flow control has not yet kicked in.
|
||||
SimpleBuffer mSimpleBuffer;
|
||||
|
||||
bool mAttempting0RTT{false};
|
||||
};
|
||||
|
||||
} // namespace mozilla::net
|
||||
|
||||
#endif // mozilla_net_Http2StreamBase_h
|
|
@ -0,0 +1,92 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// HttpLog.h should generally be included first
|
||||
#include "HttpLog.h"
|
||||
|
||||
// Log on level :5, instead of default :4.
|
||||
#undef LOG
|
||||
#define LOG(args) LOG5(args)
|
||||
#undef LOG_ENABLED
|
||||
#define LOG_ENABLED() LOG5_ENABLED()
|
||||
|
||||
#include "nsHttpHandler.h"
|
||||
#include "Http2StreamTunnel.h"
|
||||
#include "Http2ConnectTransaction.h"
|
||||
#include "nsHttpConnectionInfo.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
Http2StreamTunnel::~Http2StreamTunnel() { ClearTransactionsBlockedOnTunnel(); }
|
||||
|
||||
void Http2StreamTunnel::HandleResponseHeaders(nsACString& aHeadersOut,
|
||||
int32_t httpResponseCode) {
|
||||
LOG3(
|
||||
("Http2StreamTunnel %p Tunnel Response code %d", this, httpResponseCode));
|
||||
// 1xx response is simply skipeed and a final response is expected.
|
||||
// 2xx response needs to be encrypted.
|
||||
if ((httpResponseCode / 100) > 2) {
|
||||
MapStreamToPlainText();
|
||||
}
|
||||
if (MapStreamToHttpConnection(aHeadersOut, httpResponseCode)) {
|
||||
// Process transactions only if we have a final response, i.e., response
|
||||
// code >= 200.
|
||||
ClearTransactionsBlockedOnTunnel();
|
||||
}
|
||||
|
||||
if (!mPlainTextTunnel) {
|
||||
aHeadersOut.Truncate();
|
||||
LOG(
|
||||
("Http2StreamTunnel::ConvertHeaders %p 0x%X headers removed for "
|
||||
"tunnel\n",
|
||||
this, mStreamID));
|
||||
}
|
||||
}
|
||||
|
||||
bool Http2StreamTunnel::MapStreamToHttpConnection(
|
||||
const nsACString& aFlat407Headers, int32_t aHttpResponseCode) {
|
||||
RefPtr<Http2ConnectTransaction> qiTrans(
|
||||
mTransaction->QueryHttp2ConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
|
||||
return qiTrans->MapStreamToHttpConnection(mSocketTransport,
|
||||
mTransaction->ConnectionInfo(),
|
||||
aFlat407Headers, aHttpResponseCode);
|
||||
}
|
||||
|
||||
void Http2StreamTunnel::MapStreamToPlainText() {
|
||||
RefPtr<Http2ConnectTransaction> qiTrans(
|
||||
mTransaction->QueryHttp2ConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
mPlainTextTunnel = true;
|
||||
qiTrans->ForcePlainText();
|
||||
}
|
||||
|
||||
nsCString& Http2StreamTunnel::RegistrationKey() {
|
||||
if (mRegistrationKey.IsEmpty()) {
|
||||
MOZ_ASSERT(Transaction());
|
||||
MOZ_ASSERT(Transaction()->ConnectionInfo());
|
||||
|
||||
mRegistrationKey = Transaction()->ConnectionInfo()->HashKey();
|
||||
}
|
||||
|
||||
return mRegistrationKey;
|
||||
}
|
||||
|
||||
void Http2StreamTunnel::ClearTransactionsBlockedOnTunnel() {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
|
||||
nsresult rv =
|
||||
gHttpHandler->ConnMgr()->ProcessPendingQ(mTransaction->ConnectionInfo());
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG3(
|
||||
("Http2StreamTunnel::ClearTransactionsBlockedOnTunnel %p\n"
|
||||
" ProcessPendingQ failed: %08x\n",
|
||||
this, static_cast<uint32_t>(rv)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_Http2StreamTunnel_h
|
||||
#define mozilla_net_Http2StreamTunnel_h
|
||||
|
||||
#include "Http2StreamBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class Http2StreamTunnel : public Http2StreamBase {
|
||||
public:
|
||||
Http2StreamTunnel(nsAHttpTransaction* httpTransaction, Http2Session* session,
|
||||
int32_t priority, uint64_t bcId)
|
||||
: Http2StreamBase(httpTransaction, session, priority, bcId) {}
|
||||
|
||||
bool IsTunnel() override { return true; }
|
||||
|
||||
nsCString& RegistrationKey();
|
||||
|
||||
protected:
|
||||
~Http2StreamTunnel();
|
||||
void HandleResponseHeaders(nsACString& aHeadersOut,
|
||||
int32_t httpResponseCode) override;
|
||||
|
||||
private:
|
||||
void ClearTransactionsBlockedOnTunnel();
|
||||
bool MapStreamToHttpConnection(const nsACString& aFlat407Headers,
|
||||
int32_t aHttpResponseCode);
|
||||
void MapStreamToPlainText();
|
||||
|
||||
bool mPlainTextTunnel{false};
|
||||
nsCString mRegistrationKey;
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_Http2StreamTunnel_h
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// HttpLog.h should generally be included first
|
||||
#include "HttpLog.h"
|
||||
|
||||
// Log on level :5, instead of default :4.
|
||||
#undef LOG
|
||||
#define LOG(args) LOG5(args)
|
||||
#undef LOG_ENABLED
|
||||
#define LOG_ENABLED() LOG5_ENABLED()
|
||||
|
||||
#include "Http2StreamWebSocket.h"
|
||||
#include "Http2ConnectTransaction.h"
|
||||
|
||||
namespace mozilla::net {
|
||||
// ConvertResponseHeaders is used to convert the response headers
|
||||
// into HTTP/1 format and report some telemetry
|
||||
void Http2StreamWebSocket::HandleResponseHeaders(nsACString& aHeadersOut,
|
||||
int32_t httpResponseCode) {
|
||||
LOG3(("Http2StreamBase %p websocket response code %d", this,
|
||||
httpResponseCode));
|
||||
if (httpResponseCode == 200) {
|
||||
MapStreamToHttpConnection(aHeadersOut);
|
||||
}
|
||||
}
|
||||
|
||||
bool Http2StreamWebSocket::MapStreamToHttpConnection(
|
||||
const nsACString& aFlat407Headers) {
|
||||
RefPtr<Http2ConnectTransaction> qiTrans(
|
||||
mTransaction->QueryHttp2ConnectTransaction());
|
||||
MOZ_ASSERT(qiTrans);
|
||||
|
||||
return qiTrans->MapStreamToHttpConnection(
|
||||
mSocketTransport, mTransaction->ConnectionInfo(), aFlat407Headers, -1);
|
||||
}
|
||||
|
||||
} // namespace mozilla::net
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. *//* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et tw=80 : */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_net_Http2StreamWebSocket_h
|
||||
#define mozilla_net_Http2StreamWebSocket_h
|
||||
|
||||
#include "Http2StreamBase.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
||||
class Http2StreamWebSocket : public Http2StreamBase {
|
||||
public:
|
||||
Http2StreamWebSocket(nsAHttpTransaction* httpTransaction,
|
||||
Http2Session* session, int32_t priority, uint64_t bcId)
|
||||
: Http2StreamBase(httpTransaction, session, priority, bcId) {}
|
||||
|
||||
protected:
|
||||
void HandleResponseHeaders(nsACString& aHeadersOut,
|
||||
int32_t httpResponseCode) override;
|
||||
|
||||
private:
|
||||
bool MapStreamToHttpConnection(const nsACString& aFlat407Headers);
|
||||
};
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_net_Http2StreamWebSocket_h
|
|
@ -109,6 +109,9 @@ UNIFIED_SOURCES += [
|
|||
"Http2Push.cpp",
|
||||
"Http2Session.cpp",
|
||||
"Http2Stream.cpp",
|
||||
"Http2StreamBase.cpp",
|
||||
"Http2StreamTunnel.cpp",
|
||||
"Http2StreamWebSocket.cpp",
|
||||
"Http3Session.cpp",
|
||||
"Http3Stream.cpp",
|
||||
"HttpAuthUtils.cpp",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "PLDHashTable.h"
|
||||
#include "mozilla/DataMutex.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/StaticPrefs_network.h"
|
||||
#include "nsCRT.h"
|
||||
|
@ -21,7 +22,9 @@
|
|||
#include "nsHttpHandler.h"
|
||||
#include "nsICacheEntry.h"
|
||||
#include "nsIRequest.h"
|
||||
#include "nsIStandardURL.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsStandardURL.h"
|
||||
#include "sslerr.h"
|
||||
#include <errno.h>
|
||||
#include <functional>
|
||||
|
@ -1028,5 +1031,55 @@ bool SecurityErrorThatMayNeedRestart(nsresult aReason) {
|
|||
(aReason == psm::GetXPCOMFromNSSError(SSL_ERROR_BAD_MAC_ALERT));
|
||||
}
|
||||
|
||||
nsresult MakeOriginURL(const nsACString& origin, nsCOMPtr<nsIURI>& url) {
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = net_ExtractURLScheme(origin, scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return MakeOriginURL(scheme, origin, url);
|
||||
}
|
||||
|
||||
nsresult MakeOriginURL(const nsACString& scheme, const nsACString& origin,
|
||||
nsCOMPtr<nsIURI>& url) {
|
||||
return NS_MutateURI(new nsStandardURL::Mutator())
|
||||
.Apply(&nsIStandardURLMutator::Init, nsIStandardURL::URLTYPE_AUTHORITY,
|
||||
scheme.EqualsLiteral("http") ? NS_HTTP_DEFAULT_PORT
|
||||
: NS_HTTPS_DEFAULT_PORT,
|
||||
origin, nullptr, nullptr, nullptr)
|
||||
.Finalize(url);
|
||||
}
|
||||
|
||||
void CreatePushHashKey(const nsCString& scheme, const nsCString& hostHeader,
|
||||
const mozilla::OriginAttributes& originAttributes,
|
||||
uint64_t serial, const nsACString& pathInfo,
|
||||
nsCString& outOrigin, nsCString& outKey) {
|
||||
nsCString fullOrigin = scheme;
|
||||
fullOrigin.AppendLiteral("://");
|
||||
fullOrigin.Append(hostHeader);
|
||||
|
||||
nsCOMPtr<nsIURI> origin;
|
||||
nsresult rv = MakeOriginURL(scheme, fullOrigin, origin);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = origin->GetAsciiSpec(outOrigin);
|
||||
outOrigin.Trim("/", false, true, false);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
// Fallback to plain text copy - this may end up behaving poorly
|
||||
outOrigin = fullOrigin;
|
||||
}
|
||||
|
||||
outKey = outOrigin;
|
||||
outKey.AppendLiteral("/[");
|
||||
nsAutoCString suffix;
|
||||
originAttributes.CreateSuffix(suffix);
|
||||
outKey.Append(suffix);
|
||||
outKey.Append(']');
|
||||
outKey.AppendLiteral("/[http2.");
|
||||
outKey.AppendInt(serial);
|
||||
outKey.Append(']');
|
||||
outKey.Append(pathInfo);
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsString.h"
|
||||
#include "nsError.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/OriginAttributes.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/Tuple.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
@ -418,6 +419,18 @@ static inline bool AllowedErrorForHTTPSRRFallback(nsresult aError) {
|
|||
|
||||
bool SecurityErrorThatMayNeedRestart(nsresult aReason);
|
||||
|
||||
[[nodiscard]] nsresult MakeOriginURL(const nsACString& origin,
|
||||
nsCOMPtr<nsIURI>& url);
|
||||
|
||||
[[nodiscard]] nsresult MakeOriginURL(const nsACString& scheme,
|
||||
const nsACString& origin,
|
||||
nsCOMPtr<nsIURI>& url);
|
||||
|
||||
void CreatePushHashKey(const nsCString& scheme, const nsCString& hostHeader,
|
||||
const mozilla::OriginAttributes& originAttributes,
|
||||
uint64_t serial, const nsACString& pathInfo,
|
||||
nsCString& outOrigin, nsCString& outKey);
|
||||
|
||||
} // namespace net
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -273,9 +273,22 @@ FxAccountsWebChannel.prototype = {
|
|||
break;
|
||||
case COMMAND_PAIR_PREFERENCES:
|
||||
if (lazy.pairingEnabled) {
|
||||
browser.loadURI("about:preferences?action=pair#sync", {
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
});
|
||||
let window = browser.ownerGlobal;
|
||||
// We should close the FxA tab after we open our pref page
|
||||
let selectedTab = window.gBrowser.selectedTab;
|
||||
window.switchToTabHavingURI(
|
||||
"about:preferences?action=pair#sync",
|
||||
true,
|
||||
{
|
||||
ignoreQueryString: true,
|
||||
replaceQueryString: true,
|
||||
adoptIntoActiveWindow: true,
|
||||
ignoreFragment: "whenComparing",
|
||||
triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
}
|
||||
);
|
||||
// close the tab
|
||||
window.gBrowser.removeTab(selectedTab);
|
||||
}
|
||||
break;
|
||||
case COMMAND_FIREFOX_VIEW:
|
||||
|
|
|
@ -93,6 +93,12 @@ criteria = "safe-to-deploy"
|
|||
delta = "0.4.0 -> 0.5.0"
|
||||
notes = "The repository for this crate belongs in the Mozilla org."
|
||||
|
||||
[[audits.flagset]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.4.3"
|
||||
notes = "Uses no ambient capabilities, vetted the one instance of unsafe."
|
||||
|
||||
[[audits.getrandom]]
|
||||
who = "Mike Hommey <mh+mozilla@glandium.org>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -268,6 +274,36 @@ criteria = "safe-to-deploy"
|
|||
version = "1.0.2"
|
||||
notes = "Very small crate, just hosts the Void type for easier cross-crate interfacing."
|
||||
|
||||
[[audits.wasm-encoder]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.7.0"
|
||||
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. This has no unsafe code and uses no ambient capabilities."
|
||||
|
||||
[[audits.wasm-encoder]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.7.0 -> 0.14.0"
|
||||
notes = "wasm-encoder has no unsafe code and uses no ambient capabilities."
|
||||
|
||||
[[audits.wasm-smith]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.11.2"
|
||||
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. I've vetted the one instance of unsafe code."
|
||||
|
||||
[[audits.wasmparser]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.87.0"
|
||||
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. I've vetted the one instance of unsafe code."
|
||||
|
||||
[[audits.wast]]
|
||||
who = "Ryan Hunt <rhunt@eqrion.net>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "44.0.0"
|
||||
notes = "Maintained by the Bytecode Alliance, with contributions from Mozilla. wast has no unsafe code and the only ambient capability it uses is to read the full contents of a file that is given to it."
|
||||
|
||||
[[audits.webdriver]]
|
||||
who = "Henrik Skupin <mail@hskupin.info>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -1693,22 +1693,10 @@ criteria = "safe-to-run"
|
|||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wasm-encoder]]
|
||||
version = "0.7.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.wasm-smith]]
|
||||
version = "0.8.0"
|
||||
criteria = "safe-to-run"
|
||||
|
||||
[[exemptions.wasmparser]]
|
||||
version = "0.78.2"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.wast]]
|
||||
version = "41.0.0"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
[[exemptions.webrtc-sdp]]
|
||||
version = "0.3.9"
|
||||
criteria = "safe-to-deploy"
|
||||
|
|
|
@ -325,6 +325,16 @@ merge-automation:
|
|||
from-branch: 'central'
|
||||
to-repo: 'https://hg.mozilla.org/releases/mozilla-beta'
|
||||
to-branch: 'beta'
|
||||
early-to-late-beta:
|
||||
fetch-version-from: "browser/config/version.txt"
|
||||
version-files: []
|
||||
replacements:
|
||||
- - build/defines.sh
|
||||
- EARLY_BETA_OR_EARLIER=1
|
||||
- EARLY_BETA_OR_EARLIER=
|
||||
merge-old-head: false
|
||||
to-repo: 'https://hg.mozilla.org/releases/mozilla-beta'
|
||||
to-branch: 'beta'
|
||||
beta-to-release:
|
||||
fetch-version-from: "browser/config/version.txt"
|
||||
version-files:
|
||||
|
|
|
@ -441,7 +441,7 @@ function push_repo {
|
|||
do
|
||||
echo "Removing old request $diff"
|
||||
# There is no 'arc abandon', see bug 1452082
|
||||
echo '{"transactions": [{"type":"abandon", "value": true}], "objectIdentifier": "'"${diff}"'"}' | arc call-conduit differential.revision.edit
|
||||
echo '{"transactions": [{"type":"abandon", "value": true}], "objectIdentifier": "'"${diff}"'"}' | $ARC call-conduit -- differential.revision.edit
|
||||
done
|
||||
|
||||
$ARC diff --verbatim --reviewers "${REVIEWERS}"
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
ABS_WORK_DIR = os.path.join(os.getcwd(), "build")
|
||||
|
||||
config = {
|
||||
"log_name": "beta_to_release",
|
||||
"copy_files": [
|
||||
{
|
||||
"src": "browser/config/version.txt",
|
||||
"dst": "browser/config/version_display.txt",
|
||||
},
|
||||
],
|
||||
"replacements": [
|
||||
# File, from, to
|
||||
],
|
||||
"vcs_share_base": os.path.join(ABS_WORK_DIR, "hg-shared"),
|
||||
# "hg_share_base": None,
|
||||
"from_repo_url": "https://hg.mozilla.org/releases/mozilla-beta",
|
||||
"to_repo_url": "https://hg.mozilla.org/releases/mozilla-release",
|
||||
"base_tag": "FIREFOX_RELEASE_%(major_version)s_BASE",
|
||||
"end_tag": "FIREFOX_RELEASE_%(major_version)s_END",
|
||||
"migration_behavior": "beta_to_release",
|
||||
"require_remove_locales": False,
|
||||
"pull_all_branches": True,
|
||||
"virtualenv_modules": [
|
||||
"requests==2.8.1",
|
||||
],
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
ABS_WORK_DIR = os.path.join(os.getcwd(), "build")
|
||||
|
||||
config = {
|
||||
"log_name": "central_to_beta",
|
||||
"version_files": [
|
||||
{"file": "browser/config/version.txt", "suffix": ""},
|
||||
{"file": "browser/config/version_display.txt", "suffix": "b1"},
|
||||
{"file": "config/milestone.txt", "suffix": ""},
|
||||
],
|
||||
"replacements": [
|
||||
# File, from, to
|
||||
(
|
||||
f,
|
||||
"ac_add_options --with-branding=browser/branding/nightly",
|
||||
"ac_add_options --enable-official-branding",
|
||||
)
|
||||
for f in [
|
||||
"browser/config/mozconfigs/linux32/l10n-mozconfig",
|
||||
"browser/config/mozconfigs/linux64/l10n-mozconfig",
|
||||
"browser/config/mozconfigs/win32/l10n-mozconfig",
|
||||
"browser/config/mozconfigs/win64/l10n-mozconfig",
|
||||
"browser/config/mozconfigs/win64-aarch64/l10n-mozconfig",
|
||||
"browser/config/mozconfigs/macosx64/l10n-mozconfig",
|
||||
]
|
||||
],
|
||||
"vcs_share_base": os.path.join(ABS_WORK_DIR, "hg-shared"),
|
||||
# "hg_share_base": None,
|
||||
"from_repo_url": "https://hg.mozilla.org/mozilla-central",
|
||||
"to_repo_url": "https://hg.mozilla.org/releases/mozilla-beta",
|
||||
"base_tag": "FIREFOX_BETA_%(major_version)s_BASE",
|
||||
"end_tag": "FIREFOX_BETA_%(major_version)s_END",
|
||||
"migration_behavior": "central_to_beta",
|
||||
"virtualenv_modules": [
|
||||
"requests==2.8.1",
|
||||
],
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# This config is for `mach try release` to support beta simulations.
|
||||
|
||||
config = {
|
||||
"replacements": [
|
||||
("build/defines.sh", "EARLY_BETA_OR_EARLIER=1", "EARLY_BETA_OR_EARLIER="),
|
||||
],
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
from __future__ import absolute_import
|
||||
import os
|
||||
|
||||
ABS_WORK_DIR = os.path.join(os.getcwd(), "build")
|
||||
NEW_ESR_REPO = "https://hg.mozilla.org/releases/mozilla-esr68"
|
||||
|
||||
config = {
|
||||
"log_name": "relese_to_esr",
|
||||
"version_files": [
|
||||
{"file": "browser/config/version_display.txt", "suffix": "esr"},
|
||||
],
|
||||
"replacements": [],
|
||||
"vcs_share_base": os.path.join(ABS_WORK_DIR, "hg-shared"),
|
||||
# Pull from ESR repo, since we have already branched it and have landed esr-specific patches on it
|
||||
# We will need to manually merge mozilla-release into before runnning this.
|
||||
"from_repo_url": NEW_ESR_REPO,
|
||||
"to_repo_url": NEW_ESR_REPO,
|
||||
"base_tag": "FIREFOX_ESR_%(major_version)s_BASE",
|
||||
"migration_behavior": "release_to_esr",
|
||||
"require_remove_locales": False,
|
||||
"requires_head_merge": False,
|
||||
"pull_all_branches": False,
|
||||
}
|
|
@ -706,7 +706,10 @@ class Browsertime(Perftest):
|
|||
|
||||
# Double the timeouts on live sites and when running with Fenix
|
||||
if self.config["live_sites"] or self.config["app"] in ("fenix",):
|
||||
output_timeout *= 2
|
||||
# Since output_timeout is None for benchmark tests we should
|
||||
# not perform any operations on it.
|
||||
if output_timeout is not None:
|
||||
output_timeout *= 2
|
||||
proc_timeout *= 2
|
||||
|
||||
proc = self.process_handler(cmd, processOutputLine=_line_handler, env=env)
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
// META: title=IDB-backed composite blobs maintain coherency
|
||||
// META: script=resources/support-promises.js
|
||||
|
||||
// This test file is intended to help validate browser handling of complex blob
|
||||
// scenarios where one or more levels of multipart blobs are used and varying
|
||||
// IPC serialization strategies may be used depending on various complexity
|
||||
// heuristics.
|
||||
//
|
||||
// A variety of approaches of reading the blob's contents are attempted for
|
||||
// completeness:
|
||||
// - fetch of a URL created via URL.createObjectURL
|
||||
// - Note that this is likely to involve multi-process behavior in a way that
|
||||
// the next 2 currently will not unless their Blobs are round-tripped
|
||||
// through a MessagePort.
|
||||
// - FileReader
|
||||
// - Blob.prototype.arrayBuffer()
|
||||
|
||||
function composite_blob_test({ blobCount, blobSize, name }) {
|
||||
for (const mode of ["fetch-blob-url", "file-reader", "direct"]) {
|
||||
promise_test(async testCase => {
|
||||
const key = "the-blobs";
|
||||
let memBlobs = [];
|
||||
for (let iBlob = 0; iBlob < blobCount; iBlob++) {
|
||||
memBlobs.push(new Blob([make_arraybuffer_contents(iBlob, blobSize)]));
|
||||
}
|
||||
|
||||
const db = await createDatabase(testCase, db => {
|
||||
db.createObjectStore("blobs");
|
||||
});
|
||||
|
||||
const write_tx = db.transaction("blobs", "readwrite");
|
||||
let store = write_tx.objectStore("blobs");
|
||||
store.put(memBlobs, key);
|
||||
// Make the blobs eligible for GC which is most realistic and most likely
|
||||
// to cause problems.
|
||||
memBlobs = null;
|
||||
|
||||
await promiseForTransaction(testCase, write_tx);
|
||||
|
||||
const read_tx = db.transaction("blobs");
|
||||
store = read_tx.objectStore("blobs");
|
||||
const read_req = store.get(key);
|
||||
|
||||
await promiseForTransaction(testCase, read_tx);
|
||||
|
||||
const diskBlobs = read_req.result;
|
||||
const compositeBlob = new Blob(diskBlobs);
|
||||
|
||||
if (mode === "fetch-blob-url") {
|
||||
const blobUrl = URL.createObjectURL(compositeBlob);
|
||||
let urlResp = await fetch(blobUrl);
|
||||
let urlFetchArrayBuffer = await urlResp.arrayBuffer();
|
||||
urlResp = null;
|
||||
|
||||
URL.revokeObjectURL(blobUrl);
|
||||
validate_arraybuffer_contents("fetched URL", urlFetchArrayBuffer, blobCount, blobSize);
|
||||
urlFetchArrayBuffer = null;
|
||||
|
||||
} else if (mode === "file-reader") {
|
||||
let reader = new FileReader();
|
||||
let readerPromise = new Promise(resolve => {
|
||||
reader.onload = () => {
|
||||
resolve(reader.result);
|
||||
}
|
||||
})
|
||||
reader.readAsArrayBuffer(compositeBlob);
|
||||
|
||||
let readArrayBuffer = await readerPromise;
|
||||
readerPromise = null;
|
||||
reader = null;
|
||||
|
||||
validate_arraybuffer_contents("FileReader", readArrayBuffer, blobCount, blobSize);
|
||||
readArrayBuffer = null;
|
||||
} else if (mode === "direct") {
|
||||
let directArrayBuffer = await compositeBlob.arrayBuffer();
|
||||
validate_arraybuffer_contents("arrayBuffer", directArrayBuffer, blobCount, blobSize);
|
||||
}
|
||||
}, `Composite Blob Handling: ${name}: ${mode}`);
|
||||
}
|
||||
}
|
||||
|
||||
// Create an ArrayBuffer whose even bytes are the index identifier and whose
|
||||
// odd bytes are a sequence incremented by 3 (wrapping at 256) so that
|
||||
// discontinuities at power-of-2 boundaries are more detectable.
|
||||
function make_arraybuffer_contents(index, size) {
|
||||
const arr = new Uint8Array(size);
|
||||
for (let i = 0, counter = 0; i < size; i += 2, counter = (counter + 3) % 256) {
|
||||
arr[i] = index;
|
||||
arr[i + 1] = counter;
|
||||
}
|
||||
return arr.buffer;
|
||||
}
|
||||
|
||||
function validate_arraybuffer_contents(source, buffer, blobCount, blobSize) {
|
||||
// Accumulate a list of problems we perceive so we can report what seems to
|
||||
// have happened all at once.
|
||||
const problems = [];
|
||||
|
||||
const arr = new Uint8Array(buffer);
|
||||
|
||||
const expectedLength = blobCount * blobSize;
|
||||
const actualCount = arr.length / blobSize;
|
||||
if (arr.length !== expectedLength) {
|
||||
problems.push(`ArrayBuffer only holds ${actualCount} blobs' worth instead of ${blobCount}.`);
|
||||
problems.push(`Actual ArrayBuffer is ${arr.length} bytes but expected ${expectedLength}`);
|
||||
}
|
||||
|
||||
const counterBlobStep = (blobSize / 2 * 3) % 256;
|
||||
let expectedBlob = 0;
|
||||
let blobSeenSoFar = 0;
|
||||
let expectedCounter = 0;
|
||||
let counterDrift = 0;
|
||||
for (let i = 0; i < arr.length; i += 2) {
|
||||
if (arr[i] !== expectedBlob || blobSeenSoFar >= blobSize) {
|
||||
if (blobSeenSoFar !== blobSize) {
|
||||
problems.push(`Truncated blob ${expectedBlob} after ${blobSeenSoFar} bytes.`);
|
||||
} else {
|
||||
expectedBlob++;
|
||||
}
|
||||
if (expectedBlob !== arr[i]) {
|
||||
problems.push(`Expected blob ${expectedBlob} but found ${arr[i]}, compensating.`);
|
||||
expectedBlob = arr[i];
|
||||
}
|
||||
blobSeenSoFar = 0;
|
||||
expectedCounter = (expectedBlob * counterBlobStep) % 256;
|
||||
counterDrift = 0;
|
||||
}
|
||||
|
||||
if (arr[i + 1] !== (expectedCounter + counterDrift) % 256) {
|
||||
const newDrift = expectedCounter - arr[i + 1];
|
||||
problems.push(`In blob ${expectedBlob} at ${blobSeenSoFar + 1} bytes in, counter drift now ${newDrift} was ${counterDrift}`);
|
||||
counterDrift = newDrift;
|
||||
}
|
||||
|
||||
blobSeenSoFar += 2;
|
||||
expectedCounter = (expectedCounter + 3) % 256;
|
||||
}
|
||||
|
||||
if (problems.length) {
|
||||
assert_true(false, `${source} blob payload problem: ${problems.join("\n")}`);
|
||||
} else {
|
||||
assert_true(true, `${source} blob payloads validated.`);
|
||||
}
|
||||
}
|
||||
|
||||
composite_blob_test({
|
||||
blobCount: 16,
|
||||
blobSize: 256 * 1024,
|
||||
name: "Many blobs",
|
||||
});
|
|
@ -0,0 +1 @@
|
|||
{"files":{"Cargo.toml":"5a87209bc98397121d9b710b6eb05559c5f2ddb7884e82fbfc706026a24fac13","LICENSE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","README.md":"391c693969a7cd5e1810d3fc4271f1b69f79ee1a26def1fc9b3f7c5df50920dd","src/lib.rs":"77804ee547d8723e603975d586deaf4fa8a58bf13a8c80d9416eed0298b39462"},"package":"cda653ca797810c02f7ca4b804b40b8b95ae046eb989d356bce17919a8c25499"}
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче