mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge mozilla-central to autoland r=merge a=merge on a CLOSED TREE
This commit is contained in:
commit
b2d2b2678a
@ -29,7 +29,7 @@ run-if = debug || nightly_build # Requires startuprecorder.js, which is only ava
|
||||
[browser_urlbar_keyed_search_reflows.js]
|
||||
skip-if = (os == 'linux') || (os == 'win' && debug) # Disabled on Linux and Windows debug due to perma failures. Bug 1392320.
|
||||
[browser_urlbar_search_reflows.js]
|
||||
skip-if = debug && (os == 'linux' || os == 'win') # Disabled on Linux and Windows debug due to intermittent timeouts. Bug 1414126.
|
||||
skip-if = (debug || ccov) && (os == 'linux' || os == 'win') # Disabled on Linux and Windows debug and ccov due to intermittent timeouts. Bug 1414126, bug 1426611.
|
||||
[browser_windowclose_reflows.js]
|
||||
[browser_windowopen_flicker.js]
|
||||
skip-if = (debug && os == 'win') # Disabled on windows debug for intermittent leaks
|
||||
|
@ -79,8 +79,10 @@ this.TestRunner = {
|
||||
let screenshotPath = FileUtils.getFile("TmpD", subDirs).path;
|
||||
|
||||
const MOZ_UPLOAD_DIR = env.get("MOZ_UPLOAD_DIR");
|
||||
const MOZ_SOURCE_REPO = env.get("MOZ_SOURCE_REPO");
|
||||
if (MOZ_UPLOAD_DIR && !MOZ_SOURCE_REPO.includes("/integration/")) {
|
||||
const GECKO_HEAD_REPOSITORY = env.get("GECKO_HEAD_REPOSITORY");
|
||||
// We don't want to upload images (from MOZ_UPLOAD_DIR) on integration
|
||||
// branches in order to reduce bandwidth/storage.
|
||||
if (MOZ_UPLOAD_DIR && !GECKO_HEAD_REPOSITORY.includes("/integration/")) {
|
||||
screenshotPath = MOZ_UPLOAD_DIR;
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ const DEFAULT_FAVICON_TAB = `data:text/html,<meta%20charset="utf-8"><title>No%20
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Timer.jsm");
|
||||
Cu.import("resource://testing-common/TestUtils.jsm");
|
||||
Cu.import("resource://testing-common/BrowserTestUtils.jsm");
|
||||
|
||||
this.Tabs = {
|
||||
init(libDir) {},
|
||||
@ -112,6 +113,11 @@ this.Tabs = {
|
||||
await new Promise((resolve, reject) => {
|
||||
setTimeout(resolve, 3000);
|
||||
});
|
||||
// Make sure the tabstrip is scrolled all the way to the left.
|
||||
let scrolled = BrowserTestUtils.waitForEvent(browserWindow.gBrowser.tabContainer, "scrollend");
|
||||
browserWindow.gBrowser.tabContainer.arrowScrollbox.scrollByIndex(-100);
|
||||
await scrolled;
|
||||
|
||||
await allTabTitlesDisplayed(browserWindow);
|
||||
},
|
||||
},
|
||||
|
@ -897,7 +897,7 @@ nsScriptSecurityManager::CheckLoadURIFlags(nsIURI *aSourceURI,
|
||||
if (accessAllowed) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else {
|
||||
} else if (targetScheme.EqualsLiteral("chrome")) {
|
||||
// Allow the load only if the chrome package is whitelisted.
|
||||
nsCOMPtr<nsIXULChromeRegistry> reg(
|
||||
do_GetService(NS_CHROMEREGISTRY_CONTRACTID));
|
||||
|
@ -8,10 +8,13 @@
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
AutoTArray<RefPtr<DocGroup>, 2>* DocGroup::sPendingDocGroups = nullptr;
|
||||
|
||||
/* static */ nsresult
|
||||
DocGroup::GetKey(nsIPrincipal* aPrincipal, nsACString& aKey)
|
||||
{
|
||||
@ -81,5 +84,23 @@ DocGroup::GetValidAccessPtr()
|
||||
return mTabGroup->GetValidAccessPtr();
|
||||
}
|
||||
|
||||
void
|
||||
DocGroup::SignalSlotChange(const HTMLSlotElement* aSlot)
|
||||
{
|
||||
if (mSignalSlotList.Contains(aSlot)) {
|
||||
return;
|
||||
}
|
||||
|
||||
mSignalSlotList.AppendElement(const_cast<HTMLSlotElement*>(aSlot));
|
||||
|
||||
if (!sPendingDocGroups) {
|
||||
// Queue a mutation observer compound microtask.
|
||||
nsDOMMutationObserver::QueueMutationObserverMicroTask();
|
||||
sPendingDocGroups = new AutoTArray<RefPtr<DocGroup>, 2>;
|
||||
}
|
||||
|
||||
sPendingDocGroups->AppendElement(this);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "mozilla/dom/TabGroup.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/dom/CustomElementRegistry.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractThread;
|
||||
@ -99,6 +100,23 @@ public:
|
||||
// DocGroup.
|
||||
bool* GetValidAccessPtr();
|
||||
|
||||
// Append aSlot to the list of signal slot list, if it's not in it already
|
||||
// list, and queue a mutation observer microtask.
|
||||
void SignalSlotChange(const mozilla::dom::HTMLSlotElement* aSlot);
|
||||
|
||||
const nsTArray<RefPtr<HTMLSlotElement>>& SignalSlotList() const
|
||||
{
|
||||
return mSignalSlotList;
|
||||
}
|
||||
|
||||
void ClearSignalSlotList()
|
||||
{
|
||||
mSignalSlotList.Clear();
|
||||
}
|
||||
|
||||
// List of DocGroups that has non-empty signal slot list.
|
||||
static AutoTArray<RefPtr<DocGroup>, 2>* sPendingDocGroups;
|
||||
|
||||
private:
|
||||
DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
|
||||
~DocGroup();
|
||||
@ -107,6 +125,7 @@ private:
|
||||
RefPtr<TabGroup> mTabGroup;
|
||||
nsTArray<nsIDocument*> mDocuments;
|
||||
RefPtr<mozilla::dom::CustomElementReactionsStack> mReactionsStack;
|
||||
nsTArray<RefPtr<HTMLSlotElement>> mSignalSlotList;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -3878,7 +3878,7 @@ Element::GetInnerHTML(nsAString& aInnerHTML)
|
||||
}
|
||||
|
||||
void
|
||||
Element::SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError)
|
||||
Element::SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal* aSubjectPrincipal, ErrorResult& aError)
|
||||
{
|
||||
SetInnerHTMLInternal(aInnerHTML, aError);
|
||||
}
|
||||
|
@ -1339,7 +1339,7 @@ public:
|
||||
nsTArray<RefPtr<Animation>>& aAnimations);
|
||||
|
||||
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML);
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal& aSubjectPrincipal, ErrorResult& aError);
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML, nsIPrincipal* aSubjectPrincipal, ErrorResult& aError);
|
||||
void GetOuterHTML(nsAString& aOuterHTML);
|
||||
void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError);
|
||||
void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText,
|
||||
@ -1566,9 +1566,9 @@ public:
|
||||
aError = SetAttr(kNameSpaceID_None, aAttr, aValue, true);
|
||||
}
|
||||
|
||||
void SetAttr(nsAtom* aAttr, const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||
void SetAttr(nsAtom* aAttr, const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError)
|
||||
{
|
||||
aError = SetAttr(kNameSpaceID_None, aAttr, aValue, &aTriggeringPrincipal, true);
|
||||
aError = SetAttr(kNameSpaceID_None, aAttr, aValue, aTriggeringPrincipal, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -134,6 +134,7 @@ ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
return;
|
||||
}
|
||||
|
||||
bool doEnqueueSlotChange = false;
|
||||
if (oldSlot && oldSlot != currentSlot) {
|
||||
// Move assigned nodes from old slot to new slot.
|
||||
const nsTArray<RefPtr<nsINode>>& assignedNodes = oldSlot->AssignedNodes();
|
||||
@ -142,6 +143,12 @@ ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
|
||||
oldSlot->RemoveAssignedNode(assignedNode);
|
||||
currentSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
// Otherwise add appropriate nodes to this slot from the host.
|
||||
@ -152,8 +159,13 @@ ShadowRoot::AddSlot(HTMLSlotElement* aSlot)
|
||||
child->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (child->IsSlotable() && slotName.Equals(name)) {
|
||||
currentSlot->AppendAssignedNode(child);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
currentSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -171,8 +183,13 @@ ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
|
||||
if (currentSlots->Length() == 1) {
|
||||
MOZ_ASSERT(currentSlots->ElementAt(0) == aSlot);
|
||||
mSlotMap.Remove(name);
|
||||
aSlot->ClearAssignedNodes();
|
||||
|
||||
if (aSlot->AssignedNodes().Length() > 0) {
|
||||
aSlot->ClearAssignedNodes();
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
} else {
|
||||
bool doEnqueueSlotChange = false;
|
||||
bool doReplaceSlot = currentSlots->ElementAt(0) == aSlot;
|
||||
currentSlots->RemoveElement(aSlot);
|
||||
HTMLSlotElement* replacementSlot = currentSlots->ElementAt(0);
|
||||
@ -186,6 +203,12 @@ ShadowRoot::RemoveSlot(HTMLSlotElement* aSlot)
|
||||
|
||||
aSlot->RemoveAssignedNode(assignedNode);
|
||||
replacementSlot->AppendAssignedNode(assignedNode);
|
||||
doEnqueueSlotChange = true;
|
||||
}
|
||||
|
||||
if (doEnqueueSlotChange) {
|
||||
aSlot->EnqueueSlotChangeEvent();
|
||||
replacementSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -436,6 +459,12 @@ ShadowRoot::MaybeReassignElement(Element* aElement,
|
||||
const HTMLSlotElement* newSlot = AssignSlotFor(aElement);
|
||||
|
||||
if (oldSlot != newSlot) {
|
||||
if (oldSlot) {
|
||||
oldSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
if (newSlot) {
|
||||
newSlot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -564,11 +593,24 @@ ShadowRoot::ContentInserted(nsIDocument* aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aChild->IsSlotable() || aContainer != GetHost()) {
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AssignSlotFor(aChild);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
if (const HTMLSlotElement* slot = AssignSlotFor(aChild)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@ -584,13 +626,26 @@ ShadowRoot::ContentRemoved(nsIDocument* aDocument,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aChild->IsSlotable() || aContainer != GetHost()) {
|
||||
if (!aChild->IsSlotable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoString slotName;
|
||||
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
UnassignSlotFor(aChild, slotName);
|
||||
if (aContainer && aContainer == GetHost()) {
|
||||
nsAutoString slotName;
|
||||
aChild->GetAttr(kNameSpaceID_None, nsGkAtoms::slot, slotName);
|
||||
if (const HTMLSlotElement* slot = UnassignSlotFor(aChild, slotName)) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// If parent's root is a shadow root, and parent is a slot whose assigned
|
||||
// nodes is the empty list, then run signal a slot change for parent.
|
||||
HTMLSlotElement* slot = HTMLSlotElement::FromContentOrNull(aContainer);
|
||||
if (slot && slot->GetContainingShadow() == this &&
|
||||
slot->AssignedNodes().IsEmpty()) {
|
||||
slot->EnqueueSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
@ -610,6 +611,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/* static */ void
|
||||
nsDOMMutationObserver::QueueMutationObserverMicroTask()
|
||||
{
|
||||
CycleCollectedJSContext* ccjs = CycleCollectedJSContext::Get();
|
||||
if (!ccjs) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MutationObserverMicroTask> momt =
|
||||
new MutationObserverMicroTask();
|
||||
ccjs->DispatchMicroTaskRunnable(momt.forget());
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMutationObserver::HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||
{
|
||||
if (sScheduledMutationObservers ||
|
||||
mozilla::dom::DocGroup::sPendingDocGroups) {
|
||||
HandleMutationsInternal(aAso);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDOMMutationObserver::RescheduleForRun()
|
||||
{
|
||||
@ -887,7 +910,23 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
|
||||
{
|
||||
nsTArray<RefPtr<nsDOMMutationObserver> >* suppressedObservers = nullptr;
|
||||
|
||||
while (sScheduledMutationObservers) {
|
||||
// Let signalList be a copy of unit of related similar-origin browsing
|
||||
// contexts' signal slot list.
|
||||
nsTArray<RefPtr<HTMLSlotElement>> signalList;
|
||||
if (DocGroup::sPendingDocGroups) {
|
||||
for (uint32_t i = 0; i < DocGroup::sPendingDocGroups->Length(); ++i) {
|
||||
DocGroup* docGroup = DocGroup::sPendingDocGroups->ElementAt(i);
|
||||
signalList.AppendElements(docGroup->SignalSlotList());
|
||||
|
||||
// Empty unit of related similar-origin browsing contexts' signal slot
|
||||
// list.
|
||||
docGroup->ClearSignalSlotList();
|
||||
}
|
||||
delete DocGroup::sPendingDocGroups;
|
||||
DocGroup::sPendingDocGroups = nullptr;
|
||||
}
|
||||
|
||||
if (sScheduledMutationObservers) {
|
||||
AutoTArray<RefPtr<nsDOMMutationObserver>, 4>* observers =
|
||||
sScheduledMutationObservers;
|
||||
sScheduledMutationObservers = nullptr;
|
||||
@ -917,6 +956,11 @@ nsDOMMutationObserver::HandleMutationsInternal(AutoSlowOperation& aAso)
|
||||
delete suppressedObservers;
|
||||
suppressedObservers = nullptr;
|
||||
}
|
||||
|
||||
// Fire slotchange event for each slot in signalList.
|
||||
for (uint32_t i = 0; i < signalList.Length(); ++i) {
|
||||
signalList[i]->FireSlotChangeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
nsDOMMutationRecord*
|
||||
|
@ -575,12 +575,9 @@ public:
|
||||
}
|
||||
|
||||
// static methods
|
||||
static void HandleMutations(mozilla::AutoSlowOperation& aAso)
|
||||
{
|
||||
if (sScheduledMutationObservers) {
|
||||
HandleMutationsInternal(aAso);
|
||||
}
|
||||
}
|
||||
static void QueueMutationObserverMicroTask();
|
||||
|
||||
static void HandleMutations(mozilla::AutoSlowOperation& aAso);
|
||||
|
||||
static bool AllScheduledMutationObserversAreSuppressed()
|
||||
{
|
||||
|
@ -1353,10 +1353,10 @@ public:
|
||||
GetTextContentInternal(aTextContent, aError);
|
||||
}
|
||||
void SetTextContent(const nsAString& aTextContent,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aError)
|
||||
{
|
||||
SetTextContentInternal(aTextContent, &aSubjectPrincipal, aError);
|
||||
SetTextContentInternal(aTextContent, aSubjectPrincipal, aError);
|
||||
}
|
||||
void SetTextContent(const nsAString& aTextContent,
|
||||
mozilla::ErrorResult& aError)
|
||||
|
@ -7415,12 +7415,27 @@ class CGCallGenerator(CGThing):
|
||||
self.cgRoot.append(call)
|
||||
|
||||
if needsSubjectPrincipal:
|
||||
getPrincipal = dedent(
|
||||
needsNonSystemPrincipal = (
|
||||
"needsNonSystemSubjectPrincipal" in extendedAttributes)
|
||||
if needsNonSystemPrincipal:
|
||||
checkPrincipal = dedent(
|
||||
"""
|
||||
if (nsContentUtils::IsSystemPrincipal(principal)) {
|
||||
principal = nullptr;
|
||||
}
|
||||
""")
|
||||
else:
|
||||
checkPrincipal = ""
|
||||
|
||||
getPrincipal = fill(
|
||||
"""
|
||||
JSCompartment* compartment = js::GetContextCompartment(cx);
|
||||
MOZ_ASSERT(compartment);
|
||||
JSPrincipals* principals = JS_GetCompartmentPrincipals(compartment);
|
||||
""")
|
||||
nsIPrincipal* principal = nsJSPrincipals::get(principals);
|
||||
${checkPrincipal}
|
||||
""",
|
||||
checkPrincipal=checkPrincipal)
|
||||
|
||||
if descriptor.interface.isExposedInAnyWorker():
|
||||
self.cgRoot.prepend(CGGeneric(fill(
|
||||
@ -7428,18 +7443,25 @@ class CGCallGenerator(CGThing):
|
||||
Maybe<nsIPrincipal*> subjectPrincipal;
|
||||
if (NS_IsMainThread()) {
|
||||
$*{getPrincipal}
|
||||
subjectPrincipal.emplace(nsJSPrincipals::get(principals));
|
||||
subjectPrincipal.emplace(principal);
|
||||
}
|
||||
""",
|
||||
getPrincipal=getPrincipal)))
|
||||
else:
|
||||
if needsNonSystemPrincipal:
|
||||
principalType = "nsIPrincipal*";
|
||||
else:
|
||||
principalType = "NonNull<nsIPrincipal>"
|
||||
|
||||
self.cgRoot.prepend(CGGeneric(fill(
|
||||
"""
|
||||
$*{getPrincipal}
|
||||
// Initializing a nonnull is pretty darn annoying...
|
||||
NonNull<nsIPrincipal> subjectPrincipal;
|
||||
subjectPrincipal = static_cast<nsIPrincipal*>(nsJSPrincipals::get(principals));
|
||||
${principalType} subjectPrincipal;
|
||||
{
|
||||
$*{getPrincipal}
|
||||
subjectPrincipal = principal;
|
||||
}
|
||||
""",
|
||||
principalType=principalType,
|
||||
getPrincipal=getPrincipal)))
|
||||
|
||||
if isFallible or canOOM:
|
||||
@ -14280,8 +14302,18 @@ class CGBindingRoot(CGThing):
|
||||
dictionary = dictionary.parent
|
||||
return False
|
||||
|
||||
def needsNonSystemPrincipal(member):
|
||||
return (
|
||||
member.getExtendedAttribute("NeedsSubjectPrincipal") == ["NonSystem"] or
|
||||
member.getExtendedAttribute("SetterNeedsSubjectPrincipal") == ["NonSystem"] or
|
||||
member.getExtendedAttribute("GetterNeedsSubjectPrincipal") == ["NonSystem"])
|
||||
|
||||
def descriptorNeedsNonSystemPrincipal(d):
|
||||
return any(needsNonSystemPrincipal(m) for m in d.interface.members)
|
||||
|
||||
bindingHeaders["nsContentUtils.h"] = (
|
||||
any(descriptorHasChromeOnly(d) for d in descriptors) or
|
||||
any(descriptorNeedsNonSystemPrincipal(d) for d in descriptors) or
|
||||
any(dictionaryHasChromeOnly(d) for d in dictionaries))
|
||||
hasNonEmptyDictionaries = any(
|
||||
len(dict.members) > 0 for dict in dictionaries)
|
||||
@ -14700,6 +14732,8 @@ class CGNativeMember(ClassMethod):
|
||||
# Cheat and assume self.descriptorProvider is a descriptor
|
||||
if self.descriptorProvider.interface.isExposedInAnyWorker():
|
||||
args.append(Argument("Maybe<nsIPrincipal*>", "aSubjectPrincipal"))
|
||||
elif 'needsNonSystemSubjectPrincipal' in self.extendedAttrs:
|
||||
args.append(Argument("nsIPrincipal*", "aPrincipal"))
|
||||
else:
|
||||
args.append(Argument("nsIPrincipal&", "aPrincipal"))
|
||||
# And the caller type, if desired.
|
||||
|
@ -614,9 +614,16 @@ class Descriptor(DescriptorProvider):
|
||||
attrs.append("canOOM")
|
||||
|
||||
def maybeAppendNeedsSubjectPrincipalToAttrs(attrs, needsSubjectPrincipal):
|
||||
ensureValidNeedsSubjectPrincipalExtendedAttribute(needsSubjectPrincipal)
|
||||
if (needsSubjectPrincipal is not None and
|
||||
needsSubjectPrincipal is not True and
|
||||
needsSubjectPrincipal != ["NonSystem"]):
|
||||
raise TypeError("Unknown value for 'NeedsSubjectPrincipal': %s" %
|
||||
needsSubjectPrincipal[0])
|
||||
|
||||
if needsSubjectPrincipal is not None:
|
||||
attrs.append("needsSubjectPrincipal")
|
||||
if needsSubjectPrincipal == ["NonSystem"]:
|
||||
attrs.append("needsNonSystemSubjectPrincipal")
|
||||
|
||||
name = member.identifier.name
|
||||
throws = self.interface.isJSImplemented() or member.getExtendedAttribute("Throws")
|
||||
|
@ -29,7 +29,7 @@ def generate(output, idlFilename, preprocessorHeader):
|
||||
# Unfortunately, even some of the getters here are fallible
|
||||
# (e.g. on nsComputedDOMStyle).
|
||||
extendedAttrs = ["Throws", "TreatNullAs=EmptyString",
|
||||
"SetterNeedsSubjectPrincipal"]
|
||||
"SetterNeedsSubjectPrincipal=NonSystem"]
|
||||
if pref is not "":
|
||||
extendedAttrs.append('Pref="%s"' % pref)
|
||||
|
||||
|
@ -971,6 +971,9 @@ public:
|
||||
void NeedsCallerTypeMethod(CallerType);
|
||||
bool NeedsCallerTypeAttr(CallerType);
|
||||
void SetNeedsCallerTypeAttr(bool, CallerType);
|
||||
void NeedsNonSystemSubjectPrincipalMethod(nsIPrincipal*);
|
||||
bool NeedsNonSystemSubjectPrincipalAttr(nsIPrincipal*);
|
||||
void SetNeedsNonSystemSubjectPrincipalAttr(bool, nsIPrincipal*);
|
||||
void CeReactionsMethod();
|
||||
void CeReactionsMethodOverload();
|
||||
void CeReactionsMethodOverload(const nsAString&);
|
||||
@ -1466,6 +1469,9 @@ public:
|
||||
void NeedsCallerTypeMethod(CallerType);
|
||||
bool NeedsCallerTypeAttr(CallerType);
|
||||
void SetNeedsCallerTypeAttr(bool, CallerType);
|
||||
void NeedsNonSystemSubjectPrincipalMethod(Maybe<nsIPrincipal*>);
|
||||
bool NeedsNonSystemSubjectPrincipalAttr(Maybe<nsIPrincipal*>);
|
||||
void SetNeedsNonSystemSubjectPrincipalAttr(bool, Maybe<nsIPrincipal*>);
|
||||
};
|
||||
|
||||
class TestHTMLConstructorInterface : public nsGenericHTMLElement
|
||||
|
@ -957,6 +957,8 @@ interface TestInterface {
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
||||
[NeedsSubjectPrincipal=NonSystem] void needsNonSystemSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal=NonSystem] attribute boolean needsNonSystemSubjectPrincipalAttr;
|
||||
[CEReactions] void ceReactionsMethod();
|
||||
[CEReactions] void ceReactionsMethodOverload();
|
||||
[CEReactions] void ceReactionsMethodOverload(DOMString bar);
|
||||
@ -1303,6 +1305,8 @@ interface TestWorkerExposedInterface {
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
||||
[NeedsSubjectPrincipal=NonSystem] void needsNonSystemSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal=NonSystem] attribute boolean needsNonSystemSubjectPrincipalAttr;
|
||||
};
|
||||
|
||||
[HTMLConstructor]
|
||||
|
@ -783,6 +783,8 @@ interface TestExampleInterface {
|
||||
[SetterCanOOM] attribute boolean canOOMSetterAttr;
|
||||
[NeedsSubjectPrincipal] void needsSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsSubjectPrincipal=NonSystem] void needsNonSystemSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal=NonSystem] attribute boolean needsNonSystemSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
||||
[CEReactions] void ceReactionsMethod();
|
||||
@ -833,4 +835,6 @@ interface TestExampleWorkerInterface {
|
||||
[NeedsSubjectPrincipal] attribute boolean needsSubjectPrincipalAttr;
|
||||
[NeedsCallerType] void needsCallerTypeMethod();
|
||||
[NeedsCallerType] attribute boolean needsCallerTypeAttr;
|
||||
[NeedsSubjectPrincipal=NonSystem] void needsNonSystemSubjectPrincipalMethod();
|
||||
[NeedsSubjectPrincipal=NonSystem] attribute boolean needsNonSystemSubjectPrincipalAttr;
|
||||
};
|
||||
|
@ -104,7 +104,7 @@ public:
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ public:
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ public:
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aError);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aError);
|
||||
}
|
||||
@ -158,7 +158,7 @@ public:
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
|
||||
}
|
||||
void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aError)
|
||||
void SetSrcset(const nsAString& aSrcset, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aError)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, aError);
|
||||
}
|
||||
|
@ -718,7 +718,7 @@ public:
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::src, nullptr, aValue);
|
||||
}
|
||||
void SetSrc(const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
|
||||
void SetSrc(const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aValue, aTriggeringPrincipal, aRv);
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::href, nullptr, aValue);
|
||||
}
|
||||
void SetHref(const nsAString& aHref, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
|
||||
void SetHref(const nsAString& aHref, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::href, aHref, aTriggeringPrincipal, aRv);
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ public:
|
||||
|
||||
MediaError* GetError() const;
|
||||
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aRv);
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML)
|
||||
|
||||
void
|
||||
HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
|
||||
nsIPrincipal& aScriptedPrincipal,
|
||||
nsIPrincipal* aScriptedPrincipal,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
|
||||
|
@ -29,7 +29,7 @@ public:
|
||||
|
||||
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aError) override;
|
||||
|
||||
// nsIScriptElement
|
||||
@ -82,15 +82,11 @@ public:
|
||||
SetHTMLBoolAttr(nsGkAtoms::defer, aDefer, aRv);
|
||||
}
|
||||
|
||||
void GetSrc(nsAString& aSrc, nsIPrincipal&)
|
||||
{
|
||||
GetSrc(aSrc);
|
||||
}
|
||||
void GetSrc(nsAString& aSrc)
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, ErrorResult& aRv)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, ErrorResult& aRv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, aRv);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/DocGroup.h"
|
||||
#include "mozilla/dom/HTMLSlotElement.h"
|
||||
#include "mozilla/dom/HTMLSlotElementBinding.h"
|
||||
#include "mozilla/dom/HTMLUnknownElement.h"
|
||||
@ -206,6 +207,26 @@ HTMLSlotElement::ClearAssignedNodes()
|
||||
mAssignedNodes.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::EnqueueSlotChangeEvent() const
|
||||
{
|
||||
DocGroup* docGroup = OwnerDoc()->GetDocGroup();
|
||||
if (!docGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
docGroup->SignalSlotChange(this);
|
||||
}
|
||||
|
||||
void
|
||||
HTMLSlotElement::FireSlotChangeEvent()
|
||||
{
|
||||
nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
|
||||
static_cast<nsIContent*>(this),
|
||||
NS_LITERAL_STRING("slotchange"), true,
|
||||
false);
|
||||
}
|
||||
|
||||
JSObject*
|
||||
HTMLSlotElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
|
@ -64,6 +64,9 @@ public:
|
||||
void RemoveAssignedNode(nsINode* aNode);
|
||||
void ClearAssignedNodes();
|
||||
|
||||
void EnqueueSlotChangeEvent() const;
|
||||
void FireSlotChangeEvent();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLSlotElement();
|
||||
virtual JSObject*
|
||||
|
@ -58,7 +58,7 @@ public:
|
||||
{
|
||||
GetURIAttr(nsGkAtoms::src, nullptr, aSrc);
|
||||
}
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal& aTriggeringPrincipal, mozilla::ErrorResult& rv)
|
||||
void SetSrc(const nsAString& aSrc, nsIPrincipal* aTriggeringPrincipal, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::src, aSrc, aTriggeringPrincipal, rv);
|
||||
}
|
||||
@ -86,7 +86,7 @@ public:
|
||||
{
|
||||
GetHTMLAttr(nsGkAtoms::srcset, aSrcset);
|
||||
}
|
||||
void SetSrcset(const nsAString& aSrcset, nsIPrincipal& aTriggeringPrincipal, mozilla::ErrorResult& rv)
|
||||
void SetSrcset(const nsAString& aSrcset, nsIPrincipal* aTriggeringPrincipal, mozilla::ErrorResult& rv)
|
||||
{
|
||||
SetHTMLAttr(nsGkAtoms::srcset, aSrcset, aTriggeringPrincipal, rv);
|
||||
}
|
||||
|
@ -175,10 +175,10 @@ HTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML)
|
||||
|
||||
void
|
||||
HTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML,
|
||||
nsIPrincipal& aScriptedPrincipal,
|
||||
nsIPrincipal* aScriptedPrincipal,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
SetTextContentInternal(aInnerHTML, &aScriptedPrincipal, aError);
|
||||
SetTextContentInternal(aInnerHTML, aScriptedPrincipal, aError);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML) override;
|
||||
using nsGenericHTMLElement::SetInnerHTML;
|
||||
virtual void SetInnerHTML(const nsAString& aInnerHTML,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
mozilla::ErrorResult& aError) override;
|
||||
virtual void SetTextContentInternal(const nsAString& aTextContent,
|
||||
nsIPrincipal* aSubjectPrincipal,
|
||||
|
@ -813,7 +813,7 @@ protected:
|
||||
{
|
||||
mozilla::dom::Element::SetAttr(aName, aValue, aError);
|
||||
}
|
||||
void SetHTMLAttr(nsAtom* aName, const nsAString& aValue, nsIPrincipal& aTriggeringPrincipal, mozilla::ErrorResult& aError)
|
||||
void SetHTMLAttr(nsAtom* aName, const nsAString& aValue, nsIPrincipal* aTriggeringPrincipal, mozilla::ErrorResult& aError)
|
||||
{
|
||||
mozilla::dom::Element::SetAttr(aName, aValue, aTriggeringPrincipal, aError);
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ ModuleLoadRequest::ModuleLoadRequest(nsIURI* aURI,
|
||||
aParent->mElement,
|
||||
aParent->mValidJSVersion,
|
||||
aParent->mCORSMode,
|
||||
aParent->mIntegrity,
|
||||
SRIMetadata(),
|
||||
aParent->mURI,
|
||||
aParent->mReferrerPolicy),
|
||||
mIsTopLevel(false),
|
||||
|
@ -102,6 +102,10 @@ ModuleScript::SetErrorToRethrow(const JS::Value& aError)
|
||||
MOZ_ASSERT(!aError.isUndefined());
|
||||
MOZ_ASSERT(!HasErrorToRethrow());
|
||||
|
||||
// This is only called after SetModuleRecord() or SetParseError() so we don't
|
||||
// need to call HoldJSObjects() here.
|
||||
MOZ_ASSERT(mModuleRecord || HasParseError());
|
||||
|
||||
mErrorToRethrow = aError;
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind,
|
||||
nsIScriptElement* aElement,
|
||||
ValidJSVersion aValidJSVersion,
|
||||
mozilla::CORSMode aCORSMode,
|
||||
const mozilla::dom::SRIMetadata& aIntegrity,
|
||||
const SRIMetadata& aIntegrity,
|
||||
nsIURI* aReferrer,
|
||||
mozilla::net::ReferrerPolicy aReferrerPolicy)
|
||||
: mKind(aKind)
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
nsIScriptElement* aElement,
|
||||
ValidJSVersion aValidJSVersion,
|
||||
mozilla::CORSMode aCORSMode,
|
||||
const mozilla::dom::SRIMetadata &aIntegrity,
|
||||
const SRIMetadata &aIntegrity,
|
||||
nsIURI* aReferrer,
|
||||
mozilla::net::ReferrerPolicy aReferrerPolicy);
|
||||
|
||||
@ -195,7 +195,7 @@ public:
|
||||
nsAutoCString mURL; // Keep the URI's filename alive during off thread parsing.
|
||||
int32_t mLineNo;
|
||||
const mozilla::CORSMode mCORSMode;
|
||||
const mozilla::dom::SRIMetadata mIntegrity;
|
||||
const SRIMetadata mIntegrity;
|
||||
const nsCOMPtr<nsIURI> mReferrer;
|
||||
const mozilla::net::ReferrerPolicy mReferrerPolicy;
|
||||
|
||||
|
@ -1570,9 +1570,14 @@ ScriptLoader::ProcessScriptElement(nsIScriptElement* aElement)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Inline scripts ignore ther CORS mode and are always CORS_NONE.
|
||||
// Inline classic scripts ignore ther CORS mode and are always CORS_NONE.
|
||||
CORSMode corsMode = CORS_NONE;
|
||||
if (scriptKind == ScriptKind::Module) {
|
||||
corsMode = aElement->GetCORSMode();
|
||||
}
|
||||
|
||||
request = CreateLoadRequest(scriptKind, mDocument->GetDocumentURI(), aElement,
|
||||
validJSVersion, CORS_NONE,
|
||||
validJSVersion, corsMode,
|
||||
SRIMetadata(), // SRI doesn't apply
|
||||
ourRefPolicy);
|
||||
request->mValidJSVersion = validJSVersion;
|
||||
@ -3033,10 +3038,10 @@ ScriptLoader::PrepareLoadedRequest(ScriptLoadRequest* aRequest,
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
|
||||
// If this load was subject to a CORS check; don't flag it with a
|
||||
// separate origin principal, so that it will treat our document's
|
||||
// principal as the origin principal
|
||||
if (aRequest->mCORSMode == CORS_NONE) {
|
||||
// If this load was subject to a CORS check, don't flag it with a separate
|
||||
// origin principal, so that it will treat our document's principal as the
|
||||
// origin principal. Module loads always use CORS.
|
||||
if (!aRequest->IsModuleRequest() && aRequest->mCORSMode == CORS_NONE) {
|
||||
rv = nsContentUtils::GetSecurityManager()->
|
||||
GetChannelResultPrincipal(channel, getter_AddRefs(aRequest->mOriginPrincipal));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -344,7 +344,7 @@ private:
|
||||
nsIScriptElement* aElement,
|
||||
ValidJSVersion aValidJSVersion,
|
||||
mozilla::CORSMode aCORSMode,
|
||||
const mozilla::dom::SRIMetadata& aIntegrity,
|
||||
const SRIMetadata& aIntegrity,
|
||||
mozilla::net::ReferrerPolicy aReferrerPolicy);
|
||||
|
||||
/**
|
||||
|
@ -42,7 +42,7 @@ interface AnonymousContent {
|
||||
* Set the value of an attribute of an element inside this custom anonymous
|
||||
* content.
|
||||
*/
|
||||
[NeedsSubjectPrincipal, Throws]
|
||||
[NeedsSubjectPrincipal=NonSystem, Throws]
|
||||
void setAttributeForElement(DOMString elementId,
|
||||
DOMString attributeName,
|
||||
DOMString value);
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
interface Attr : Node {
|
||||
readonly attribute DOMString localName;
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString value;
|
||||
|
||||
[Constant]
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
interface CSSStyleDeclaration {
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString cssText;
|
||||
|
||||
readonly attribute unsigned long length;
|
||||
@ -20,7 +20,7 @@ interface CSSStyleDeclaration {
|
||||
[Throws]
|
||||
CSSValue? getPropertyCSSValue(DOMString property);
|
||||
DOMString getPropertyPriority(DOMString property);
|
||||
[CEReactions, NeedsSubjectPrincipal, Throws]
|
||||
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
|
||||
void setProperty(DOMString property, [TreatNullAs=EmptyString] DOMString value, [TreatNullAs=EmptyString] optional DOMString priority = "");
|
||||
[CEReactions, Throws]
|
||||
DOMString removeProperty(DOMString property);
|
||||
|
@ -40,9 +40,9 @@ interface Element : Node {
|
||||
DOMString? getAttribute(DOMString name);
|
||||
[Pure]
|
||||
DOMString? getAttributeNS(DOMString? namespace, DOMString localName);
|
||||
[CEReactions, NeedsSubjectPrincipal, Throws]
|
||||
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
|
||||
void setAttribute(DOMString name, DOMString value);
|
||||
[CEReactions, NeedsSubjectPrincipal, Throws]
|
||||
[CEReactions, NeedsSubjectPrincipal=NonSystem, Throws]
|
||||
void setAttributeNS(DOMString? namespace, DOMString name, DOMString value);
|
||||
[CEReactions, Throws]
|
||||
void removeAttribute(DOMString name);
|
||||
@ -230,7 +230,7 @@ partial interface Element {
|
||||
|
||||
// http://domparsing.spec.whatwg.org/#extensions-to-the-element-interface
|
||||
partial interface Element {
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, Pure, SetterThrows, TreatNullAs=EmptyString]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, Pure, SetterThrows, TreatNullAs=EmptyString]
|
||||
attribute DOMString innerHTML;
|
||||
[CEReactions, Pure,SetterThrows,TreatNullAs=EmptyString]
|
||||
attribute DOMString outerHTML;
|
||||
|
@ -17,7 +17,7 @@ interface HTMLFrameElement : HTMLElement {
|
||||
attribute DOMString name;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString scrolling;
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString frameBorder;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
[HTMLConstructor]
|
||||
interface HTMLIFrameElement : HTMLElement {
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows, Pure]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows, Pure]
|
||||
attribute DOMString src;
|
||||
[CEReactions, SetterThrows, Pure]
|
||||
attribute DOMString srcdoc;
|
||||
|
@ -21,9 +21,9 @@ interface nsIStreamListener;
|
||||
interface HTMLImageElement : HTMLElement {
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString alt;
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString srcset;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString? crossOrigin;
|
||||
|
@ -81,7 +81,7 @@ interface HTMLInputElement : HTMLElement {
|
||||
attribute boolean required;
|
||||
[CEReactions, Pure, SetterThrows]
|
||||
attribute unsigned long size;
|
||||
[CEReactions, Pure, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, Pure, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
[CEReactions, Pure, SetterThrows]
|
||||
attribute DOMString step;
|
||||
|
@ -16,7 +16,7 @@
|
||||
interface HTMLLinkElement : HTMLElement {
|
||||
[Pure]
|
||||
attribute boolean disabled;
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows, Pure]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows, Pure]
|
||||
attribute DOMString href;
|
||||
[CEReactions, SetterThrows, Pure]
|
||||
attribute DOMString? crossOrigin;
|
||||
|
@ -17,7 +17,7 @@ interface HTMLMediaElement : HTMLElement {
|
||||
readonly attribute MediaError? error;
|
||||
|
||||
// network state
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
readonly attribute DOMString currentSrc;
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
[HTMLConstructor]
|
||||
interface HTMLScriptElement : HTMLElement {
|
||||
[CEReactions, NeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString type;
|
||||
|
@ -13,14 +13,14 @@
|
||||
|
||||
[HTMLConstructor]
|
||||
interface HTMLSourceElement : HTMLElement {
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString src;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString type;
|
||||
};
|
||||
|
||||
partial interface HTMLSourceElement {
|
||||
[CEReactions, SetterNeedsSubjectPrincipal, SetterThrows]
|
||||
[CEReactions, SetterNeedsSubjectPrincipal=NonSystem, SetterThrows]
|
||||
attribute DOMString srcset;
|
||||
[CEReactions, SetterThrows]
|
||||
attribute DOMString sizes;
|
||||
|
@ -59,7 +59,8 @@ interface Node : EventTarget {
|
||||
|
||||
[CEReactions, SetterThrows, Pure]
|
||||
attribute DOMString? nodeValue;
|
||||
[CEReactions, SetterThrows, GetterCanOOM, SetterNeedsSubjectPrincipal, Pure]
|
||||
[CEReactions, SetterThrows, GetterCanOOM,
|
||||
SetterNeedsSubjectPrincipal=NonSystem, Pure]
|
||||
attribute DOMString? textContent;
|
||||
[CEReactions, Throws]
|
||||
Node insertBefore(Node node, Node? child);
|
||||
|
@ -2457,6 +2457,31 @@ RuntimeService::CreateSharedWorker(const GlobalObject& aGlobal,
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(window);
|
||||
|
||||
// If the window is blocked from accessing storage, do not allow it
|
||||
// to connect to a SharedWorker. This would potentially allow it
|
||||
// to communicate with other windows that do have storage access.
|
||||
// Allow private browsing, however, as we handle that isolation
|
||||
// via the principal.
|
||||
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
|
||||
if (storageAllowed != nsContentUtils::StorageAccess::eAllow &&
|
||||
storageAllowed != nsContentUtils::StorageAccess::ePrivateBrowsing) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
||||
// Assert that the principal private browsing state matches the
|
||||
// StorageAccess value.
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
if (storageAllowed == nsContentUtils::StorageAccess::ePrivateBrowsing) {
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
nsCOMPtr<nsIPrincipal> principal = doc ? doc->NodePrincipal() : nullptr;
|
||||
uint32_t privateBrowsingId = 0;
|
||||
if (principal) {
|
||||
MOZ_ALWAYS_SUCCEEDS(principal->GetPrivateBrowsingId(&privateBrowsingId));
|
||||
}
|
||||
MOZ_DIAGNOSTIC_ASSERT(privateBrowsingId != 0);
|
||||
}
|
||||
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
WorkerLoadInfo loadInfo;
|
||||
|
@ -56,6 +56,7 @@ support-files =
|
||||
rvals_worker.js
|
||||
sharedWorker_console.js
|
||||
sharedWorker_sharedWorker.js
|
||||
sharedWorker_thirdparty_frame.html
|
||||
simpleThread_worker.js
|
||||
suspend_window.html
|
||||
suspend_worker.js
|
||||
@ -172,6 +173,7 @@ support-files =
|
||||
[test_resolveWorker-assignment.html]
|
||||
[test_rvals.html]
|
||||
[test_sharedWorker.html]
|
||||
[test_sharedWorker_thirdparty.html]
|
||||
[test_simpleThread.html]
|
||||
[test_suspend.html]
|
||||
[test_terminate.html]
|
||||
|
16
dom/workers/test/sharedWorker_thirdparty_frame.html
Normal file
16
dom/workers/test/sharedWorker_thirdparty_frame.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE HTML>
|
||||
<script>
|
||||
let params = new URLSearchParams(document.location.search.substring(1));
|
||||
let name = params.get('name');
|
||||
try {
|
||||
let worker = new SharedWorker('sharedWorker_sharedWorker.js',
|
||||
{ name: name });
|
||||
worker.port.addEventListener('message', evt => {
|
||||
parent.postMessage( { name: name, result: 'allowed' }, '*');
|
||||
}, { once: true });
|
||||
worker.port.start();
|
||||
worker.port.postMessage('ping');
|
||||
} catch(e) {
|
||||
parent.postMessage({ name: name, result: 'blocked' }, '*');
|
||||
}
|
||||
</script>
|
60
dom/workers/test/test_sharedWorker_thirdparty.html
Normal file
60
dom/workers/test/test_sharedWorker_thirdparty.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for SharedWorker in 3rd Party Iframes</title>
|
||||
<script src="/tests/SimpleTest/SimpleTest.js"> </script>
|
||||
<script src="/tests/SimpleTest/SpawnTask.js"> </script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script class="testbody">
|
||||
|
||||
function testThirdPartyFrame(name) {
|
||||
return new Promise(resolve => {
|
||||
let frame = document.createElement('iframe');
|
||||
frame.src =
|
||||
'http://example.org/tests/dom/workers/test/sharedWorker_thirdparty_frame.html?name=' + name;
|
||||
document.body.appendChild(frame);
|
||||
window.addEventListener('message', function messageListener(evt) {
|
||||
if (evt.data.name !== name) {
|
||||
return;
|
||||
}
|
||||
frame.remove();
|
||||
window.removeEventListener('message', messageListener);
|
||||
resolve(evt.data.result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const COOKIE_BEHAVIOR_ACCEPT = 0;
|
||||
const COOKIE_BEHAVIOR_REJECTFOREIGN = 1;
|
||||
|
||||
add_task(async function allowed() {
|
||||
await SpecialPowers.pushPrefEnv({ set: [
|
||||
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_ACCEPT]
|
||||
]});
|
||||
let result = await testThirdPartyFrame('allowed');
|
||||
ok(result === 'allowed',
|
||||
'SharedWorker should be allowed when 3rd party iframes can access storage');
|
||||
});
|
||||
|
||||
add_task(async function blocked() {
|
||||
await SpecialPowers.pushPrefEnv({ set: [
|
||||
["network.cookie.cookieBehavior", COOKIE_BEHAVIOR_REJECTFOREIGN]
|
||||
]});
|
||||
let result = await testThirdPartyFrame('blocked');
|
||||
ok(result === 'blocked',
|
||||
'SharedWorker should not be allowed when 3rd party iframes are denied storage');
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -2242,14 +2242,9 @@ MachineState::FromBailout(RegisterDump::GPRArray& regs, RegisterDump::FPUArray&
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalSingle; i++)
|
||||
machine.setRegisterLocation(FloatRegister(i, FloatRegister::Single), (double*)&fbase[i]);
|
||||
#elif defined(JS_CODEGEN_MIPS32)
|
||||
float* fbase = (float*)&fpregs[0];
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalDouble; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Double),
|
||||
&fpregs[i].d);
|
||||
}
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalSingle; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Single),
|
||||
(double*)&fbase[i]);
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Double), &fpregs[i]);
|
||||
machine.setRegisterLocation(FloatRegister::FromIndex(i, FloatRegister::Single), &fpregs[i]);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
for (unsigned i = 0; i < FloatRegisters::TotalPhys; i++) {
|
||||
|
@ -1967,7 +1967,7 @@ MacroAssembler::convertValueToFloatingPoint(ValueOperand value, FloatRegister ou
|
||||
jump(&done);
|
||||
|
||||
bind(&isDouble);
|
||||
FloatRegister tmp = output;
|
||||
FloatRegister tmp = output.asDouble();
|
||||
if (outputType == MIRType::Float32 && hasMultiAlias())
|
||||
tmp = ScratchDoubleReg;
|
||||
|
||||
|
@ -423,6 +423,10 @@ struct FloatRegister
|
||||
return false;
|
||||
}
|
||||
|
||||
FloatRegister asSingle() const { return FloatRegister(code_, FloatRegisters::Single); }
|
||||
FloatRegister asDouble() const { return FloatRegister(code_, FloatRegisters::Double); }
|
||||
FloatRegister asSimd128() const { MOZ_CRASH(); }
|
||||
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
JS_STATIC_ASSERT(sizeof(SetType) == 8);
|
||||
return mozilla::CountTrailingZeroes64(x);
|
||||
|
@ -266,7 +266,7 @@ class FloatRegistersMIPSShared
|
||||
f31,
|
||||
invalid_freg
|
||||
};
|
||||
typedef FPRegisterID Code;
|
||||
typedef uint32_t Code;
|
||||
typedef FPRegisterID Encoding;
|
||||
|
||||
// Content spilled during bailouts.
|
||||
@ -274,7 +274,7 @@ class FloatRegistersMIPSShared
|
||||
double d;
|
||||
};
|
||||
|
||||
static const char* GetName(Code code) {
|
||||
static const char* GetName(Encoding code) {
|
||||
static const char * const Names[] = { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"f8", "f9", "f10", "f11", "f12", "f13",
|
||||
"f14", "f15", "f16", "f17", "f18", "f19",
|
||||
@ -283,9 +283,13 @@ class FloatRegistersMIPSShared
|
||||
return Names[code];
|
||||
}
|
||||
|
||||
static const Code Invalid = invalid_freg;
|
||||
static const Encoding Invalid = invalid_freg;
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
typedef uint32_t SetType;
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
typedef uint64_t SetType;
|
||||
#endif
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@ -298,16 +302,33 @@ class FloatRegisterMIPSShared
|
||||
|
||||
typedef FloatRegistersMIPSShared::SetType SetType;
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
return mozilla::CountPopulation32(x);
|
||||
}
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
return mozilla::CountTrailingZeroes32(x);
|
||||
}
|
||||
static uint32_t LastBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
|
||||
return 31 - mozilla::CountLeadingZeroes32(x);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_MIPS64)
|
||||
static uint32_t SetSize(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
return mozilla::CountPopulation64(x);
|
||||
}
|
||||
static uint32_t FirstBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
return mozilla::CountTrailingZeroes64(x);
|
||||
}
|
||||
static uint32_t LastBit(SetType x) {
|
||||
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
|
||||
return 63 - mozilla::CountLeadingZeroes64(x);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace mips_private {
|
||||
@ -328,12 +349,12 @@ hasUnaliasedDouble() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On MIPS, fn-double aliases both fn-float32 and fn+1-float32, so if you need
|
||||
// to convert a float32 to a double as a temporary, you need a temporary
|
||||
// double register.
|
||||
// MIPS64 doesn't support it and on MIPS32 we don't allocate odd single fp
|
||||
// registers thus not exposing multi aliasing to the jit.
|
||||
// See comments in Arhitecture-mips32.h.
|
||||
inline bool
|
||||
hasMultiAlias() {
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
|
@ -58,6 +58,13 @@ js::jit::SA(uint32_t value)
|
||||
return value << SAShift;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
js::jit::FS(uint32_t value)
|
||||
{
|
||||
MOZ_ASSERT(value < 32);
|
||||
return value << FSShift;
|
||||
}
|
||||
|
||||
Register
|
||||
js::jit::toRS(Instruction& i)
|
||||
{
|
||||
@ -1341,15 +1348,15 @@ AssemblerMIPSShared::as_movd(FloatRegister fd, FloatRegister fs)
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_ctc1(Register rt, FPControl fc)
|
||||
{
|
||||
spew("ctc1 %3s,%3s", rt.name(), FloatRegister(fc).name());
|
||||
return writeInst(InstReg(op_cop1, rs_ctc1, rt, FloatRegister(fc)).encode());
|
||||
spew("ctc1 %3s,%d", rt.name(), fc);
|
||||
return writeInst(InstReg(op_cop1, rs_ctc1, rt, (uint32_t)fc).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
AssemblerMIPSShared::as_cfc1(Register rt, FPControl fc)
|
||||
{
|
||||
spew("cfc1 %3s,%3s", rt.name(), FloatRegister(fc).name());
|
||||
return writeInst(InstReg(op_cop1, rs_cfc1, rt, FloatRegister(fc)).encode());
|
||||
spew("cfc1 %3s,%d", rt.name(), fc);
|
||||
return writeInst(InstReg(op_cop1, rs_cfc1, rt, (uint32_t)fc).encode());
|
||||
}
|
||||
|
||||
BufferOffset
|
||||
|
@ -219,15 +219,14 @@ class InstJump;
|
||||
|
||||
uint32_t RS(Register r);
|
||||
uint32_t RT(Register r);
|
||||
uint32_t RT(uint32_t regCode);
|
||||
uint32_t RT(FloatRegister r);
|
||||
uint32_t RD(Register r);
|
||||
uint32_t RD(FloatRegister r);
|
||||
uint32_t RD(uint32_t regCode);
|
||||
uint32_t RZ(Register r);
|
||||
uint32_t RZ(FloatRegister r);
|
||||
uint32_t SA(uint32_t value);
|
||||
uint32_t SA(FloatRegister r);
|
||||
uint32_t FS(uint32_t value);
|
||||
|
||||
Register toRS (Instruction& i);
|
||||
Register toRT (Instruction& i);
|
||||
@ -1422,6 +1421,9 @@ class InstReg : public Instruction
|
||||
: Instruction(op | code | ff)
|
||||
{ }
|
||||
// for float point
|
||||
InstReg(Opcode op, RSField rs, Register rt, uint32_t fs)
|
||||
: Instruction(op | rs | RT(rt) | FS(fs))
|
||||
{ }
|
||||
InstReg(Opcode op, RSField rs, Register rt, FloatRegister rd)
|
||||
: Instruction(op | rs | RT(rt) | RD(rd))
|
||||
{ }
|
||||
|
@ -28,38 +28,33 @@ const Registers::SetType Registers::CallMask =
|
||||
(1 << Registers::v0) |
|
||||
(1 << Registers::v1); // used for double-size returns
|
||||
|
||||
FloatRegisters::Code
|
||||
FloatRegisters::Encoding
|
||||
FloatRegisters::FromName(const char* name)
|
||||
{
|
||||
for (size_t i = 0; i < Total; i++) {
|
||||
for (size_t i = 0; i < RegisterIdLimit; i++) {
|
||||
if (strcmp(GetName(i), name) == 0)
|
||||
return Code(i);
|
||||
return Encoding(i);
|
||||
}
|
||||
|
||||
return Invalid;
|
||||
}
|
||||
|
||||
FloatRegister
|
||||
FloatRegister::doubleOverlay(unsigned int which) const
|
||||
FloatRegister::doubleOverlay() const
|
||||
{
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (kind_ != Double)
|
||||
return FloatRegister(code_ & ~1, Double);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
if (isSingle())
|
||||
return FloatRegister(code_, Double);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FloatRegister
|
||||
FloatRegister::singleOverlay(unsigned int which) const
|
||||
FloatRegister::singleOverlay() const
|
||||
{
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
if (kind_ == Double) {
|
||||
// Only even registers are double
|
||||
MOZ_ASSERT(code_ % 2 == 0);
|
||||
MOZ_ASSERT(which < 2);
|
||||
return FloatRegister(code_ + which, Single);
|
||||
}
|
||||
MOZ_ASSERT(which == 0);
|
||||
return FloatRegister(code_, Single);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
if (isDouble())
|
||||
return FloatRegister(code_, Single);
|
||||
return *this;
|
||||
}
|
||||
|
||||
FloatRegisterSet
|
||||
@ -67,12 +62,8 @@ FloatRegister::ReduceSetForPush(const FloatRegisterSet& s)
|
||||
{
|
||||
LiveFloatRegisterSet mod;
|
||||
for (FloatRegisterIterator iter(s); iter.more(); ++iter) {
|
||||
if ((*iter).isSingle()) {
|
||||
// Even for single size registers save complete double register.
|
||||
mod.addUnchecked((*iter).doubleOverlay());
|
||||
} else {
|
||||
mod.addUnchecked(*iter);
|
||||
}
|
||||
// Even for single size registers save complete double register.
|
||||
mod.addUnchecked((*iter).doubleOverlay());
|
||||
}
|
||||
return mod.set();
|
||||
}
|
||||
@ -83,18 +74,21 @@ FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s)
|
||||
FloatRegisterSet ss = s.reduceSetForPush();
|
||||
uint64_t bits = ss.bits();
|
||||
// We are only pushing double registers.
|
||||
MOZ_ASSERT((bits & 0xffffffff) == 0);
|
||||
uint32_t ret = mozilla::CountPopulation32(bits >> 32) * sizeof(double);
|
||||
MOZ_ASSERT((bits & 0xFFFF) == 0);
|
||||
uint32_t ret = mozilla::CountPopulation32(bits) * sizeof(double);
|
||||
|
||||
// Additional space needed by MacroAssembler::PushRegsInMask to ensure
|
||||
// correct alignment of double values.
|
||||
if (ret)
|
||||
ret += sizeof(double);
|
||||
|
||||
return ret;
|
||||
}
|
||||
uint32_t
|
||||
FloatRegister::getRegisterDumpOffsetInBytes()
|
||||
{
|
||||
if (isSingle())
|
||||
return id() * sizeof(float);
|
||||
if (isDouble())
|
||||
return id() * sizeof(double);
|
||||
MOZ_CRASH();
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return id() * sizeof(float);
|
||||
}
|
||||
|
||||
} // namespace ion
|
||||
|
@ -19,7 +19,6 @@
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
// Shadow stack space is not required on MIPS.
|
||||
static const uint32_t ShadowStackSpace = 4 * sizeof(uintptr_t);
|
||||
|
||||
// These offsets are specific to nunboxing, and capture offsets into the
|
||||
@ -32,88 +31,66 @@ static const int32_t NUNBOX32_PAYLOAD_OFFSET = 0;
|
||||
// For MIPS this is 2 instructions relative call.
|
||||
static const uint32_t BAILOUT_TABLE_ENTRY_SIZE = 2 * sizeof(void*);
|
||||
|
||||
// MIPS32 can have two types of floating-point coprocessors:
|
||||
// - 32 bit floating-point coprocessor - In this case, there are 32 single
|
||||
// MIPS32 can have two types of floating-point coprocessors modes:
|
||||
// - FR=0 mode/ 32-bit FPRs - Historical default, there are 32 single
|
||||
// precision registers and pairs of even and odd float registers are used as
|
||||
// double precision registers. Example: f0 (double) is composed of
|
||||
// f0 and f1 (single).
|
||||
// - 64 bit floating-point coprocessor - In this case, there are 32 double
|
||||
// precision register which can also be used as single precision registers.
|
||||
// f0 and f1 (single). Loongson3A FPU running in this mode doesn't allow
|
||||
// use of odd registers for single precision arithmetic.
|
||||
// - FR=1 mode/ 64-bit FPRs - In this case, there are 32 double precision register
|
||||
// which can also be used as single precision registers.
|
||||
// More info https://dmz-portal.imgtec.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
|
||||
|
||||
// Currently we enable 16 even single precision registers which can be also can be used
|
||||
// as double precision registers. It enables jit code to run even on Loongson3A.
|
||||
// It does not support FR=1 mode because MacroAssembler threats odd single precision
|
||||
// registers as high parts of even double precision registers.
|
||||
#ifdef __mips_fpr
|
||||
static_assert(__mips_fpr == 32, "MIPS32 jit only supports FR=0 fpu mode.");
|
||||
#endif
|
||||
|
||||
// When using O32 ABI, floating-point coprocessor is 32 bit.
|
||||
// When using N32 ABI, floating-point coprocessor is 64 bit.
|
||||
class FloatRegisters : public FloatRegistersMIPSShared
|
||||
{
|
||||
public:
|
||||
static const char* GetName(uint32_t i) {
|
||||
MOZ_ASSERT(i < Total);
|
||||
return FloatRegistersMIPSShared::GetName(Code(i % 32));
|
||||
MOZ_ASSERT(i < RegisterIdLimit);
|
||||
return FloatRegistersMIPSShared::GetName(Encoding(i % 32));
|
||||
}
|
||||
|
||||
static Code FromName(const char* name);
|
||||
static Encoding FromName(const char* name);
|
||||
|
||||
static const uint32_t Total = 64;
|
||||
static const uint32_t Total = 32;
|
||||
static const uint32_t TotalDouble = 16;
|
||||
static const uint32_t RegisterIdLimit = 32;
|
||||
// Workarounds: On Loongson CPU-s the odd FP registers behave differently
|
||||
// in fp-32 mode than standard MIPS.
|
||||
#if defined(_MIPS_ARCH_LOONGSON3A)
|
||||
static const uint32_t TotalSingle = 16;
|
||||
|
||||
static const uint32_t Allocatable = 28;
|
||||
static const SetType AllSingleMask = 0x55555555ULL;
|
||||
#else
|
||||
static const uint32_t TotalSingle = 32;
|
||||
static const uint32_t Allocatable = 42;
|
||||
static const SetType AllSingleMask = (1ULL << 32) - 1;
|
||||
#endif
|
||||
static const SetType AllSingleMask = (1ULL << TotalSingle) - 1;
|
||||
|
||||
static const SetType AllDoubleMask = ((1ULL << TotalDouble) - 1) << TotalSingle;
|
||||
static const SetType AllMask = AllDoubleMask | AllSingleMask;
|
||||
|
||||
// When saving all registers we only need to do is save double registers.
|
||||
static const uint32_t TotalPhys = 16;
|
||||
static const uint32_t RegisterIdLimit = 32;
|
||||
|
||||
static_assert(sizeof(SetType) * 8 >= Total,
|
||||
"SetType should be large enough to enumerate all registers.");
|
||||
|
||||
static const SetType AllDoubleMask = 0x55555555ULL << 32;
|
||||
static const SetType AllMask = AllDoubleMask | AllSingleMask;
|
||||
|
||||
static const SetType NonVolatileDoubleMask =
|
||||
((1ULL << FloatRegisters::f20) |
|
||||
(1ULL << FloatRegisters::f22) |
|
||||
(1ULL << FloatRegisters::f24) |
|
||||
(1ULL << FloatRegisters::f26) |
|
||||
(1ULL << FloatRegisters::f28) |
|
||||
(1ULL << FloatRegisters::f30)) << 32;
|
||||
|
||||
// f20-single and f21-single alias f20-double ...
|
||||
static const SetType NonVolatileMask =
|
||||
NonVolatileDoubleMask |
|
||||
(1ULL << FloatRegisters::f20) |
|
||||
(1ULL << FloatRegisters::f21) |
|
||||
(1ULL << FloatRegisters::f22) |
|
||||
(1ULL << FloatRegisters::f23) |
|
||||
(1ULL << FloatRegisters::f24) |
|
||||
(1ULL << FloatRegisters::f25) |
|
||||
(1ULL << FloatRegisters::f26) |
|
||||
(1ULL << FloatRegisters::f27) |
|
||||
(1ULL << FloatRegisters::f28) |
|
||||
(1ULL << FloatRegisters::f29) |
|
||||
(1ULL << FloatRegisters::f30) |
|
||||
(1ULL << FloatRegisters::f31);
|
||||
((SetType(1) << (FloatRegisters::f20 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f22 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f24 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f26 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f28 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f30 >> 1))) * ((1 << TotalSingle) + 1);
|
||||
|
||||
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
|
||||
static const SetType VolatileDoubleMask = AllDoubleMask & ~NonVolatileDoubleMask;
|
||||
|
||||
static const SetType WrapperMask = VolatileMask;
|
||||
|
||||
static const SetType NonAllocatableDoubleMask =
|
||||
((1ULL << FloatRegisters::f16) |
|
||||
(1ULL << FloatRegisters::f18)) << 32;
|
||||
// f16-single and f17-single alias f16-double ...
|
||||
static const SetType NonAllocatableMask =
|
||||
NonAllocatableDoubleMask |
|
||||
(1ULL << FloatRegisters::f16) |
|
||||
(1ULL << FloatRegisters::f17) |
|
||||
(1ULL << FloatRegisters::f18) |
|
||||
(1ULL << FloatRegisters::f19);
|
||||
((SetType(1) << (FloatRegisters::f16 >> 1)) |
|
||||
(SetType(1) << (FloatRegisters::f18 >> 1))) * ((1 << TotalSingle) + 1);
|
||||
|
||||
// Registers that can be allocated without being saved, generally.
|
||||
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
|
||||
@ -133,16 +110,16 @@ class FloatRegister : public FloatRegisterMIPSShared
|
||||
typedef Codes::Code Code;
|
||||
typedef Codes::Encoding Encoding;
|
||||
|
||||
uint32_t code_ : 6;
|
||||
Encoding code_ : 6;
|
||||
protected:
|
||||
RegType kind_ : 1;
|
||||
|
||||
public:
|
||||
constexpr FloatRegister(uint32_t code, RegType kind = Double)
|
||||
: code_ (Code(code)), kind_(kind)
|
||||
: code_ (Encoding(code)), kind_(kind)
|
||||
{ }
|
||||
constexpr FloatRegister()
|
||||
: code_(Code(FloatRegisters::invalid_freg)), kind_(Double)
|
||||
: code_(FloatRegisters::invalid_freg), kind_(Double)
|
||||
{ }
|
||||
|
||||
bool operator==(const FloatRegister& other) const {
|
||||
@ -156,52 +133,43 @@ class FloatRegister : public FloatRegisterMIPSShared
|
||||
return code_ == FloatRegisters::invalid_freg;
|
||||
}
|
||||
|
||||
bool isNotOdd() const { return !isInvalid() && ((code_ & 1) == 0); }
|
||||
|
||||
bool isSingle() const { return kind_ == Single; }
|
||||
bool isDouble() const { return kind_ == Double; }
|
||||
|
||||
FloatRegister doubleOverlay(unsigned int which = 0) const;
|
||||
FloatRegister singleOverlay(unsigned int which = 0) const;
|
||||
FloatRegister sintOverlay(unsigned int which = 0) const;
|
||||
FloatRegister uintOverlay(unsigned int which = 0) const;
|
||||
FloatRegister doubleOverlay() const;
|
||||
FloatRegister singleOverlay() const;
|
||||
|
||||
FloatRegister asSingle() const { return singleOverlay(); }
|
||||
FloatRegister asDouble() const { return doubleOverlay(); }
|
||||
FloatRegister asSimd128() const { MOZ_CRASH("NYI"); }
|
||||
|
||||
Code code() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return Code(code_ | (kind_ << 5));
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return Code((code_ >> 1) | (kind_ << 4));
|
||||
}
|
||||
Encoding encoding() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return Encoding(code_);
|
||||
return code_;
|
||||
}
|
||||
uint32_t id() const {
|
||||
MOZ_ASSERT(!isInvalid());
|
||||
return code_;
|
||||
}
|
||||
static FloatRegister FromCode(uint32_t i) {
|
||||
uint32_t code = i & 31;
|
||||
uint32_t kind = i >> 5;
|
||||
return FloatRegister(code, RegType(kind));
|
||||
uint32_t code = i & 15;
|
||||
uint32_t kind = i >> 4;
|
||||
return FloatRegister(Encoding(code << 1), RegType(kind));
|
||||
}
|
||||
// This is similar to FromCode except for double registers on O32.
|
||||
|
||||
static FloatRegister FromIndex(uint32_t index, RegType kind) {
|
||||
#if defined(USES_O32_ABI)
|
||||
// Only even FP registers are avaiable for Loongson on O32.
|
||||
# if defined(_MIPS_ARCH_LOONGSON3A)
|
||||
return FloatRegister(index * 2, kind);
|
||||
# else
|
||||
if (kind == Double)
|
||||
return FloatRegister(index * 2, kind);
|
||||
# endif
|
||||
#endif
|
||||
return FloatRegister(index, kind);
|
||||
MOZ_ASSERT(index < 16);
|
||||
return FloatRegister(Encoding(index << 1), kind);
|
||||
}
|
||||
|
||||
bool volatile_() const {
|
||||
if (isDouble())
|
||||
return !!((1ULL << code_) & FloatRegisters::VolatileMask);
|
||||
return !!((1ULL << (code_ & ~1)) & FloatRegisters::VolatileMask);
|
||||
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
|
||||
}
|
||||
const char* name() const {
|
||||
return FloatRegisters::GetName(code_);
|
||||
@ -210,61 +178,49 @@ class FloatRegister : public FloatRegisterMIPSShared
|
||||
return other.kind_ != kind_ || code_ != other.code_;
|
||||
}
|
||||
bool aliases(const FloatRegister& other) {
|
||||
if (kind_ == other.kind_)
|
||||
return code_ == other.code_;
|
||||
return doubleOverlay() == other.doubleOverlay();
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return code_ == other.code_;
|
||||
}
|
||||
uint32_t numAliased() const {
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
return 3;
|
||||
}
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return 2;
|
||||
}
|
||||
void aliased(uint32_t aliasIdx, FloatRegister* ret) {
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
|
||||
if (aliasIdx == 0) {
|
||||
*ret = *this;
|
||||
return;
|
||||
}
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
MOZ_ASSERT(aliasIdx <= 2);
|
||||
*ret = singleOverlay(aliasIdx - 1);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aliasIdx == 1);
|
||||
*ret = doubleOverlay(aliasIdx - 1);
|
||||
if (isDouble()) {
|
||||
*ret = singleOverlay();
|
||||
} else {
|
||||
*ret = doubleOverlay();
|
||||
}
|
||||
}
|
||||
uint32_t numAlignedAliased() const {
|
||||
if (isDouble()) {
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
return 2;
|
||||
}
|
||||
// f1-float32 has 0 other aligned aliases, 1 total.
|
||||
// f0-float32 has 1 other aligned alias, 2 total.
|
||||
return 2 - (code_ & 1);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return 2;
|
||||
}
|
||||
// | f0-double |
|
||||
// | f0-float32 | f1-float32 |
|
||||
// We only push double registers on MIPS. So, if we've stored f0-double
|
||||
// we also want to f0-float32 is stored there.
|
||||
void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) {
|
||||
MOZ_ASSERT(isDouble());
|
||||
MOZ_ASSERT((code_ & 1) == 0);
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
|
||||
if (aliasIdx == 0) {
|
||||
*ret = *this;
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(aliasIdx == 1);
|
||||
*ret = singleOverlay(aliasIdx - 1);
|
||||
if (isDouble()) {
|
||||
*ret = singleOverlay();
|
||||
} else {
|
||||
*ret = doubleOverlay();
|
||||
}
|
||||
}
|
||||
|
||||
SetType alignedOrDominatedAliasedSet() const {
|
||||
if (isSingle())
|
||||
return SetType(1) << code_;
|
||||
|
||||
MOZ_ASSERT(isDouble());
|
||||
return SetType(0b11) << code_;
|
||||
MOZ_ASSERT(isNotOdd());
|
||||
return (SetType(1) << (code_ >> 1)) * ((1 << FloatRegisters::TotalSingle) + 1);
|
||||
}
|
||||
|
||||
static constexpr RegTypeName DefaultType = RegTypeName::Float64;
|
||||
@ -306,6 +262,21 @@ FloatRegister::LiveAsIndexableSet<RegTypeName::Any>(SetType set)
|
||||
return set;
|
||||
}
|
||||
|
||||
template <> inline FloatRegister::SetType
|
||||
FloatRegister::AllocatableAsIndexableSet<RegTypeName::Float32>(SetType set)
|
||||
{
|
||||
// Single registers are not dominating any smaller registers, thus masking
|
||||
// is enough to convert an allocatable set into a set of register list all
|
||||
// single register available.
|
||||
return set & FloatRegisters::AllSingleMask;
|
||||
}
|
||||
|
||||
template <> inline FloatRegister::SetType
|
||||
FloatRegister::AllocatableAsIndexableSet<RegTypeName::Float64>(SetType set)
|
||||
{
|
||||
return set & FloatRegisters::AllDoubleMask;
|
||||
}
|
||||
|
||||
// In order to handle functions such as int(*)(int, double) where the first
|
||||
// argument is a general purpose register, and the second argument is a floating
|
||||
// point register, we have to store the double content into 2 general purpose
|
||||
|
@ -157,7 +157,9 @@ class Assembler : public AssemblerMIPSShared
|
||||
// precision registers that make one double register.
|
||||
FloatRegister getOddPair(FloatRegister reg) {
|
||||
MOZ_ASSERT(reg.isDouble());
|
||||
return reg.singleOverlay(1);
|
||||
MOZ_ASSERT(reg.id() % 2 == 0);
|
||||
FloatRegister odd(reg.id() | 1, FloatRegister::Single);
|
||||
return odd;
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -826,6 +826,5 @@ CodeGeneratorMIPS::setReturnDoubleRegs(LiveRegisterSet* regs)
|
||||
{
|
||||
MOZ_ASSERT(ReturnFloat32Reg.code_ == ReturnDoubleReg.code_);
|
||||
regs->add(ReturnFloat32Reg);
|
||||
regs->add(ReturnDoubleReg.singleOverlay(1));
|
||||
regs->add(ReturnDoubleReg);
|
||||
}
|
@ -751,7 +751,7 @@ MacroAssemblerMIPS::ma_ss(FloatRegister ft, Address address)
|
||||
void
|
||||
MacroAssemblerMIPS::ma_pop(FloatRegister fs)
|
||||
{
|
||||
ma_ld(fs.doubleOverlay(0), Address(StackPointer, 0));
|
||||
ma_ld(fs.doubleOverlay(), Address(StackPointer, 0));
|
||||
as_addiu(StackPointer, StackPointer, sizeof(double));
|
||||
}
|
||||
|
||||
@ -759,7 +759,7 @@ void
|
||||
MacroAssemblerMIPS::ma_push(FloatRegister fs)
|
||||
{
|
||||
as_addiu(StackPointer, StackPointer, -sizeof(double));
|
||||
ma_sd(fs.doubleOverlay(0), Address(StackPointer, 0));
|
||||
ma_sd(fs.doubleOverlay(), Address(StackPointer, 0));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2110,18 +2110,22 @@ MacroAssembler::PushRegsInMask(LiveRegisterSet set)
|
||||
}
|
||||
MOZ_ASSERT(diffG == 0);
|
||||
|
||||
// Double values have to be aligned. We reserve extra space so that we can
|
||||
// start writing from the first aligned location.
|
||||
// We reserve a whole extra double so that the buffer has even size.
|
||||
ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
|
||||
reserveStack(diffF + sizeof(double));
|
||||
if (diffF > 0) {
|
||||
// Double values have to be aligned. We reserve extra space so that we can
|
||||
// start writing from the first aligned location.
|
||||
// We reserve a whole extra double so that the buffer has even size.
|
||||
ma_and(SecondScratchReg, sp, Imm32(~(ABIStackAlignment - 1)));
|
||||
reserveStack(diffF);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if ((*iter).code() % 2 == 0)
|
||||
as_sd(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
as_sd(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
|
||||
void
|
||||
@ -2132,18 +2136,22 @@ MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
|
||||
const int32_t reservedG = diffG;
|
||||
const int32_t reservedF = diffF;
|
||||
|
||||
// Read the buffer form the first aligned location.
|
||||
ma_addu(SecondScratchReg, sp, Imm32(reservedF + sizeof(double)));
|
||||
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
|
||||
if (reservedF > 0) {
|
||||
// Read the buffer form the first aligned location.
|
||||
ma_addu(SecondScratchReg, sp, Imm32(reservedF));
|
||||
ma_and(SecondScratchReg, SecondScratchReg, Imm32(~(ABIStackAlignment - 1)));
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if (!ignore.has(*iter) && ((*iter).code() % 2 == 0))
|
||||
// Use assembly l.d because we have alligned the stack.
|
||||
as_ld(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
|
||||
LiveFloatRegisterSet fpignore(ignore.fpus().reduceSetForPush());
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
if (!ignore.has(*iter))
|
||||
as_ld(*iter, SecondScratchReg, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
freeStack(reservedF);
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
freeStack(reservedF + sizeof(double));
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
|
||||
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
|
||||
diffG -= sizeof(intptr_t);
|
||||
@ -2155,14 +2163,13 @@ MacroAssembler::PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register)
|
||||
MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register scratch)
|
||||
{
|
||||
FloatRegisterSet fpuSet(set.fpus().reduceSetForPush());
|
||||
unsigned numFpu = fpuSet.size();
|
||||
int32_t diffF = fpuSet.getPushSizeInBytes();
|
||||
int32_t diffF = set.fpus().getPushSizeInBytes();
|
||||
int32_t diffG = set.gprs().size() * sizeof(intptr_t);
|
||||
|
||||
MOZ_ASSERT(dest.offset >= diffG + diffF);
|
||||
MOZ_ASSERT(dest.base == StackPointer);
|
||||
|
||||
for (GeneralRegisterBackwardIterator iter(set.gprs()); iter.more(); ++iter) {
|
||||
diffG -= sizeof(intptr_t);
|
||||
@ -2171,21 +2178,19 @@ MacroAssembler::storeRegsInMask(LiveRegisterSet set, Address dest, Register)
|
||||
}
|
||||
MOZ_ASSERT(diffG == 0);
|
||||
|
||||
for (FloatRegisterBackwardIterator iter(fpuSet); iter.more(); ++iter) {
|
||||
FloatRegister reg = *iter;
|
||||
diffF -= reg.size();
|
||||
numFpu -= 1;
|
||||
dest.offset -= reg.size();
|
||||
if (reg.isDouble())
|
||||
storeDouble(reg, dest);
|
||||
else if (reg.isSingle())
|
||||
storeFloat32(reg, dest);
|
||||
else
|
||||
MOZ_CRASH("Unknown register type.");
|
||||
if (diffF > 0) {
|
||||
|
||||
computeEffectiveAddress(dest, scratch);
|
||||
ma_and(scratch, scratch, Imm32(~(ABIStackAlignment - 1)));
|
||||
|
||||
diffF -= sizeof(double);
|
||||
|
||||
for (FloatRegisterForwardIterator iter(set.fpus().reduceSetForPush()); iter.more(); ++iter) {
|
||||
as_sd(*iter, scratch, -diffF);
|
||||
diffF -= sizeof(double);
|
||||
}
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
MOZ_ASSERT(numFpu == 0);
|
||||
diffF -= diffF % sizeof(uintptr_t);
|
||||
MOZ_ASSERT(diffF == 0);
|
||||
}
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
@ -239,11 +239,7 @@ static const LiveRegisterSet NonVolatileRegs =
|
||||
FloatRegisterSet(FloatRegisters::NonVolatileMask));
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
static const unsigned NonVolatileRegsPushSize = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||
NonVolatileRegs.fpus().getPushSizeInBytes() +
|
||||
sizeof(double);
|
||||
#elif defined(JS_CODEGEN_NONE)
|
||||
#if defined(JS_CODEGEN_NONE)
|
||||
static const unsigned NonVolatileRegsPushSize = 0;
|
||||
#else
|
||||
static const unsigned NonVolatileRegsPushSize = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
|
||||
|
@ -79,10 +79,10 @@ public:
|
||||
} \
|
||||
\
|
||||
void \
|
||||
Set##method_(const nsAString& aValue, nsIPrincipal& aSubjectPrincipal, \
|
||||
Set##method_(const nsAString& aValue, nsIPrincipal* aSubjectPrincipal, \
|
||||
mozilla::ErrorResult& rv) \
|
||||
{ \
|
||||
rv = SetPropertyValue(eCSSProperty_##id_, aValue, &aSubjectPrincipal); \
|
||||
rv = SetPropertyValue(eCSSProperty_##id_, aValue, aSubjectPrincipal); \
|
||||
}
|
||||
|
||||
#define CSS_PROP_LIST_EXCLUDE_INTERNAL
|
||||
|
@ -112,9 +112,9 @@ public:
|
||||
NS_IMETHOD GetParentRule(nsIDOMCSSRule * *aParentRule) override = 0;
|
||||
|
||||
// WebIDL interface for CSSStyleDeclaration
|
||||
void SetCssText(const nsAString& aString, nsIPrincipal& aSubjectPrincipal,
|
||||
void SetCssText(const nsAString& aString, nsIPrincipal* aSubjectPrincipal,
|
||||
mozilla::ErrorResult& rv) {
|
||||
rv = SetCssText(aString, &aSubjectPrincipal);
|
||||
rv = SetCssText(aString, aSubjectPrincipal);
|
||||
}
|
||||
void GetCssText(nsString& aString) {
|
||||
// Cast to nsAString& so we end up calling our virtual
|
||||
@ -141,9 +141,9 @@ public:
|
||||
GetPropertyPriority(aPropName, static_cast<nsAString&>(aPriority));
|
||||
}
|
||||
void SetProperty(const nsAString& aPropName, const nsAString& aValue,
|
||||
const nsAString& aPriority, nsIPrincipal& aSubjectPrincipal,
|
||||
const nsAString& aPriority, nsIPrincipal* aSubjectPrincipal,
|
||||
mozilla::ErrorResult& rv) {
|
||||
rv = SetProperty(aPropName, aValue, aPriority, &aSubjectPrincipal);
|
||||
rv = SetProperty(aPropName, aValue, aPriority, aSubjectPrincipal);
|
||||
}
|
||||
void RemoveProperty(const nsAString& aPropName, nsString& aRetval,
|
||||
mozilla::ErrorResult& rv) {
|
||||
|
@ -4071,7 +4071,9 @@ pref_ReadPrefFromJar(nsZipArchive* aJarReader, const char* aName)
|
||||
URLPreloader::ReadZip(aJarReader, nsDependentCString(aName)));
|
||||
|
||||
Parser parser;
|
||||
parser.Parse(manifest.get(), manifest.Length());
|
||||
if (!parser.Parse(manifest.get(), manifest.Length())) {
|
||||
return NS_ERROR_FILE_CORRUPTED;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -4806,8 +4806,22 @@ pref("network.tcp.keepalive.retry_interval", 1); // seconds
|
||||
pref("network.tcp.keepalive.probe_count", 4);
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
pref("network.tcp.tcp_fastopen_enable", true);
|
||||
#else
|
||||
pref("network.tcp.tcp_fastopen_enable", false);
|
||||
#endif
|
||||
pref("network.tcp.tcp_fastopen_consecutive_failure_limit", 5);
|
||||
// We are trying to detect stalled tcp connections that use TFO and TLS
|
||||
// (bug 1395494).
|
||||
// This is only happening if a connection is idle for more than 10s, but we
|
||||
// will make this a pref. If tcp_fastopen_http_stalls_limit of stalls are
|
||||
// detected the TCP fast open will be disabled.
|
||||
// If tcp_fastopen_http_check_for_stalls_only_if_idle_for is set to 0 the
|
||||
// check will not be performed.
|
||||
pref("network.tcp.tcp_fastopen_http_check_for_stalls_only_if_idle_for", 10);
|
||||
pref("network.tcp.tcp_fastopen_http_stalls_limit", 3);
|
||||
pref("network.tcp.tcp_fastopen_http_stalls_timeout", 20);
|
||||
|
||||
// Whether to disable acceleration for all widgets.
|
||||
pref("layers.acceleration.disabled", false);
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include "nsICacheStorage.h"
|
||||
#include "CacheControlParser.h"
|
||||
#include "LoadContextInfo.h"
|
||||
#include "TCPFastOpenLayer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
@ -119,6 +120,8 @@ Http2Session::Http2Session(nsISocketTransport *aSocketTransport, uint32_t versio
|
||||
, mAttemptingEarlyData(attemptingEarlyData)
|
||||
, mOriginFrameActivated(false)
|
||||
, mTlsHandshakeFinished(false)
|
||||
, mCheckNetworkStallsWithTFO(false)
|
||||
, mLastRequestBytesSentTime(0)
|
||||
{
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
|
||||
@ -269,8 +272,19 @@ Http2Session::ReadTimeoutTick(PRIntervalTime now)
|
||||
LOG3(("Http2Session::ReadTimeoutTick %p delta since last read %ds\n",
|
||||
this, PR_IntervalToSeconds(now - mLastReadEpoch)));
|
||||
|
||||
uint32_t nextTick = UINT32_MAX;
|
||||
if (mCheckNetworkStallsWithTFO && mLastRequestBytesSentTime) {
|
||||
PRIntervalTime initialResponseDelta = now - mLastRequestBytesSentTime;
|
||||
if (initialResponseDelta >= gHttpHandler->FastOpenStallsTimeout()) {
|
||||
gHttpHandler->IncrementFastOpenStallsCounter();
|
||||
mCheckNetworkStallsWithTFO = false;
|
||||
} else {
|
||||
nextTick = PR_IntervalToSeconds(gHttpHandler->FastOpenStallsTimeout()) -
|
||||
PR_IntervalToSeconds(initialResponseDelta);
|
||||
}
|
||||
}
|
||||
if (!mPingThreshold)
|
||||
return UINT32_MAX;
|
||||
return nextTick;
|
||||
|
||||
if ((now - mLastReadEpoch) < mPingThreshold) {
|
||||
// recent activity means ping is not an issue
|
||||
@ -283,8 +297,8 @@ Http2Session::ReadTimeoutTick(PRIntervalTime now)
|
||||
}
|
||||
}
|
||||
|
||||
return PR_IntervalToSeconds(mPingThreshold) -
|
||||
PR_IntervalToSeconds(now - mLastReadEpoch);
|
||||
return std::min(nextTick, PR_IntervalToSeconds(mPingThreshold) -
|
||||
PR_IntervalToSeconds(now - mLastReadEpoch));
|
||||
}
|
||||
|
||||
if (mPingSentEpoch) {
|
||||
@ -373,6 +387,20 @@ Http2Session::RegisterStreamID(Http2Stream *stream, uint32_t aNewID)
|
||||
}
|
||||
|
||||
mStreamIDHash.Put(aNewID, stream);
|
||||
|
||||
// If TCP fast Open has been used and conection was idle for some time
|
||||
// we will be cautious and watch out for bug 1395494.
|
||||
if (!mCheckNetworkStallsWithTFO && mConnection) {
|
||||
RefPtr<nsHttpConnection> conn = mConnection->HttpConnection();
|
||||
if (conn && (conn->GetFastOpenStatus() == TFO_DATA_SENT) &&
|
||||
gHttpHandler->CheckIfConnectionIsStalledOnlyIfIdleForThisAmountOfSeconds() &&
|
||||
IdleTime() >= gHttpHandler->CheckIfConnectionIsStalledOnlyIfIdleForThisAmountOfSeconds()) {
|
||||
// If a connection was using the TCP FastOpen and it was idle for a
|
||||
// long time we should check for stalls like bug 1395494.
|
||||
mCheckNetworkStallsWithTFO = true;
|
||||
mLastRequestBytesSentTime = PR_IntervalNow();
|
||||
}
|
||||
}
|
||||
return aNewID;
|
||||
}
|
||||
|
||||
@ -512,8 +540,10 @@ Http2Session::NetworkRead(nsAHttpSegmentWriter *writer, char *buf,
|
||||
}
|
||||
|
||||
nsresult rv = writer->OnWriteSegment(buf, count, countWritten);
|
||||
if (NS_SUCCEEDED(rv) && *countWritten > 0)
|
||||
if (NS_SUCCEEDED(rv) && *countWritten > 0) {
|
||||
mLastReadEpoch = PR_IntervalNow();
|
||||
mCheckNetworkStallsWithTFO = false;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -563,6 +563,9 @@ private:
|
||||
// We should propagate this events to the first nsHttpTransaction.
|
||||
RefPtr<nsHttpTransaction> mFirstHttpTransaction;
|
||||
bool mTlsHandshakeFinished;
|
||||
|
||||
bool mCheckNetworkStallsWithTFO;
|
||||
PRIntervalTime mLastRequestBytesSentTime;
|
||||
private:
|
||||
/// connect tunnels
|
||||
void DispatchOnTunnel(nsAHttpTransaction *, nsIInterfaceRequestor *);
|
||||
|
@ -90,6 +90,8 @@ nsHttpConnection::nsHttpConnection()
|
||||
, mFastOpenStatus(TFO_NOT_SET)
|
||||
, mForceSendDuringFastOpenPending(false)
|
||||
, mReceivedSocketWouldBlockDuringFastOpen(false)
|
||||
, mCheckNetworkStallsWithTFO(false)
|
||||
, mLastRequestBytesSentTime(0)
|
||||
{
|
||||
LOG(("Creating nsHttpConnection @%p\n", this));
|
||||
|
||||
@ -641,6 +643,18 @@ nsHttpConnection::Activate(nsAHttpTransaction *trans, uint32_t caps, int32_t pri
|
||||
NS_ENSURE_ARG_POINTER(trans);
|
||||
NS_ENSURE_TRUE(!mTransaction, NS_ERROR_IN_PROGRESS);
|
||||
|
||||
// If TCP fast Open has been used and conection was idle for some time
|
||||
// we will be cautious and watch out for bug 1395494.
|
||||
if (mNPNComplete && (mFastOpenStatus == TFO_DATA_SENT) &&
|
||||
gHttpHandler->CheckIfConnectionIsStalledOnlyIfIdleForThisAmountOfSeconds() &&
|
||||
IdleTime() >= gHttpHandler->CheckIfConnectionIsStalledOnlyIfIdleForThisAmountOfSeconds()) {
|
||||
// If a connection was using the TCP FastOpen and it was idle for a
|
||||
// long time we should check for stalls like bug 1395494.
|
||||
mCheckNetworkStallsWithTFO = true;
|
||||
// Also reset last write. We should start measuring a stall time only
|
||||
// after we really write a request to the network.
|
||||
mLastRequestBytesSentTime = 0;
|
||||
}
|
||||
// reset the read timers to wash away any idle time
|
||||
mLastWriteTime = mLastReadTime = PR_IntervalNow();
|
||||
|
||||
@ -1355,6 +1369,19 @@ nsHttpConnection::ReadTimeoutTick(PRIntervalTime now)
|
||||
nextTickAfter = std::max(nextTickAfter, 1U);
|
||||
}
|
||||
|
||||
// Check for the TCP Fast Open related stalls.
|
||||
if (mCheckNetworkStallsWithTFO && mLastRequestBytesSentTime) {
|
||||
PRIntervalTime initialResponseDelta = now - mLastRequestBytesSentTime;
|
||||
if (initialResponseDelta >= gHttpHandler->FastOpenStallsTimeout()) {
|
||||
gHttpHandler->IncrementFastOpenStallsCounter();
|
||||
mCheckNetworkStallsWithTFO = false;
|
||||
} else {
|
||||
uint32_t next = PR_IntervalToSeconds(gHttpHandler->FastOpenStallsTimeout()) -
|
||||
PR_IntervalToSeconds(initialResponseDelta);
|
||||
nextTickAfter = std::min(nextTickAfter, next);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mNPNComplete) {
|
||||
// We can reuse mLastWriteTime here, because it is set when the
|
||||
// connection is activated and only change when a transaction
|
||||
@ -1856,6 +1883,9 @@ nsHttpConnection::OnSocketWritable()
|
||||
mTransaction->OnTransportStatus(mSocketTransport,
|
||||
NS_NET_STATUS_WAITING_FOR,
|
||||
0);
|
||||
if (mCheckNetworkStallsWithTFO) {
|
||||
mLastRequestBytesSentTime = PR_IntervalNow();
|
||||
}
|
||||
|
||||
rv = ResumeRecv(); // start reading
|
||||
}
|
||||
@ -1898,6 +1928,8 @@ nsHttpConnection::OnWriteSegment(char *buf,
|
||||
else
|
||||
mSocketInCondition = NS_OK; // reset condition
|
||||
|
||||
mCheckNetworkStallsWithTFO = false;
|
||||
|
||||
return mSocketInCondition;
|
||||
}
|
||||
|
||||
|
@ -234,6 +234,9 @@ public:
|
||||
bool JoinConnection(const nsACString &hostname, int32_t port);
|
||||
|
||||
void SetFastOpenStatus(uint8_t tfoStatus);
|
||||
uint8_t GetFastOpenStatus() {
|
||||
return mFastOpenStatus;
|
||||
}
|
||||
|
||||
void SetEvent(nsresult aStatus);
|
||||
|
||||
@ -401,6 +404,8 @@ private:
|
||||
|
||||
bool mForceSendDuringFastOpenPending;
|
||||
bool mReceivedSocketWouldBlockDuringFastOpen;
|
||||
bool mCheckNetworkStallsWithTFO;
|
||||
PRIntervalTime mLastRequestBytesSentTime;
|
||||
|
||||
public:
|
||||
void BootstrapTimings(TimingStruct times);
|
||||
|
@ -4584,7 +4584,6 @@ nsHalfOpenSocket::SetFastOpenConnected(nsresult aError, bool aWillRetry)
|
||||
mConnectionNegotiatingFastOpen = nullptr;
|
||||
if (mEnt) {
|
||||
mEnt->mDoNotDestroy = false;
|
||||
MOZ_ASSERT(mEnt->mHalfOpens.Contains(this));
|
||||
} else {
|
||||
MOZ_ASSERT(!mSynTimer);
|
||||
MOZ_ASSERT(!mBackupTransport);
|
||||
|
@ -109,8 +109,11 @@
|
||||
#define SAFE_HINT_HEADER_VALUE "safeHint.enabled"
|
||||
#define SECURITY_PREFIX "security."
|
||||
|
||||
#define TCP_FAST_OPEN_ENABLE "network.tcp.tcp_fastopen_enable"
|
||||
#define TCP_FAST_OPEN_FAILURE_LIMIT "network.tcp.tcp_fastopen_consecutive_failure_limit"
|
||||
#define TCP_FAST_OPEN_ENABLE "network.tcp.tcp_fastopen_enable"
|
||||
#define TCP_FAST_OPEN_FAILURE_LIMIT "network.tcp.tcp_fastopen_consecutive_failure_limit"
|
||||
#define TCP_FAST_OPEN_STALLS_LIMIT "network.tcp.tcp_fastopen_http_stalls_limit"
|
||||
#define TCP_FAST_OPEN_STALLS_IDLE "network.tcp.tcp_fastopen_http_check_for_stalls_only_if_idle_for"
|
||||
#define TCP_FAST_OPEN_STALLS_TIMEOUT "network.tcp.tcp_fastopen_http_stalls_timeout"
|
||||
|
||||
#define UA_PREF(_pref) UA_PREF_PREFIX _pref
|
||||
#define HTTP_PREF(_pref) HTTP_PREF_PREFIX _pref
|
||||
@ -285,6 +288,10 @@ nsHttpHandler::nsHttpHandler()
|
||||
, mUseFastOpen(true)
|
||||
, mFastOpenConsecutiveFailureLimit(5)
|
||||
, mFastOpenConsecutiveFailureCounter(0)
|
||||
, mFastOpenStallsLimit(3)
|
||||
, mFastOpenStallsCounter(0)
|
||||
, mFastOpenStallsIdleTime(10)
|
||||
, mFastOpenStallsTimeout(20)
|
||||
, mActiveTabPriority(true)
|
||||
, mProcessId(0)
|
||||
, mNextChannelId(1)
|
||||
@ -336,7 +343,7 @@ nsHttpHandler::SetFastOpenOSSupport()
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// set min version minus 1.
|
||||
#if XP_MACOSX
|
||||
int min_version[] = {15, 0};
|
||||
int min_version[] = {17, 3};
|
||||
#elif ANDROID
|
||||
int min_version[] = {4, 4};
|
||||
#elif XP_LINUX
|
||||
@ -452,6 +459,9 @@ nsHttpHandler::Init()
|
||||
prefBranch->AddObserver(SECURITY_PREFIX, this, true);
|
||||
prefBranch->AddObserver(TCP_FAST_OPEN_ENABLE, this, true);
|
||||
prefBranch->AddObserver(TCP_FAST_OPEN_FAILURE_LIMIT, this, true);
|
||||
prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_LIMIT, this, true);
|
||||
prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_IDLE, this, true);
|
||||
prefBranch->AddObserver(TCP_FAST_OPEN_STALLS_TIMEOUT, this, true);
|
||||
PrefsChanged(prefBranch, nullptr);
|
||||
}
|
||||
|
||||
@ -736,6 +746,20 @@ nsHttpHandler::IncrementFastOpenConsecutiveFailureCounter()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpHandler::IncrementFastOpenStallsCounter()
|
||||
{
|
||||
LOG(("nsHttpHandler::IncrementFastOpenStallsCounter - failed=%d "
|
||||
"failure_limit=%d", mFastOpenStallsCounter, mFastOpenStallsLimit));
|
||||
if (mFastOpenStallsCounter < mFastOpenStallsLimit) {
|
||||
mFastOpenStallsCounter++;
|
||||
if (mFastOpenStallsCounter == mFastOpenStallsLimit) {
|
||||
LOG(("nsHttpHandler::IncrementFastOpenStallsCounter - "
|
||||
"There are too many stalls involving TFO and TLS."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsHttpHandler::GetStreamConverterService(nsIStreamConverterService **result)
|
||||
{
|
||||
@ -1929,6 +1953,36 @@ nsHttpHandler::PrefsChanged(nsIPrefBranch *prefs, const char *pref)
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_LIMIT)) {
|
||||
rv = prefs->GetIntPref(TCP_FAST_OPEN_STALLS_LIMIT, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (val < 0) {
|
||||
val = 0;
|
||||
}
|
||||
mFastOpenStallsLimit = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_TIMEOUT)) {
|
||||
rv = prefs->GetIntPref(TCP_FAST_OPEN_STALLS_TIMEOUT, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (val < 0) {
|
||||
val = 0;
|
||||
}
|
||||
mFastOpenStallsTimeout = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(TCP_FAST_OPEN_STALLS_IDLE)) {
|
||||
rv = prefs->GetIntPref(TCP_FAST_OPEN_STALLS_IDLE, &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (val < 0) {
|
||||
val = 0;
|
||||
}
|
||||
mFastOpenStallsIdleTime = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (PREF_CHANGED(HTTP_PREF("spdy.hpack-default-buffer"))) {
|
||||
rv = prefs->GetIntPref(HTTP_PREF("spdy.default-hpack-buffer"), &val);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
@ -2275,8 +2329,10 @@ nsHttpHandler::Observe(nsISupports *subject,
|
||||
Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 1);
|
||||
} else if (!mUseFastOpen) {
|
||||
Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 2);
|
||||
} else {
|
||||
} else if (mFastOpenConsecutiveFailureCounter >= mFastOpenConsecutiveFailureLimit) {
|
||||
Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 3);
|
||||
} else {
|
||||
Telemetry::Accumulate(Telemetry::TCP_FAST_OPEN_STATUS, 4);
|
||||
}
|
||||
} else if (!strcmp(topic, "profile-change-net-restore")) {
|
||||
// initialize connection manager
|
||||
|
@ -177,7 +177,8 @@ public:
|
||||
bool UseFastOpen()
|
||||
{
|
||||
return mUseFastOpen && mFastOpenSupported &&
|
||||
mFastOpenConsecutiveFailureCounter < mFastOpenConsecutiveFailureLimit;
|
||||
(mFastOpenStallsCounter < mFastOpenStallsLimit) &&
|
||||
(mFastOpenConsecutiveFailureCounter < mFastOpenConsecutiveFailureLimit);
|
||||
}
|
||||
// If one of tcp connections return PR_NOT_TCP_SOCKET_ERROR while trying
|
||||
// fast open, it means that Fast Open is turned off so we will not try again
|
||||
@ -195,6 +196,14 @@ public:
|
||||
mFastOpenConsecutiveFailureCounter = 0;
|
||||
}
|
||||
|
||||
void IncrementFastOpenStallsCounter();
|
||||
uint32_t CheckIfConnectionIsStalledOnlyIfIdleForThisAmountOfSeconds() {
|
||||
return mFastOpenStallsIdleTime;
|
||||
}
|
||||
uint32_t FastOpenStallsTimeout() {
|
||||
return mFastOpenStallsTimeout;
|
||||
}
|
||||
|
||||
// returns the HTTP framing check level preference, as controlled with
|
||||
// network.http.enforce-framing.http1 and network.http.enforce-framing.soft
|
||||
FrameCheckLevel GetEnforceH1Framing() { return mEnforceH1Framing; }
|
||||
@ -651,6 +660,10 @@ private:
|
||||
Atomic<bool, Relaxed> mFastOpenSupported;
|
||||
uint32_t mFastOpenConsecutiveFailureLimit;
|
||||
uint32_t mFastOpenConsecutiveFailureCounter;
|
||||
uint32_t mFastOpenStallsLimit;
|
||||
uint32_t mFastOpenStallsCounter;
|
||||
uint32_t mFastOpenStallsIdleTime;
|
||||
uint32_t mFastOpenStallsTimeout;
|
||||
|
||||
// If true, the transactions from active tab will be dispatched first.
|
||||
bool mActiveTabPriority;
|
||||
|
@ -1 +1 @@
|
||||
NSPR_4_18_BETA4
|
||||
NSPR_4_18_BETA5
|
||||
|
@ -10,4 +10,3 @@
|
||||
*/
|
||||
|
||||
#error "Do not include this header file."
|
||||
|
||||
|
15
nsprpub/configure
vendored
15
nsprpub/configure
vendored
@ -6560,11 +6560,13 @@ fi
|
||||
|
||||
$as_echo "#define HAVE_POINTER_LOCALTIME_R 1" >>confdefs.h
|
||||
|
||||
|
||||
HOST_DARWIN_MAJOR=`echo "$build_os" | sed -E -e 's/^darwin([0-9]+).*$/\1/'`
|
||||
|
||||
if test "$HOST_DARWIN_MAJOR" -ge 15 ; then
|
||||
$as_echo "#define HAS_CONNECTX 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
fi
|
||||
AS='$(CC) -x assembler-with-cpp'
|
||||
CFLAGS="$CFLAGS -Wall -fno-common"
|
||||
case "${target_cpu}" in
|
||||
@ -8472,19 +8474,12 @@ case "$target" in
|
||||
|
||||
fi
|
||||
if test "$USE_PTHREADS"; then
|
||||
if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then
|
||||
$as_echo "#define _REENTRANT 1" >>confdefs.h
|
||||
|
||||
$as_echo "#define _PR_DCETHREADS 1" >>confdefs.h
|
||||
|
||||
else
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define _POSIX_C_SOURCE 199506L
|
||||
_ACEOF
|
||||
|
||||
$as_echo "#define _PR_HAVE_THREADSAFE_GETHOST 1" >>confdefs.h
|
||||
$as_echo "#define _PR_HAVE_THREADSAFE_GETHOST 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
fi
|
||||
if test "$USE_USER_PTHREADS"; then
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
|
@ -2889,13 +2889,8 @@ case "$target" in
|
||||
AC_DEFINE(_PR_LOCAL_THREADS_ONLY)
|
||||
fi
|
||||
if test "$USE_PTHREADS"; then
|
||||
if echo "$OS_RELEASE" | egrep '^(B.10.10|B.10.20)' >/dev/null; then
|
||||
AC_DEFINE(_REENTRANT)
|
||||
AC_DEFINE(_PR_DCETHREADS)
|
||||
else
|
||||
AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L)
|
||||
AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST)
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L)
|
||||
AC_DEFINE(_PR_HAVE_THREADSAFE_GETHOST)
|
||||
fi
|
||||
if test "$USE_USER_PTHREADS"; then
|
||||
AC_DEFINE_UNQUOTED(_POSIX_C_SOURCE,199506L)
|
||||
|
@ -14,29 +14,7 @@
|
||||
#define _PR_MD_DISABLE_CLOCK_INTERRUPTS()
|
||||
#define _PR_MD_ENABLE_CLOCK_INTERRUPTS()
|
||||
|
||||
/* In good standards fashion, the DCE threads (based on posix-4) are not
|
||||
* quite the same as newer posix implementations. These are mostly name
|
||||
* changes and small differences, so macros usually do the trick
|
||||
*/
|
||||
#ifdef _PR_DCETHREADS
|
||||
#define _PT_PTHREAD_MUTEXATTR_INIT pthread_mutexattr_create
|
||||
#define _PT_PTHREAD_MUTEXATTR_DESTROY pthread_mutexattr_delete
|
||||
#define _PT_PTHREAD_MUTEX_INIT(m, a) pthread_mutex_init(&(m), a)
|
||||
#define _PT_PTHREAD_MUTEX_IS_LOCKED(m) (0 == pthread_mutex_trylock(&(m)))
|
||||
#define _PT_PTHREAD_CONDATTR_INIT pthread_condattr_create
|
||||
#define _PT_PTHREAD_COND_INIT(m, a) pthread_cond_init(&(m), a)
|
||||
#define _PT_PTHREAD_CONDATTR_DESTROY pthread_condattr_delete
|
||||
|
||||
/* Notes about differences between DCE threads and pthreads 10:
|
||||
* 1. pthread_mutex_trylock returns 1 when it locks the mutex
|
||||
* 0 when it does not. The latest pthreads has a set of errno-like
|
||||
* return values.
|
||||
* 2. return values from pthread_cond_timedwait are different.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
#elif defined(BSDI)
|
||||
#if defined(BSDI)
|
||||
/*
|
||||
* Mutex and condition attributes are not supported. The attr
|
||||
* argument to pthread_mutex_init() and pthread_cond_init() must
|
||||
@ -106,13 +84,7 @@
|
||||
* PR_EnterMonitor calls any of these functions, infinite
|
||||
* recursion ensues.
|
||||
*/
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define _PT_PTHREAD_INVALIDATE_THR_HANDLE(t) \
|
||||
memset(&(t), 0, sizeof(pthread_t))
|
||||
#define _PT_PTHREAD_THR_HANDLE_IS_INVALID(t) \
|
||||
(!memcmp(&(t), &pt_zero_tid, sizeof(pthread_t)))
|
||||
#define _PT_PTHREAD_COPY_THR_HANDLE(st, dt) (dt) = (st)
|
||||
#elif defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \
|
||||
#if defined(IRIX) || defined(OSF1) || defined(AIX) || defined(SOLARIS) \
|
||||
|| defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
|
||||
|| defined(HPUX) || defined(FREEBSD) \
|
||||
|| defined(NETBSD) || defined(OPENBSD) || defined(BSDI) \
|
||||
@ -125,17 +97,7 @@
|
||||
#error "pthreads is not supported for this architecture"
|
||||
#endif
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define _PT_PTHREAD_ATTR_INIT pthread_attr_create
|
||||
#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_delete
|
||||
#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, a, f, r)
|
||||
#define _PT_PTHREAD_KEY_CREATE pthread_keycreate
|
||||
#define _PT_PTHREAD_ATTR_SETSCHEDPOLICY pthread_attr_setsched
|
||||
#define _PT_PTHREAD_ATTR_GETSTACKSIZE(a, s) \
|
||||
(*(s) = pthread_attr_getstacksize(*(a)), 0)
|
||||
#define _PT_PTHREAD_GETSPECIFIC(k, r) \
|
||||
pthread_getspecific((k), (pthread_addr_t *) &(r))
|
||||
#elif defined(_PR_PTHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#define _PT_PTHREAD_ATTR_INIT pthread_attr_init
|
||||
#define _PT_PTHREAD_ATTR_DESTROY pthread_attr_destroy
|
||||
#define _PT_PTHREAD_CREATE(t, a, f, r) pthread_create(t, &a, f, r)
|
||||
@ -147,22 +109,6 @@
|
||||
#error "Cannot determine pthread strategy"
|
||||
#endif
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define _PT_PTHREAD_EXPLICIT_SCHED _PT_PTHREAD_DEFAULT_SCHED
|
||||
#endif
|
||||
|
||||
/*
|
||||
* pthread_mutex_trylock returns different values in DCE threads and
|
||||
* pthreads.
|
||||
*/
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define PT_TRYLOCK_SUCCESS 1
|
||||
#define PT_TRYLOCK_BUSY 0
|
||||
#else
|
||||
#define PT_TRYLOCK_SUCCESS 0
|
||||
#define PT_TRYLOCK_BUSY EBUSY
|
||||
#endif
|
||||
|
||||
/*
|
||||
* These platforms don't have sigtimedwait()
|
||||
*/
|
||||
@ -190,16 +136,9 @@
|
||||
#define PT_PRIO_MIN DEFAULT_PRIO
|
||||
#define PT_PRIO_MAX DEFAULT_PRIO
|
||||
#elif defined(HPUX)
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define PT_PRIO_MIN PRI_OTHER_MIN
|
||||
#define PT_PRIO_MAX PRI_OTHER_MAX
|
||||
#else /* defined(_PR_DCETHREADS) */
|
||||
#include <sys/sched.h>
|
||||
#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER)
|
||||
#define PT_PRIO_MAX sched_get_priority_max(SCHED_OTHER)
|
||||
#endif /* defined(_PR_DCETHREADS) */
|
||||
|
||||
#elif defined(LINUX) || defined(__GNU__) || defined(__GLIBC__) \
|
||||
|| defined(FREEBSD) || defined(SYMBIAN)
|
||||
#define PT_PRIO_MIN sched_get_priority_min(SCHED_OTHER)
|
||||
@ -238,9 +177,7 @@
|
||||
* Needed for garbage collection -- Look at PR_Suspend/PR_Resume
|
||||
* implementation.
|
||||
*/
|
||||
#if defined(_PR_DCETHREADS)
|
||||
#define _PT_PTHREAD_YIELD() pthread_yield()
|
||||
#elif defined(OSF1)
|
||||
#if defined(OSF1)
|
||||
/*
|
||||
* sched_yield can't be called from a signal handler. Must use
|
||||
* the _np version.
|
||||
|
@ -6,14 +6,6 @@
|
||||
#ifndef primpl_h___
|
||||
#define primpl_h___
|
||||
|
||||
/*
|
||||
* HP-UX 10.10's pthread.h (DCE threads) includes dce/cma.h, which
|
||||
* has:
|
||||
* #define sigaction _sigaction_sys
|
||||
* This macro causes chaos if signal.h gets included before pthread.h.
|
||||
* To be safe, we include pthread.h first.
|
||||
*/
|
||||
|
||||
#if defined(_PR_PTHREADS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
@ -1877,7 +1869,7 @@ extern PRFileDesc *_pr_stderr;
|
||||
** and functions with macros that expand to the native thread
|
||||
** types and functions on each platform.
|
||||
*/
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#define _PR_ZONE_ALLOCATOR
|
||||
#endif
|
||||
|
||||
|
@ -138,12 +138,8 @@ endif
|
||||
|
||||
ifeq ($(OS_ARCH),HP-UX)
|
||||
ifeq ($(USE_PTHREADS), 1)
|
||||
ifeq (,$(filter-out B.10.10 B.10.20,$(OS_RELEASE)))
|
||||
OS_LIBS = -ldce
|
||||
else
|
||||
OS_LIBS = -lpthread -lrt
|
||||
endif
|
||||
endif
|
||||
ifeq ($(PTHREADS_USER), 1)
|
||||
OS_LIBS = -lpthread
|
||||
endif
|
||||
|
@ -2854,28 +2854,11 @@ void _PR_UnixInit(void)
|
||||
#endif
|
||||
#endif /* !defined(_PR_PTHREADS) */
|
||||
|
||||
/*
|
||||
* Under HP-UX DCE threads, sigaction() installs a per-thread
|
||||
* handler, so we use sigvector() to install a process-wide
|
||||
* handler.
|
||||
*/
|
||||
#if defined(HPUX) && defined(_PR_DCETHREADS)
|
||||
{
|
||||
struct sigvec vec;
|
||||
|
||||
vec.sv_handler = SIG_IGN;
|
||||
vec.sv_mask = 0;
|
||||
vec.sv_flags = 0;
|
||||
rv = sigvector(SIGPIPE, &vec, NULL);
|
||||
PR_ASSERT(0 == rv);
|
||||
}
|
||||
#else
|
||||
sigact.sa_handler = SIG_IGN;
|
||||
sigemptyset(&sigact.sa_mask);
|
||||
sigact.sa_flags = 0;
|
||||
rv = sigaction(SIGPIPE, &sigact, 0);
|
||||
PR_ASSERT(0 == rv);
|
||||
#endif /* HPUX && _PR_DCETHREADS */
|
||||
|
||||
_pr_rename_lock = PR_NewLock();
|
||||
PR_ASSERT(NULL != _pr_rename_lock);
|
||||
|
@ -685,10 +685,6 @@ static void pr_SigchldHandler(int sig)
|
||||
|
||||
static void pr_InstallSigchldHandler()
|
||||
{
|
||||
#if defined(HPUX) && defined(_PR_DCETHREADS)
|
||||
#error "HP-UX DCE threads have their own SIGCHLD handler"
|
||||
#endif
|
||||
|
||||
struct sigaction act, oact;
|
||||
int rv;
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
#if !defined(_PR_HAVE_ATOMIC_OPS)
|
||||
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
/*
|
||||
* PR_AtomicDecrement() is used in NSPR's thread-specific data
|
||||
* destructor. Because thread-specific data destructors may be
|
||||
@ -190,7 +190,7 @@ _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
|
||||
pthread_mutex_unlock(&atomic_locks[idx]);
|
||||
return rv;
|
||||
}
|
||||
#else /* _PR_PTHREADS && !_PR_DCETHREADS */
|
||||
#else /* _PR_PTHREADS */
|
||||
/*
|
||||
* We use a single lock for all the emulated atomic operations.
|
||||
* The lock contention should be acceptable.
|
||||
@ -259,7 +259,7 @@ _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval)
|
||||
PR_Unlock(atomic_lock);
|
||||
return rv;
|
||||
}
|
||||
#endif /* _PR_PTHREADS && !_PR_DCETHREADS */
|
||||
#endif /* _PR_PTHREADS */
|
||||
|
||||
#endif /* !_PR_HAVE_ATOMIC_OPS */
|
||||
|
||||
|
@ -1895,19 +1895,6 @@ static PRInt32 pt_Send(
|
||||
PRInt32 tmp_amount = amount;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Under HP-UX DCE threads, pthread.h includes dce/cma_ux.h,
|
||||
* which has the following:
|
||||
* # define send cma_send
|
||||
* extern int cma_send (int , void *, int, int );
|
||||
* So we need to cast away the 'const' of argument #2 for send().
|
||||
*/
|
||||
#if defined (HPUX) && defined(_PR_DCETHREADS)
|
||||
#define PT_SENDBUF_CAST (void *)
|
||||
#else
|
||||
#define PT_SENDBUF_CAST
|
||||
#endif
|
||||
|
||||
if (pt_TestAbort()) return bytes;
|
||||
|
||||
/*
|
||||
@ -1918,9 +1905,9 @@ static PRInt32 pt_Send(
|
||||
#if defined(SOLARIS)
|
||||
PR_ASSERT(0 == flags);
|
||||
retry:
|
||||
bytes = write(fd->secret->md.osfd, PT_SENDBUF_CAST buf, tmp_amount);
|
||||
bytes = write(fd->secret->md.osfd, buf, tmp_amount);
|
||||
#else
|
||||
bytes = send(fd->secret->md.osfd, PT_SENDBUF_CAST buf, amount, flags);
|
||||
bytes = send(fd->secret->md.osfd, buf, amount, flags);
|
||||
#endif
|
||||
syserrno = errno;
|
||||
|
||||
|
@ -23,11 +23,6 @@ static pthread_condattr_t _pt_cvar_attr;
|
||||
|
||||
#if defined(DEBUG)
|
||||
extern PTDebug pt_debug; /* this is shared between several modules */
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
static pthread_t pt_zero_tid; /* a null pthread_t (pthread_t is a struct
|
||||
* in DCE threads) to compare with */
|
||||
#endif /* defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(DEBUG) */
|
||||
|
||||
#if defined(FREEBSD)
|
||||
@ -263,12 +258,7 @@ static PRIntn pt_TimedWait(
|
||||
rv = pthread_cond_timedwait(cv, ml, &tmo);
|
||||
|
||||
/* NSPR doesn't report timeouts */
|
||||
#ifdef _PR_DCETHREADS
|
||||
if (rv == -1) return (errno == EAGAIN) ? 0 : errno;
|
||||
else return rv;
|
||||
#else
|
||||
return (rv == ETIMEDOUT) ? 0 : rv;
|
||||
#endif
|
||||
} /* pt_TimedWait */
|
||||
|
||||
|
||||
@ -1171,14 +1161,14 @@ PR_IMPLEMENT(PRStatus) PR_DeleteSemaphore(const char *name)
|
||||
PR_IMPLEMENT(PRStatus) PRP_TryLock(PRLock *lock)
|
||||
{
|
||||
PRIntn rv = pthread_mutex_trylock(&lock->mutex);
|
||||
if (rv == PT_TRYLOCK_SUCCESS)
|
||||
if (rv == 0)
|
||||
{
|
||||
PR_ASSERT(PR_FALSE == lock->locked);
|
||||
lock->locked = PR_TRUE;
|
||||
lock->owner = pthread_self();
|
||||
}
|
||||
/* XXX set error code? */
|
||||
return (PT_TRYLOCK_SUCCESS == rv) ? PR_SUCCESS : PR_FAILURE;
|
||||
return (0 == rv) ? PR_SUCCESS : PR_FAILURE;
|
||||
} /* PRP_TryLock */
|
||||
|
||||
PR_IMPLEMENT(PRCondVar*) PRP_NewNakedCondVar(void)
|
||||
|
@ -9,7 +9,7 @@
|
||||
** Exports: ptthread.h
|
||||
*/
|
||||
|
||||
#if defined(_PR_PTHREADS) || defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
|
||||
#include "prlog.h"
|
||||
#include "primpl.h"
|
||||
@ -58,7 +58,7 @@ static struct _PT_Bookeeping
|
||||
pthread_key_t key; /* thread private data key */
|
||||
PRBool keyCreated; /* whether 'key' should be deleted */
|
||||
PRThread *first, *last; /* list of threads we know about */
|
||||
#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
PRInt32 minPrio, maxPrio; /* range of scheduling priorities */
|
||||
#endif
|
||||
} pt_book = {0};
|
||||
@ -67,7 +67,7 @@ static void _pt_thread_death(void *arg);
|
||||
static void _pt_thread_death_internal(void *arg, PRBool callDestructors);
|
||||
static void init_pthread_gc_support(void);
|
||||
|
||||
#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
static PRIntn pt_PriorityMap(PRThreadPriority pri)
|
||||
{
|
||||
#ifdef NTO
|
||||
@ -148,21 +148,6 @@ static void *_pt_root(void *arg)
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
** DCE Threads can't detach during creation, so do it late.
|
||||
** I would like to do it only here, but that doesn't seem
|
||||
** to work.
|
||||
*/
|
||||
#if defined(_PR_DCETHREADS)
|
||||
if (detached)
|
||||
{
|
||||
/* pthread_detach() modifies its argument, so we must pass a copy */
|
||||
pthread_t self = id;
|
||||
rv = pthread_detach(&self);
|
||||
PR_ASSERT(0 == rv);
|
||||
}
|
||||
#endif /* defined(_PR_DCETHREADS) */
|
||||
|
||||
/* Set up the thread stack information */
|
||||
_PR_InitializeStack(thred->stack);
|
||||
|
||||
@ -329,7 +314,7 @@ static PRThread* _PR_CreateThread(
|
||||
|
||||
if (EPERM != pt_schedpriv)
|
||||
{
|
||||
#if !defined(_PR_DCETHREADS) && _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
struct sched_param schedule;
|
||||
#endif
|
||||
|
||||
@ -340,10 +325,7 @@ static PRThread* _PR_CreateThread(
|
||||
|
||||
/* Use the default scheduling policy */
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
rv = pthread_attr_setprio(&tattr, pt_PriorityMap(priority));
|
||||
PR_ASSERT(0 == rv);
|
||||
#elif _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
rv = pthread_attr_getschedparam(&tattr, &schedule);
|
||||
PR_ASSERT(0 == rv);
|
||||
schedule.sched_priority = pt_PriorityMap(priority);
|
||||
@ -353,19 +335,13 @@ static PRThread* _PR_CreateThread(
|
||||
rv = pthread_attr_setschedpolicy(&tattr, SCHED_RR); /* Round Robin */
|
||||
PR_ASSERT(0 == rv);
|
||||
#endif
|
||||
#endif /* !defined(_PR_DCETHREADS) */
|
||||
#endif /* _POSIX_THREAD_PRIORITY_SCHEDULING > 0 */
|
||||
}
|
||||
|
||||
/*
|
||||
* DCE threads can't set detach state before creating the thread.
|
||||
* AIX can't set detach late. Why can't we all just get along?
|
||||
*/
|
||||
#if !defined(_PR_DCETHREADS)
|
||||
rv = pthread_attr_setdetachstate(&tattr,
|
||||
((PR_JOINABLE_THREAD == state) ?
|
||||
PTHREAD_CREATE_JOINABLE : PTHREAD_CREATE_DETACHED));
|
||||
PR_ASSERT(0 == rv);
|
||||
#endif /* !defined(_PR_DCETHREADS) */
|
||||
|
||||
/*
|
||||
* If stackSize is 0, we use the default pthread stack size.
|
||||
@ -456,7 +432,6 @@ static PRThread* _PR_CreateThread(
|
||||
*/
|
||||
rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
|
||||
|
||||
#if !defined(_PR_DCETHREADS)
|
||||
if (EPERM == rv)
|
||||
{
|
||||
#if defined(IRIX)
|
||||
@ -482,15 +457,10 @@ static PRThread* _PR_CreateThread(
|
||||
#endif /* IRIX */
|
||||
rv = _PT_PTHREAD_CREATE(&id, tattr, _pt_root, thred);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (0 != rv)
|
||||
{
|
||||
#if defined(_PR_DCETHREADS)
|
||||
PRIntn oserr = errno;
|
||||
#else
|
||||
PRIntn oserr = rv;
|
||||
#endif
|
||||
PR_Lock(pt_book.ml);
|
||||
if (thred->state & PT_THREAD_SYSTEM)
|
||||
pt_book.system -= 1;
|
||||
@ -602,10 +572,6 @@ PR_IMPLEMENT(PRStatus) PR_JoinThread(PRThread *thred)
|
||||
PR_ASSERT(rv == 0 && result == NULL);
|
||||
if (0 == rv)
|
||||
{
|
||||
#ifdef _PR_DCETHREADS
|
||||
rv = pthread_detach(&id);
|
||||
PR_ASSERT(0 == rv);
|
||||
#endif
|
||||
/*
|
||||
* PR_FALSE, because the thread already called the TPD
|
||||
* destructors before exiting _pt_root.
|
||||
@ -693,10 +659,7 @@ PR_IMPLEMENT(void) PR_SetThreadPriority(PRThread *thred, PRThreadPriority newPri
|
||||
else if ((PRIntn)PR_PRIORITY_LAST < (PRIntn)newPri)
|
||||
newPri = PR_PRIORITY_LAST;
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
rv = pthread_setprio(thred->id, pt_PriorityMap(newPri));
|
||||
/* pthread_setprio returns the old priority */
|
||||
#elif _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
if (EPERM != pt_schedpriv)
|
||||
{
|
||||
int policy;
|
||||
@ -927,7 +890,7 @@ void _PR_InitThreads(
|
||||
pthread_init();
|
||||
#endif
|
||||
|
||||
#if defined(_PR_DCETHREADS) || _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if _POSIX_THREAD_PRIORITY_SCHEDULING > 0
|
||||
#if defined(FREEBSD)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
@ -1161,11 +1124,7 @@ PR_IMPLEMENT(void) PR_ProcessExit(PRIntn status)
|
||||
|
||||
PR_IMPLEMENT(PRUint32) PR_GetThreadID(PRThread *thred)
|
||||
{
|
||||
#if defined(_PR_DCETHREADS)
|
||||
return (PRUint32)&thred->id; /* this is really a sham! */
|
||||
#else
|
||||
return (PRUint32)thred->id; /* and I don't know what they will do with it */
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1197,18 +1156,6 @@ PR_SetThreadDumpProc(PRThread* thread, PRThreadDumpProc dump, void *arg)
|
||||
* Garbage collection support follows.
|
||||
*/
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
|
||||
/*
|
||||
* statics for Garbage Collection support. We don't need to protect these
|
||||
* signal masks since the garbage collector itself is protected by a lock
|
||||
* and multiple threads will not be garbage collecting at the same time.
|
||||
*/
|
||||
static sigset_t javagc_vtalarm_sigmask;
|
||||
static sigset_t javagc_intsoff_sigmask;
|
||||
|
||||
#else /* defined(_PR_DCETHREADS) */
|
||||
|
||||
/* a bogus signal mask for forcing a timed wait */
|
||||
/* Not so bogus in AIX as we really do a sigwait */
|
||||
static sigset_t sigwait_set;
|
||||
@ -1224,8 +1171,6 @@ static void suspend_signal_handler(PRIntn sig);
|
||||
static void null_signal_handler(PRIntn sig);
|
||||
#endif
|
||||
|
||||
#endif /* defined(_PR_DCETHREADS) */
|
||||
|
||||
/*
|
||||
* Linux pthreads use SIGUSR1 and SIGUSR2 internally, which
|
||||
* conflict with the use of these two signals in our GC support.
|
||||
@ -1236,12 +1181,6 @@ static void init_pthread_gc_support(void)
|
||||
#ifndef SYMBIAN
|
||||
PRIntn rv;
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
rv = sigemptyset(&javagc_vtalarm_sigmask);
|
||||
PR_ASSERT(0 == rv);
|
||||
rv = sigaddset(&javagc_vtalarm_sigmask, SIGVTALRM);
|
||||
PR_ASSERT(0 == rv);
|
||||
#else /* defined(_PR_DCETHREADS) */
|
||||
{
|
||||
struct sigaction sigact_usr2;
|
||||
|
||||
@ -1269,7 +1208,6 @@ static void init_pthread_gc_support(void)
|
||||
PR_ASSERT(0 ==rv);
|
||||
}
|
||||
#endif /* defined(PT_NO_SIGTIMEDWAIT) */
|
||||
#endif /* defined(_PR_DCETHREADS) */
|
||||
#endif /* SYMBIAN */
|
||||
}
|
||||
|
||||
@ -1300,9 +1238,7 @@ PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
|
||||
PRThread* thred = pt_book.first;
|
||||
|
||||
#if defined(DEBUG) || defined(FORCE_PR_ASSERT)
|
||||
#if !defined(_PR_DCETHREADS)
|
||||
PRThread *me = PR_GetCurrentThread();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_EnumerateThreads\n"));
|
||||
@ -1331,9 +1267,7 @@ PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
|
||||
|
||||
if (_PT_IS_GCABLE_THREAD(thred))
|
||||
{
|
||||
#if !defined(_PR_DCETHREADS)
|
||||
PR_ASSERT((thred == me) || (thred->suspend & PT_THREAD_SUSPENDED));
|
||||
#endif
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS,
|
||||
("In PR_EnumerateThreads callback thread %p thid = %X\n",
|
||||
thred, thred->id));
|
||||
@ -1361,8 +1295,6 @@ PR_IMPLEMENT(PRStatus) PR_EnumerateThreads(PREnumerator func, void *arg)
|
||||
* proceed until the thread is suspended or resumed.
|
||||
*/
|
||||
|
||||
#if !defined(_PR_DCETHREADS)
|
||||
|
||||
/*
|
||||
* In the signal handler, we can not use condition variable notify or wait.
|
||||
* This does not work consistently across all pthread platforms. We also can not
|
||||
@ -1661,78 +1593,6 @@ PR_IMPLEMENT(void *)PR_GetSP(PRThread *thred)
|
||||
return thred->sp;
|
||||
} /* PR_GetSP */
|
||||
|
||||
#else /* !defined(_PR_DCETHREADS) */
|
||||
|
||||
static pthread_once_t pt_gc_support_control = pthread_once_init;
|
||||
|
||||
/*
|
||||
* For DCE threads, there is no pthread_kill or a way of suspending or resuming a
|
||||
* particular thread. We will just disable the preemption (virtual timer alarm) and
|
||||
* let the executing thread finish the garbage collection. This stops all other threads
|
||||
* (GC able or not) and is very inefficient but there is no other choice.
|
||||
*/
|
||||
PR_IMPLEMENT(void) PR_SuspendAll()
|
||||
{
|
||||
PRIntn rv;
|
||||
|
||||
rv = pthread_once(&pt_gc_support_control, init_pthread_gc_support);
|
||||
PR_ASSERT(0 == rv); /* returns -1 on failure */
|
||||
#ifdef DEBUG
|
||||
suspendAllOn = PR_TRUE;
|
||||
#endif
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_SuspendAll\n"));
|
||||
/*
|
||||
* turn off preemption - i.e add virtual alarm signal to the set of
|
||||
* blocking signals
|
||||
*/
|
||||
rv = sigprocmask(
|
||||
SIG_BLOCK, &javagc_vtalarm_sigmask, &javagc_intsoff_sigmask);
|
||||
PR_ASSERT(0 == rv);
|
||||
suspendAllSuspended = PR_TRUE;
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_SuspendAll\n"));
|
||||
} /* PR_SuspendAll */
|
||||
|
||||
PR_IMPLEMENT(void) PR_ResumeAll()
|
||||
{
|
||||
PRIntn rv;
|
||||
|
||||
suspendAllSuspended = PR_FALSE;
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_ResumeAll\n"));
|
||||
/* turn on preemption - i.e re-enable virtual alarm signal */
|
||||
|
||||
rv = sigprocmask(SIG_SETMASK, &javagc_intsoff_sigmask, (sigset_t *)NULL);
|
||||
PR_ASSERT(0 == rv);
|
||||
#ifdef DEBUG
|
||||
suspendAllOn = PR_FALSE;
|
||||
#endif
|
||||
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_ResumeAll\n"));
|
||||
} /* PR_ResumeAll */
|
||||
|
||||
/* Return the stack pointer for the given thread- used by the GC */
|
||||
PR_IMPLEMENT(void*)PR_GetSP(PRThread *thred)
|
||||
{
|
||||
pthread_t tid = thred->id;
|
||||
char *thread_tcb, *top_sp;
|
||||
|
||||
/*
|
||||
* For HPUX DCE threads, pthread_t is a struct with the
|
||||
* following three fields (see pthread.h, dce/cma.h):
|
||||
* cma_t_address field1;
|
||||
* short int field2;
|
||||
* short int field3;
|
||||
* where cma_t_address is typedef'd to be either void*
|
||||
* or char*.
|
||||
*/
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("Begin PR_GetSP\n"));
|
||||
thread_tcb = (char*)tid.field1;
|
||||
top_sp = *(char**)(thread_tcb + 128);
|
||||
PR_LOG(_pr_gc_lm, PR_LOG_ALWAYS, ("End PR_GetSP %p \n", top_sp));
|
||||
return top_sp;
|
||||
} /* PR_GetSP */
|
||||
|
||||
#endif /* !defined(_PR_DCETHREADS) */
|
||||
|
||||
PR_IMPLEMENT(PRStatus) PR_SetCurrentThreadName(const char *name)
|
||||
{
|
||||
PRThread *thread;
|
||||
@ -1817,6 +1677,6 @@ PR_IMPLEMENT(const char *) PR_GetThreadName(const PRThread *thread)
|
||||
return thread->name;
|
||||
}
|
||||
|
||||
#endif /* defined(_PR_PTHREADS) || defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
|
||||
/* ptthread.c */
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined(HPUX) && defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(HPUX) && defined(_PR_PTHREADS)
|
||||
|
||||
#include <pthread.h>
|
||||
#define HAVE_UNIX98_RWLOCK
|
||||
|
@ -373,9 +373,6 @@ endif
|
||||
ifeq (,$(filter-out FreeBSD OpenBSD BSD_OS QNX Darwin OpenUNIX,$(OS_ARCH)))
|
||||
LIBPTHREAD =
|
||||
endif
|
||||
ifeq ($(OS_ARCH)$(basename $(OS_RELEASE)),HP-UXB.10)
|
||||
LIBPTHREAD = -ldce
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(OS_TARGET),Android)
|
||||
|
@ -111,16 +111,6 @@ static int32 threadStartFunc(void *arg)
|
||||
static void * threadStartFunc(void *arg)
|
||||
#endif
|
||||
{
|
||||
#ifdef _PR_DCETHREADS
|
||||
{
|
||||
int rv;
|
||||
pthread_t self = pthread_self();
|
||||
rv = pthread_detach(&self);
|
||||
if (debug_mode) PR_ASSERT(0 == rv);
|
||||
else if (0 != rv) failed_already=1;
|
||||
}
|
||||
#endif
|
||||
|
||||
Measure(AttachDetach, "Attach/Detach");
|
||||
|
||||
#ifndef IRIX
|
||||
@ -206,14 +196,12 @@ int main(int argc, char **argv)
|
||||
goto exit_now;
|
||||
}
|
||||
|
||||
#ifndef _PR_DCETHREADS
|
||||
rv = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
if (debug_mode) PR_ASSERT(0 == rv);
|
||||
else if (0 != rv) {
|
||||
failed_already=1;
|
||||
goto exit_now;
|
||||
}
|
||||
#endif /* !_PR_DCETHREADS */
|
||||
rv = _PT_PTHREAD_CREATE(&threadID, attr, threadStartFunc, NULL);
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "thread creation failed: error code %d\n", rv);
|
||||
|
@ -29,8 +29,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
|
||||
PRIntn failed_already=0;
|
||||
PRIntn debug_mode=0;
|
||||
|
||||
@ -80,20 +78,13 @@ static PRIntn prmain(PRIntn argc, char **argv)
|
||||
|
||||
} /* prmain */
|
||||
|
||||
#endif /* #if defined(_PR_DCETHREADS) */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
#if defined(_PR_DCETHREADS)
|
||||
PR_Initialize(prmain, argc, argv, 0);
|
||||
if(failed_already)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
} /* main */
|
||||
|
||||
|
||||
|
@ -52,7 +52,7 @@ static int _debug_on = 0;
|
||||
|
||||
#define DPRINTF(arg) if (_debug_on) PR_fprintf arg
|
||||
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#include <pthread.h>
|
||||
#include "md/_pth.h"
|
||||
static void *pthread_start(void *arg)
|
||||
@ -63,7 +63,7 @@ static void *pthread_start(void *arg)
|
||||
start(data);
|
||||
return NULL;
|
||||
} /* pthread_start */
|
||||
#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
|
||||
#if defined(IRIX) && !defined(_PR_PTHREADS)
|
||||
#include <sys/types.h>
|
||||
@ -109,7 +109,7 @@ static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void *arg)
|
||||
}
|
||||
break;
|
||||
case thread_pthread:
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
{
|
||||
int rv;
|
||||
pthread_t id;
|
||||
@ -137,7 +137,7 @@ static PRStatus NSPRPUB_TESTS_CreateThread(StartFn start, void *arg)
|
||||
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
||||
rv = PR_FAILURE;
|
||||
break;
|
||||
#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
|
||||
case thread_sproc:
|
||||
#if defined(IRIX) && !defined(_PR_PTHREADS)
|
||||
|
@ -196,51 +196,6 @@ finish:
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef _PR_DCETHREADS
|
||||
|
||||
#include <syscall.h>
|
||||
|
||||
pid_t PR_UnixFork1(void)
|
||||
{
|
||||
pid_t parent = getpid();
|
||||
int rv = syscall(SYS_fork);
|
||||
|
||||
if (rv == -1) {
|
||||
return (pid_t) -1;
|
||||
} else {
|
||||
/* For each process, rv is the pid of the other process */
|
||||
if (rv == parent) {
|
||||
/* the child */
|
||||
return 0;
|
||||
} else {
|
||||
/* the parent */
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(SOLARIS)
|
||||
|
||||
/*
|
||||
* It seems like that in Solaris 2.4 one must call fork1() if the
|
||||
* the child process is going to use thread functions. Solaris 2.5
|
||||
* doesn't have this problem. Calling fork() also works.
|
||||
*/
|
||||
|
||||
pid_t PR_UnixFork1(void)
|
||||
{
|
||||
return fork1();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
pid_t PR_UnixFork1(void)
|
||||
{
|
||||
return fork();
|
||||
}
|
||||
|
||||
#endif /* PR_DCETHREADS */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pid_t pid;
|
||||
@ -250,7 +205,7 @@ int main(int argc, char **argv)
|
||||
|
||||
DoIO();
|
||||
|
||||
pid = PR_UnixFork1();
|
||||
pid = fork();
|
||||
|
||||
if (pid == (pid_t) -1) {
|
||||
fprintf(stderr, "Fork failed: errno %d\n", errno);
|
||||
|
@ -606,7 +606,7 @@ typedef struct StartObject
|
||||
void *arg;
|
||||
} StartObject;
|
||||
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#include "md/_pth.h"
|
||||
#include <pthread.h>
|
||||
|
||||
@ -619,7 +619,7 @@ static void *pthread_start(void *arg)
|
||||
start(data);
|
||||
return NULL;
|
||||
} /* pthread_start */
|
||||
#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
|
||||
#if defined(IRIX) && !defined(_PR_PTHREADS)
|
||||
#include <sys/types.h>
|
||||
@ -657,10 +657,10 @@ static PRStatus JoinThread(PRThread *thread)
|
||||
rv = PR_JoinThread(thread);
|
||||
break;
|
||||
case thread_pthread:
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
rv = PR_SUCCESS;
|
||||
break;
|
||||
#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
case thread_win32:
|
||||
#if defined(WIN32)
|
||||
rv = PR_SUCCESS;
|
||||
@ -690,7 +690,7 @@ static PRStatus NewThread(
|
||||
}
|
||||
break;
|
||||
case thread_pthread:
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
{
|
||||
int rv;
|
||||
pthread_t id;
|
||||
@ -717,7 +717,7 @@ static PRStatus NewThread(
|
||||
#else
|
||||
PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
|
||||
rv = PR_FAILURE;
|
||||
#endif /* defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) */
|
||||
#endif /* defined(_PR_PTHREADS) */
|
||||
break;
|
||||
|
||||
case thread_sproc:
|
||||
|
@ -21,7 +21,7 @@
|
||||
#ifdef XP_UNIX
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
@ -313,7 +313,7 @@ PRThread* create_new_thread(PRThreadType type,
|
||||
PRInt32 native_thread = 0;
|
||||
|
||||
PR_ASSERT(state == PR_UNJOINABLE_THREAD);
|
||||
#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32)
|
||||
#if defined(_PR_PTHREADS) || defined(WIN32)
|
||||
switch(index % 4) {
|
||||
case 0:
|
||||
scope = (PR_LOCAL_THREAD);
|
||||
@ -332,7 +332,7 @@ PRInt32 native_thread = 0;
|
||||
break;
|
||||
}
|
||||
if (native_thread) {
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
pthread_t tid;
|
||||
if (!pthread_create(&tid, NULL, (void * (*)(void *)) start, arg))
|
||||
return((PRThread *) tid);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#endif
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
#ifdef SYMBIAN
|
||||
@ -104,7 +104,7 @@ PRInt32 native_thread = 0;
|
||||
|
||||
PR_ASSERT(state == PR_UNJOINABLE_THREAD);
|
||||
|
||||
#if (defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)) || defined(WIN32) || defined(XP_OS2)
|
||||
#if defined(_PR_PTHREADS) || defined(WIN32) || defined(XP_OS2)
|
||||
|
||||
switch(index % 4) {
|
||||
case 0:
|
||||
@ -124,7 +124,7 @@ PRInt32 native_thread = 0;
|
||||
break;
|
||||
}
|
||||
if (native_thread) {
|
||||
#if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS)
|
||||
#if defined(_PR_PTHREADS)
|
||||
pthread_t tid;
|
||||
if (!pthread_create(&tid, NULL, start, arg))
|
||||
return((PRThread *) tid);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user