mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
198430bca2
@ -2107,11 +2107,31 @@ DocAccessible::DoARIAOwnsRelocation(Accessible* aOwner)
|
||||
#endif
|
||||
|
||||
// Same child on same position, no change.
|
||||
if (child->Parent() == aOwner &&
|
||||
child->IndexInParent() == static_cast<int32_t>(insertIdx)) {
|
||||
MOZ_ASSERT(owned->ElementAt(idx) == child, "Not in sync!");
|
||||
idx++;
|
||||
continue;
|
||||
if (child->Parent() == aOwner) {
|
||||
int32_t indexInParent = child->IndexInParent();
|
||||
|
||||
// The child is being placed in its current index,
|
||||
// eg. aria-owns='id1 id2 id3' is changed to aria-owns='id3 id2 id1'.
|
||||
if (indexInParent == static_cast<int32_t>(insertIdx)) {
|
||||
MOZ_ASSERT(child->IsRelocated(),
|
||||
"A child, having an index in parent from aria ownded indices range, has to be aria owned");
|
||||
MOZ_ASSERT(owned->ElementAt(idx) == child,
|
||||
"Unexpected child in ARIA owned array");
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The child is being inserted directly after its current index,
|
||||
// resulting in a no-move case. This will happen when a parent aria-owns
|
||||
// its last ordinal child:
|
||||
// <ul aria-owns='id2'><li id='id1'></li><li id='id2'></li></ul>
|
||||
if (indexInParent == static_cast<int32_t>(insertIdx) - 1) {
|
||||
MOZ_ASSERT(!child->IsRelocated(), "Child should be in its ordinal position");
|
||||
child->SetRelocated(true);
|
||||
owned->InsertElementAt(idx, child);
|
||||
idx++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(owned->SafeElementAt(idx) != child, "Already in place!");
|
||||
@ -2190,7 +2210,23 @@ DocAccessible::PutChildrenBack(nsTArray<RefPtr<Accessible> >* aChildren,
|
||||
}
|
||||
}
|
||||
}
|
||||
MoveChild(child, origContainer, idxInParent);
|
||||
|
||||
// The child may have already be in its ordinal place for 2 reasons:
|
||||
// 1. It was the last ordinal child, and the first aria-owned child.
|
||||
// given: <ul id="list" aria-owns="b"><li id="a"></li><li id="b"></li></ul>
|
||||
// after load: $("list").setAttribute("aria-owns", "");
|
||||
// 2. The preceding adopted children were just reclaimed, eg:
|
||||
// given: <ul id="list"><li id="b"></li></ul>
|
||||
// after load: $("list").setAttribute("aria-owns", "a b");
|
||||
// later: $("list").setAttribute("aria-owns", "");
|
||||
if (origContainer != owner || child->IndexInParent() != idxInParent) {
|
||||
MoveChild(child, origContainer, idxInParent);
|
||||
} else {
|
||||
MOZ_ASSERT(!child->PrevSibling() || !child->PrevSibling()->IsRelocated(),
|
||||
"No relocated child should appear before this one");
|
||||
MOZ_ASSERT(!child->NextSibling() || child->NextSibling()->IsRelocated(),
|
||||
"No ordinal child should appear after this one");
|
||||
}
|
||||
}
|
||||
|
||||
aChildren->RemoveElementsAt(aStartIdx, aChildren->Length() - aStartIdx);
|
||||
|
@ -36,7 +36,8 @@ BROWSER_CHROME_MANIFESTS += [
|
||||
'tests/browser/e10s/browser.ini',
|
||||
'tests/browser/events/browser.ini',
|
||||
'tests/browser/scroll/browser.ini',
|
||||
'tests/browser/states/browser.ini'
|
||||
'tests/browser/states/browser.ini',
|
||||
'tests/browser/tree/browser.ini'
|
||||
]
|
||||
|
||||
with Files("**"):
|
||||
|
@ -160,13 +160,15 @@ class UnexpectedEvents {
|
||||
* @param {Array} events a list of events to wait (same format as
|
||||
* waitForEvent arguments)
|
||||
*/
|
||||
function waitForEvents(events, unexpected = [], ordered = false) {
|
||||
function waitForEvents(events, ordered = false) {
|
||||
let expected = events.expected || events;
|
||||
let unexpected = events.unexpected || [];
|
||||
// Next expected event index.
|
||||
let currentIdx = 0;
|
||||
|
||||
let unexpectedListener = new UnexpectedEvents(unexpected);
|
||||
|
||||
return Promise.all(events.map((evt, idx) => {
|
||||
return Promise.all(expected.map((evt, idx) => {
|
||||
let promise = evt instanceof Array ? waitForEvent(...evt) : evt;
|
||||
return promise.then(result => {
|
||||
if (ordered) {
|
||||
@ -181,6 +183,6 @@ function waitForEvents(events, unexpected = [], ordered = false) {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForOrderedEvents(events, unexpected = []) {
|
||||
return waitForEvents(events, unexpected, true);
|
||||
function waitForOrderedEvents(events) {
|
||||
return waitForEvents(events, true);
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
invokeSetStyle, getAccessibleDOMNodeID, getAccessibleTagName,
|
||||
addAccessibleTask, findAccessibleChildByID, isDefunct,
|
||||
CURRENT_CONTENT_DIR, loadScripts, loadFrameScripts, snippetToURL,
|
||||
Cc, Cu */
|
||||
Cc, Cu, arrayFromChildren */
|
||||
|
||||
const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
|
||||
|
||||
@ -358,3 +358,8 @@ function queryInterfaces(accessible, interfaces) {
|
||||
|
||||
return accessible;
|
||||
}
|
||||
|
||||
function arrayFromChildren(accessible) {
|
||||
return Array.from({ length: accessible.childCount }, (c, i) =>
|
||||
accessible.getChildAt(i));
|
||||
}
|
||||
|
9
accessible/tests/browser/tree/browser.ini
Normal file
9
accessible/tests/browser/tree/browser.ini
Normal file
@ -0,0 +1,9 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
!/accessible/tests/browser/shared-head.js
|
||||
!/accessible/tests/mochitest/*.js
|
||||
|
||||
[browser_test_aria_owns.js]
|
96
accessible/tests/browser/tree/browser_test_aria_owns.js
Normal file
96
accessible/tests/browser/tree/browser_test_aria_owns.js
Normal file
@ -0,0 +1,96 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function testChildrenIds(acc, expectedIds) {
|
||||
let ids = arrayFromChildren(acc).map(child => getAccessibleDOMNodeID(child));
|
||||
Assert.deepEqual(ids, expectedIds,
|
||||
`Children for ${getAccessibleDOMNodeID(acc)} are wrong.`);
|
||||
}
|
||||
|
||||
async function runTests(browser, accDoc) {
|
||||
let one = findAccessibleChildByID(accDoc, "one");
|
||||
let two = findAccessibleChildByID(accDoc, "two");
|
||||
let three = findAccessibleChildByID(accDoc, "three");
|
||||
let four = findAccessibleChildByID(accDoc, "four");
|
||||
|
||||
testChildrenIds(one, ["a"]);
|
||||
testChildrenIds(two, ["b", "c", "d"]);
|
||||
testChildrenIds(three, []);
|
||||
|
||||
let onReorders = waitForEvents({
|
||||
expected: [
|
||||
[EVENT_REORDER, "two"]], // children will be reordered via aria-owns
|
||||
unexpected: [
|
||||
[EVENT_REORDER, "one"], // child will remain in place
|
||||
[EVENT_REORDER, "three"], // none of its children will be reclaimed
|
||||
[EVENT_REORDER, "four"]] // child will remain in place
|
||||
});
|
||||
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
// aria-own ordinal child in place, should be a no-op.
|
||||
document.getElementById("one").setAttribute("aria-owns", "a");
|
||||
// remove aria-owned child that is already ordinal, should be no-op.
|
||||
document.getElementById("four").removeAttribute("aria-owns");
|
||||
// shuffle aria-owns with markup child.
|
||||
document.getElementById("two").setAttribute("aria-owns", "d c");
|
||||
});
|
||||
|
||||
await onReorders;
|
||||
|
||||
testChildrenIds(one, ["a"]);
|
||||
testChildrenIds(two, ["b", "d", "c"]);
|
||||
testChildrenIds(three, []);
|
||||
testChildrenIds(four, ["e"]);
|
||||
|
||||
onReorders = waitForEvent(EVENT_REORDER, "one");
|
||||
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
let aa = document.createElement("li");
|
||||
aa.id = "aa";
|
||||
document.getElementById("one").appendChild(aa);
|
||||
});
|
||||
|
||||
await onReorders;
|
||||
|
||||
testChildrenIds(one, ["aa", "a"]);
|
||||
|
||||
onReorders = waitForEvents([
|
||||
[EVENT_REORDER, "two"], // "b" will go to "three"
|
||||
[EVENT_REORDER, "three"], // some children will be reclaimed and acquired
|
||||
[EVENT_REORDER, "one"]]); // removing aria-owns will reorder native children
|
||||
|
||||
await ContentTask.spawn(browser, null, async function() {
|
||||
// removing aria-owns should reorder the children
|
||||
document.getElementById("one").removeAttribute("aria-owns");
|
||||
// child order will be overridden by aria-owns
|
||||
document.getElementById("three").setAttribute("aria-owns", "b d");
|
||||
});
|
||||
|
||||
await onReorders;
|
||||
|
||||
testChildrenIds(one, ["a", "aa"]);
|
||||
testChildrenIds(two, ["c"]);
|
||||
testChildrenIds(three, ["b", "d"]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test caching of accessible object states
|
||||
*/
|
||||
addAccessibleTask(`
|
||||
<ul id="one">
|
||||
<li id="a">Test</li>
|
||||
</ul>
|
||||
<ul id="two" aria-owns="d">
|
||||
<li id="b">Test 2</li>
|
||||
<li id="c">Test 3</li>
|
||||
</ul>
|
||||
<ul id="three">
|
||||
<li id="d">Test 4</li>
|
||||
</ul>
|
||||
<ul id="four" aria-owns="e">
|
||||
<li id="e">Test 5</li>
|
||||
</ul>
|
||||
`, runTests);
|
15
accessible/tests/browser/tree/head.js
Normal file
15
accessible/tests/browser/tree/head.js
Normal file
@ -0,0 +1,15 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
'use strict';
|
||||
|
||||
// Load the shared-head file first.
|
||||
/* import-globals-from ../shared-head.js */
|
||||
Services.scriptloader.loadSubScript(
|
||||
'chrome://mochitests/content/browser/accessible/tests/browser/shared-head.js',
|
||||
this);
|
||||
|
||||
// Loading and common.js from accessible/tests/mochitest/ for all tests, as
|
||||
// well as events.js.
|
||||
loadScripts({ name: 'common.js', dir: MOCHITESTS_DIR }, 'events.js', 'layout.js');
|
@ -1445,8 +1445,6 @@ AccessibleWrap::GetIAccessibleFor(const VARIANT& aVarChild, bool* aIsDefunct)
|
||||
if (XRE_IsParentProcess() && !IsProxy() && !sIDGen.IsChromeID(varChild.lVal)) {
|
||||
return GetRemoteIAccessibleFor(varChild);
|
||||
}
|
||||
MOZ_ASSERT(XRE_IsParentProcess() ||
|
||||
sIDGen.IsIDForThisContentProcess(varChild.lVal));
|
||||
|
||||
if (varChild.lVal > 0) {
|
||||
// Gecko child indices are 0-based in contrast to indices used in MSAA.
|
||||
|
@ -911,6 +911,7 @@ var RefreshBlocker = {
|
||||
this._filter = Cc["@mozilla.org/appshell/component/browser-status-filter;1"]
|
||||
.createInstance(Ci.nsIWebProgress);
|
||||
this._filter.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
this._filter.target = tabEventTarget;
|
||||
|
||||
let webProgress = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
|
@ -313,6 +313,18 @@
|
||||
margin-top: -32px;
|
||||
}
|
||||
|
||||
/* Remove default dotted outline around buttons' text */
|
||||
.onboarding-tour-action-button::-moz-focus-inner {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* Keyboard focus specific outline */
|
||||
.onboarding-tour-action-button:-moz-focusring {
|
||||
outline: 2px solid rgba(0,149,221,0.5);
|
||||
outline-offset: 1px;
|
||||
-moz-outline-radius: 2px;
|
||||
}
|
||||
|
||||
.onboarding-tour-action-button:hover:not([disabled]) ,
|
||||
#onboarding-notification-action-btn:hover {
|
||||
background: #0060df;
|
||||
|
@ -35,10 +35,10 @@ module.exports = createClass({
|
||||
let { boxModel } = this.props;
|
||||
let { geometryEditorEnabled, layout } = boxModel;
|
||||
let {
|
||||
height,
|
||||
height = "-",
|
||||
isPositionEditable,
|
||||
position,
|
||||
width,
|
||||
width = "-",
|
||||
} = layout;
|
||||
|
||||
let buttonClass = "layout-geometry-editor devtools-button";
|
||||
|
@ -120,12 +120,12 @@ module.exports = createClass({
|
||||
},
|
||||
|
||||
getHeightValue(property) {
|
||||
let { layout } = this.props.boxModel;
|
||||
|
||||
if (property == undefined) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
let { layout } = this.props.boxModel;
|
||||
|
||||
property -= parseFloat(layout["border-top-width"]) +
|
||||
parseFloat(layout["border-bottom-width"]) +
|
||||
parseFloat(layout["padding-top"]) +
|
||||
@ -136,12 +136,12 @@ module.exports = createClass({
|
||||
},
|
||||
|
||||
getWidthValue(property) {
|
||||
let { layout } = this.props.boxModel;
|
||||
|
||||
if (property == undefined) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
let { layout } = this.props.boxModel;
|
||||
|
||||
property -= parseFloat(layout["border-left-width"]) +
|
||||
parseFloat(layout["border-right-width"]) +
|
||||
parseFloat(layout["padding-left"]) +
|
||||
|
@ -2990,8 +2990,8 @@ Element::List(FILE* out, int32_t aIndent,
|
||||
static_cast<unsigned long long>(State().GetInternalValue()));
|
||||
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||
if (IsCommonAncestorForRangeInSelection()) {
|
||||
nsRange::RangeHashTable* ranges =
|
||||
static_cast<nsRange::RangeHashTable*>(GetProperty(nsGkAtoms::range));
|
||||
const nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
|
||||
GetExistingCommonAncestorRanges();
|
||||
fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
|
||||
}
|
||||
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
|
||||
|
@ -658,6 +658,19 @@ nsNodeSupportsWeakRefTearoff::GetWeakReference(nsIWeakReference** aInstancePtr)
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
static const size_t MaxDOMSlotSizeAllowed =
|
||||
#ifdef HAVE_64BIT_BUILD
|
||||
128;
|
||||
#else
|
||||
64;
|
||||
#endif
|
||||
|
||||
static_assert(sizeof(nsINode::nsSlots) <= MaxDOMSlotSizeAllowed,
|
||||
"DOM slots cannot be grown without consideration");
|
||||
static_assert(sizeof(FragmentOrElement::nsDOMSlots) <= MaxDOMSlotSizeAllowed,
|
||||
"DOM slots cannot be grown without consideration");
|
||||
|
||||
FragmentOrElement::nsDOMSlots::nsDOMSlots()
|
||||
: nsINode::nsSlots(),
|
||||
mDataset(nullptr)
|
||||
|
@ -22,7 +22,12 @@ namespace dom {
|
||||
StructuredCloneBlob::StructuredCloneBlob()
|
||||
: StructuredCloneHolder(CloningSupported, TransferringNotSupported,
|
||||
StructuredCloneScope::DifferentProcess)
|
||||
{};
|
||||
{}
|
||||
|
||||
StructuredCloneBlob::~StructuredCloneBlob()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
|
||||
/* static */ already_AddRefed<StructuredCloneBlob>
|
||||
@ -32,7 +37,7 @@ StructuredCloneBlob::Constructor(GlobalObject& aGlobal, JS::HandleValue aValue,
|
||||
{
|
||||
JSContext* cx = aGlobal.Context();
|
||||
|
||||
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
||||
RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
|
||||
|
||||
Maybe<JSAutoCompartment> ac;
|
||||
JS::RootedValue value(cx, aValue);
|
||||
@ -104,7 +109,7 @@ StructuredCloneBlob::ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader
|
||||
{
|
||||
JS::RootedObject obj(aCx);
|
||||
{
|
||||
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
||||
RefPtr<StructuredCloneBlob> holder = StructuredCloneBlob::Create();
|
||||
|
||||
if (!holder->ReadStructuredCloneInternal(aCx, aReader, aHolder) ||
|
||||
!holder->WrapObject(aCx, nullptr, &obj)) {
|
||||
@ -181,5 +186,20 @@ StructuredCloneBlob::WrapObject(JSContext* aCx, JS::HandleObject aGivenProto, JS
|
||||
return StructuredCloneHolderBinding::Wrap(aCx, this, aGivenProto, aResult);
|
||||
}
|
||||
|
||||
|
||||
NS_IMETHODIMP
|
||||
StructuredCloneBlob::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/dom/structured-clone-holder", KIND_HEAP, UNITS_BYTES,
|
||||
MallocSizeOf(this) + SizeOfExcludingThis(MallocSizeOf),
|
||||
"Memory used by StructuredCloneHolder DOM objects.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(StructuredCloneBlob, nsIMemoryReporter)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -9,22 +9,23 @@
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||
#include "mozilla/dom/StructuredCloneHolderBinding.h"
|
||||
#include "mozilla/RefCounted.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsISupports.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class StructuredCloneBlob : public StructuredCloneHolder
|
||||
, public RefCounted<StructuredCloneBlob>
|
||||
class StructuredCloneBlob final : public nsIMemoryReporter
|
||||
, public StructuredCloneHolder
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_REFCOUNTED_TYPENAME(StructuredCloneBlob)
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)
|
||||
|
||||
explicit StructuredCloneBlob();
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
static JSObject* ReadStructuredClone(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder);
|
||||
@ -43,12 +44,18 @@ public:
|
||||
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto, JS::MutableHandleObject aResult);
|
||||
|
||||
protected:
|
||||
template <typename T, detail::RefCountAtomicity>
|
||||
friend class detail::RefCounted;
|
||||
|
||||
~StructuredCloneBlob() = default;
|
||||
virtual ~StructuredCloneBlob();
|
||||
|
||||
private:
|
||||
explicit StructuredCloneBlob();
|
||||
|
||||
static already_AddRefed<StructuredCloneBlob> Create()
|
||||
{
|
||||
RefPtr<StructuredCloneBlob> holder = new StructuredCloneBlob();
|
||||
RegisterWeakMemoryReporter(holder);
|
||||
return holder.forget();
|
||||
}
|
||||
|
||||
bool ReadStructuredCloneInternal(JSContext* aCx, JSStructuredCloneReader* aReader,
|
||||
StructuredCloneHolder* aHolder);
|
||||
};
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "js/StructuredClone.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
@ -116,6 +117,15 @@ public:
|
||||
return mBuffer->data();
|
||||
}
|
||||
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
size_t size = 0;
|
||||
if (HasData()) {
|
||||
size += mBuffer->sizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
protected:
|
||||
UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
|
||||
|
||||
@ -306,6 +316,12 @@ protected:
|
||||
bool mSupportsCloning;
|
||||
bool mSupportsTransferring;
|
||||
|
||||
// SizeOfExcludingThis is inherited from StructuredCloneHolderBase. It doesn't
|
||||
// account for objects in the following arrays because a) they're not expected
|
||||
// to be stored in long-lived StructuredCloneHolder objects, and b) in the
|
||||
// case of BlobImpl objects, MemoryBlobImpls have their own memory reporters,
|
||||
// and the other types do not hold significant amounts of memory alive.
|
||||
|
||||
// Used for cloning blobs in the structured cloning algorithm.
|
||||
nsTArray<RefPtr<BlobImpl>> mBlobImplArray;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef TabGroup_h
|
||||
#define TabGroup_h
|
||||
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsTHashtable.h"
|
||||
@ -43,6 +44,7 @@ class TabChild;
|
||||
// window.opener. A DocGroup is a member of exactly one TabGroup.
|
||||
|
||||
class DocGroup;
|
||||
class TabChild;
|
||||
|
||||
class TabGroup final : public SchedulerGroup
|
||||
{
|
||||
|
@ -1291,6 +1291,8 @@ TimeoutManager::MaybeStartThrottleTimeout()
|
||||
nsCOMPtr<nsITimerCallback> callback =
|
||||
new ThrottleTimeoutsCallback(&mWindow);
|
||||
|
||||
mThrottleTimeoutsTimer->SetTarget(EventTarget());
|
||||
|
||||
mThrottleTimeoutsTimer->InitWithCallback(
|
||||
callback, gTimeoutThrottlingDelay, nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
@ -849,6 +849,13 @@ nsFrameMessageManager::GetDocShell(nsIDocShell** aDocShell)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::GetTabEventTarget(nsIEventTarget** aTarget)
|
||||
{
|
||||
*aTarget = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::Btoa(const nsAString& aBinaryData,
|
||||
nsAString& aAsciiBase64String)
|
||||
|
@ -1033,7 +1033,7 @@ nsPIDOMWindow<T>::nsPIDOMWindow(nsPIDOMWindowOuter *aOuterWindow)
|
||||
mMarkedCCGeneration(0), mServiceWorkersTestingEnabled(false),
|
||||
mLargeAllocStatus(LargeAllocStatus::NONE),
|
||||
mHasTriedToCacheTopInnerWindow(false),
|
||||
mNumOfIndexedDBDatabases(0), mCleanedUp(false)
|
||||
mNumOfIndexedDBDatabases(0)
|
||||
{
|
||||
if (aOuterWindow) {
|
||||
mTimeoutManager =
|
||||
@ -1620,6 +1620,7 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow)
|
||||
mNetworkUploadObserverEnabled(false),
|
||||
mNetworkDownloadObserverEnabled(false),
|
||||
#endif
|
||||
mCleanedUp(false),
|
||||
mDialogAbuseCount(0),
|
||||
mAreDialogsEnabled(true),
|
||||
#ifdef DEBUG
|
||||
@ -2005,10 +2006,7 @@ nsGlobalWindow::CleanUp()
|
||||
|
||||
mMozSelfSupport = nullptr;
|
||||
|
||||
if (mPerformance) {
|
||||
mPerformance->Shutdown();
|
||||
mPerformance = nullptr;
|
||||
}
|
||||
mPerformance = nullptr;
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
mSpeechSynthesis = nullptr;
|
||||
@ -4363,10 +4361,9 @@ nsPIDOMWindowInner::CreatePerformanceObjectIfNeeded()
|
||||
{
|
||||
MOZ_ASSERT(IsInnerWindow());
|
||||
|
||||
if (mPerformance || !mDoc || mCleanedUp) {
|
||||
if (mPerformance || !mDoc) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<nsDOMNavigationTiming> timing = mDoc->GetNavigationTiming();
|
||||
nsCOMPtr<nsITimedChannel> timedChannel(do_QueryInterface(mDoc->GetChannel()));
|
||||
bool timingEnabled = false;
|
||||
|
@ -2010,6 +2010,8 @@ protected:
|
||||
bool mNetworkDownloadObserverEnabled;
|
||||
#endif // MOZ_B2G
|
||||
|
||||
bool mCleanedUp;
|
||||
|
||||
nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
|
||||
|
||||
using XBLPrototypeHandlerTable = nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*>;
|
||||
|
@ -8,6 +8,7 @@
|
||||
interface mozIDOMWindowProxy;
|
||||
interface nsIDocShell;
|
||||
interface nsIContent;
|
||||
interface nsIEventTarget;
|
||||
interface nsIFrameLoader;
|
||||
interface nsIPrincipal;
|
||||
|
||||
@ -398,6 +399,12 @@ interface nsIContentFrameMessageManager : nsIMessageManagerGlobal
|
||||
* The top level docshell or null.
|
||||
*/
|
||||
readonly attribute nsIDocShell docShell;
|
||||
|
||||
/**
|
||||
* Returns the SchedulerEventTarget corresponding to the TabGroup
|
||||
* for this frame.
|
||||
*/
|
||||
readonly attribute nsIEventTarget tabEventTarget;
|
||||
};
|
||||
|
||||
[uuid(b39a3324-b574-4f85-8cdb-274d04f807ef)]
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "js/TypeDecls.h" // for Handle, Value, JSObject, JSContext
|
||||
#include "mozilla/dom/DOMString.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsTHashtable.h"
|
||||
#include <iosfwd>
|
||||
|
||||
// Including 'windows.h' will #define GetClassInfo to something else.
|
||||
@ -51,6 +52,7 @@ class nsIURI;
|
||||
class nsNodeSupportsWeakRefTearoff;
|
||||
class nsNodeWeakReference;
|
||||
class nsDOMMutationObserver;
|
||||
class nsRange;
|
||||
|
||||
namespace mozilla {
|
||||
class EventListenerManager;
|
||||
@ -1108,6 +1110,12 @@ public:
|
||||
*/
|
||||
nsNodeWeakReference* MOZ_NON_OWNING_REF mWeakReference;
|
||||
|
||||
/**
|
||||
* A set of ranges in the common ancestor for the selection to which
|
||||
* this node belongs to.
|
||||
*/
|
||||
mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>> mCommonAncestorRanges;
|
||||
|
||||
/**
|
||||
* Number of descendant nodes in the uncomposed document that have been
|
||||
* explicitly set as editable.
|
||||
@ -1898,6 +1906,27 @@ public:
|
||||
CallerType aCallerType,
|
||||
ErrorResult& aRv);
|
||||
|
||||
const nsTHashtable<nsPtrHashKey<nsRange>>* GetExistingCommonAncestorRanges() const
|
||||
{
|
||||
if (!HasSlots()) {
|
||||
return nullptr;
|
||||
}
|
||||
mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& ranges =
|
||||
GetExistingSlots()->mCommonAncestorRanges;
|
||||
return ranges.get();
|
||||
}
|
||||
|
||||
nsTHashtable<nsPtrHashKey<nsRange>>* GetExistingCommonAncestorRanges()
|
||||
{
|
||||
nsINode::nsSlots* slots = GetExistingSlots();
|
||||
return slots ? slots->mCommonAncestorRanges.get() : nullptr;
|
||||
}
|
||||
|
||||
mozilla::UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& GetCommonAncestorRangesPtr()
|
||||
{
|
||||
return Slots()->mCommonAncestorRanges;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
// Override this function to create a custom slots class.
|
||||
|
@ -199,6 +199,14 @@ nsInProcessTabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsInProcessTabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
|
||||
{
|
||||
nsCOMPtr<nsIEventTarget> target = GetMainThreadEventTarget();
|
||||
target.forget(aTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsInProcessTabChildGlobal::FireUnloadEvent()
|
||||
{
|
||||
|
@ -77,6 +77,7 @@ public:
|
||||
}
|
||||
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
||||
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
||||
NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
|
||||
|
||||
NS_DECL_NSIINPROCESSCONTENTFRAMEMESSAGEMANAGER
|
||||
|
||||
|
@ -2090,10 +2090,15 @@ CCRunnerFired(TimeStamp aDeadline, void* aData)
|
||||
// Our efforts to avoid a CC have failed, so we return to let the
|
||||
// timer fire once more to trigger a CC.
|
||||
|
||||
// Clear content unbinder before the first CC slice.
|
||||
Element::ClearContentUnbinder();
|
||||
// And trigger deferred deletion too.
|
||||
nsCycleCollector_doDeferredDeletion();
|
||||
if (!aDeadline.IsNull() && TimeStamp::Now() < aDeadline) {
|
||||
// Clear content unbinder before the first CC slice.
|
||||
Element::ClearContentUnbinder();
|
||||
|
||||
if (TimeStamp::Now() < aDeadline) {
|
||||
// And trigger deferred deletion too.
|
||||
nsCycleCollector_doDeferredDeletion();
|
||||
}
|
||||
}
|
||||
return didDoWork;
|
||||
}
|
||||
} else {
|
||||
|
@ -772,8 +772,6 @@ protected:
|
||||
|
||||
// The number of active IndexedDB databases. Inner window only.
|
||||
uint32_t mNumOfIndexedDBDatabases;
|
||||
|
||||
bool mCleanedUp;
|
||||
};
|
||||
|
||||
#define NS_PIDOMWINDOWINNER_IID \
|
||||
|
@ -205,8 +205,11 @@ nsRange::IsNodeSelected(nsINode* aNode, uint32_t aStartOffset,
|
||||
nsTHashtable<nsPtrHashKey<Selection>> ancestorSelections;
|
||||
uint32_t maxRangeCount = 0;
|
||||
for (; n; n = GetNextRangeCommonAncestor(n->GetParentNode())) {
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(n->GetProperty(nsGkAtoms::range));
|
||||
nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
|
||||
n->GetExistingCommonAncestorRanges();
|
||||
if (!ranges) {
|
||||
continue;
|
||||
}
|
||||
for (auto iter = ranges->ConstIter(); !iter.Done(); iter.Next()) {
|
||||
nsRange* range = iter.Get()->GetKey();
|
||||
if (range->IsInSelection() && !range->Collapsed()) {
|
||||
@ -408,12 +411,10 @@ nsRange::RegisterCommonAncestor(nsINode* aNode)
|
||||
|
||||
MarkDescendants(aNode);
|
||||
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
|
||||
UniquePtr<nsTHashtable<nsPtrHashKey<nsRange>>>& ranges =
|
||||
aNode->GetCommonAncestorRangesPtr();
|
||||
if (!ranges) {
|
||||
ranges = new RangeHashTable;
|
||||
aNode->SetProperty(nsGkAtoms::range, ranges,
|
||||
nsINode::DeleteProperty<nsRange::RangeHashTable>, true);
|
||||
ranges = MakeUnique<nsRange::RangeHashTable>();
|
||||
}
|
||||
ranges->PutEntry(this);
|
||||
aNode->SetCommonAncestorForRangeInSelection();
|
||||
@ -424,13 +425,14 @@ nsRange::UnregisterCommonAncestor(nsINode* aNode)
|
||||
{
|
||||
NS_PRECONDITION(aNode, "bad arg");
|
||||
NS_ASSERTION(aNode->IsCommonAncestorForRangeInSelection(), "wrong node");
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(aNode->GetProperty(nsGkAtoms::range));
|
||||
nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
|
||||
aNode->GetExistingCommonAncestorRanges();
|
||||
MOZ_ASSERT(ranges);
|
||||
NS_ASSERTION(ranges->GetEntry(this), "unknown range");
|
||||
|
||||
if (ranges->Count() == 1) {
|
||||
aNode->ClearCommonAncestorForRangeInSelection();
|
||||
aNode->DeleteProperty(nsGkAtoms::range);
|
||||
aNode->GetCommonAncestorRangesPtr().reset();
|
||||
UnmarkDescendants(aNode);
|
||||
} else {
|
||||
ranges->RemoveEntry(this);
|
||||
@ -3396,8 +3398,8 @@ nsRange::GetRegisteredCommonAncestor()
|
||||
"GetRegisteredCommonAncestor only valid for range in selection");
|
||||
nsINode* ancestor = GetNextRangeCommonAncestor(mStartContainer);
|
||||
while (ancestor) {
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(ancestor->GetProperty(nsGkAtoms::range));
|
||||
nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
|
||||
ancestor->GetExistingCommonAncestorRanges();
|
||||
if (ranges->GetEntry(this)) {
|
||||
break;
|
||||
}
|
||||
|
@ -393,10 +393,10 @@ protected:
|
||||
/**
|
||||
* For a range for which IsInSelection() is true, return the common
|
||||
* ancestor for the range. This method uses the selection bits and
|
||||
* nsGkAtoms::range property on the nodes to quickly find the ancestor.
|
||||
* That is, it's a faster version of GetCommonAncestor that only works
|
||||
* for ranges in a Selection. The method will assert and the behavior
|
||||
* is undefined if called on a range where IsInSelection() is false.
|
||||
* node slots to quickly find the ancestor. That is, it's a faster
|
||||
* version of GetCommonAncestor that only works for ranges in a
|
||||
* Selection. The method will assert and the behavior is undefined if
|
||||
* called on a range where IsInSelection() is false.
|
||||
*/
|
||||
nsINode* GetRegisteredCommonAncestor();
|
||||
|
||||
|
@ -165,9 +165,8 @@ nsTextNode::List(FILE* out, int32_t aIndent) const
|
||||
fprintf(out, "Text@%p", static_cast<const void*>(this));
|
||||
fprintf(out, " flags=[%08x]", static_cast<unsigned int>(GetFlags()));
|
||||
if (IsCommonAncestorForRangeInSelection()) {
|
||||
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
|
||||
RangeHashTable* ranges =
|
||||
static_cast<RangeHashTable*>(GetProperty(nsGkAtoms::range));
|
||||
const nsTHashtable<nsPtrHashKey<nsRange>>* ranges =
|
||||
GetExistingCommonAncestorRanges();
|
||||
fprintf(out, " ranges:%d", ranges ? ranges->Count() : 0);
|
||||
}
|
||||
fprintf(out, " primaryframe=%p", static_cast<void*>(GetPrimaryFrame()));
|
||||
|
@ -4108,9 +4108,9 @@ void
|
||||
EventStateManager::NotifyMouseOut(WidgetMouseEvent* aMouseEvent,
|
||||
nsIContent* aMovingInto)
|
||||
{
|
||||
OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
|
||||
RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
|
||||
|
||||
if (!wrapper->mLastOverElement)
|
||||
if (!wrapper || !wrapper->mLastOverElement)
|
||||
return;
|
||||
// Before firing mouseout, check for recursion
|
||||
if (wrapper->mLastOverElement == wrapper->mFirstOutEventElement)
|
||||
@ -4176,9 +4176,9 @@ EventStateManager::NotifyMouseOver(WidgetMouseEvent* aMouseEvent,
|
||||
{
|
||||
NS_ASSERTION(aContent, "Mouse must be over something");
|
||||
|
||||
OverOutElementsWrapper* wrapper = GetWrapperByEventID(aMouseEvent);
|
||||
RefPtr<OverOutElementsWrapper> wrapper = GetWrapperByEventID(aMouseEvent);
|
||||
|
||||
if (wrapper->mLastOverElement == aContent)
|
||||
if (!wrapper || wrapper->mLastOverElement == aContent)
|
||||
return;
|
||||
|
||||
// Before firing mouseover, check for recursion
|
||||
@ -4348,7 +4348,7 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
targetElement = mDocument->GetRootElement();
|
||||
}
|
||||
if (targetElement) {
|
||||
OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
|
||||
RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
|
||||
if (helper) {
|
||||
helper->mLastOverElement = targetElement;
|
||||
}
|
||||
@ -4363,8 +4363,8 @@ EventStateManager::GenerateMouseEnterExit(WidgetMouseEvent* aMouseEvent)
|
||||
// This is actually the window mouse exit or pointer leave event. We're not moving
|
||||
// into any new element.
|
||||
|
||||
OverOutElementsWrapper* helper = GetWrapperByEventID(aMouseEvent);
|
||||
if (helper->mLastOverFrame &&
|
||||
RefPtr<OverOutElementsWrapper> helper = GetWrapperByEventID(aMouseEvent);
|
||||
if (helper && helper->mLastOverFrame &&
|
||||
nsContentUtils::GetTopLevelWidget(aMouseEvent->mWidget) !=
|
||||
nsContentUtils::GetTopLevelWidget(helper->mLastOverFrame->GetNearestWidget())) {
|
||||
// the Mouse/PointerOut event widget doesn't have same top widget with
|
||||
|
@ -3520,6 +3520,14 @@ TabChildGlobal::GetDocShell(nsIDocShell** aDocShell)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
TabChildGlobal::GetTabEventTarget(nsIEventTarget** aTarget)
|
||||
{
|
||||
nsCOMPtr<nsIEventTarget> target = EventTargetFor(TaskCategory::Other);
|
||||
target.forget(aTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
TabChildGlobal::GetPrincipal()
|
||||
{
|
||||
|
@ -114,6 +114,7 @@ public:
|
||||
}
|
||||
NS_IMETHOD GetContent(mozIDOMWindowProxy** aContent) override;
|
||||
NS_IMETHOD GetDocShell(nsIDocShell** aDocShell) override;
|
||||
NS_IMETHOD GetTabEventTarget(nsIEventTarget** aTarget) override;
|
||||
|
||||
nsresult AddEventListener(const nsAString& aType,
|
||||
nsIDOMEventListener* aListener,
|
||||
|
@ -384,7 +384,11 @@ PaymentRequest::Show(ErrorResult& aRv)
|
||||
}
|
||||
nsresult rv = manager->ShowPayment(mInternalId);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
promise->MaybeReject(NS_ERROR_FAILURE);
|
||||
if (rv == NS_ERROR_ABORT) {
|
||||
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
|
||||
} else {
|
||||
promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
|
||||
}
|
||||
mState = eClosed;
|
||||
return promise.forget();
|
||||
}
|
||||
|
@ -490,6 +490,9 @@ PaymentRequestManager::CanMakePayment(const nsAString& aRequestId)
|
||||
nsresult
|
||||
PaymentRequestManager::ShowPayment(const nsAString& aRequestId)
|
||||
{
|
||||
if (mShowingRequest) {
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
|
||||
if (!request) {
|
||||
return NS_ERROR_FAILURE;
|
||||
@ -497,8 +500,9 @@ PaymentRequestManager::ShowPayment(const nsAString& aRequestId)
|
||||
|
||||
nsAutoString requestId(aRequestId);
|
||||
IPCPaymentShowActionRequest action(requestId);
|
||||
|
||||
return SendRequestPayment(request, action);
|
||||
nsresult rv = SendRequestPayment(request, action);
|
||||
mShowingRequest = request;
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -593,6 +597,8 @@ PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
|
||||
response.payerEmail(),
|
||||
response.payerPhone());
|
||||
if (!response.isAccepted()) {
|
||||
MOZ_ASSERT(mShowingRequest == request);
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
nsresult rv = ReleasePaymentChild(request);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -609,6 +615,8 @@ PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
|
||||
}
|
||||
request->RespondAbortPayment(response.isSucceeded());
|
||||
if (response.isSucceeded()) {
|
||||
MOZ_ASSERT(mShowingRequest == request);
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
nsresult rv = ReleasePaymentChild(request);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
@ -624,6 +632,8 @@ PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
request->RespondComplete();
|
||||
MOZ_ASSERT(mShowingRequest == request);
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
nsresult rv = ReleasePaymentChild(request);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -79,6 +79,7 @@ private:
|
||||
// The container for the created PaymentRequests
|
||||
nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
|
||||
nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
|
||||
RefPtr<PaymentRequest> mShowingRequest;
|
||||
};
|
||||
|
||||
} // end of namespace dom
|
||||
|
@ -306,11 +306,46 @@ PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
|
||||
* 2. Check third party payment app support by traversing all
|
||||
* registered third party payment apps.
|
||||
*/
|
||||
case nsIPaymentActionRequest::CANMAKE_ACTION:
|
||||
case nsIPaymentActionRequest::CANMAKE_ACTION: {
|
||||
rv = CallTestingUIAction(requestId, type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* TODO: Launch/inform payment UI here once the UI module is implemented.
|
||||
*/
|
||||
case nsIPaymentActionRequest::SHOW_ACTION:
|
||||
case nsIPaymentActionRequest::SHOW_ACTION: {
|
||||
if (mShowingRequest) {
|
||||
nsCOMPtr<nsIPaymentShowActionResponse> showResponse =
|
||||
do_CreateInstance(NS_PAYMENT_SHOW_ACTION_RESPONSE_CONTRACT_ID);
|
||||
MOZ_ASSERT(showResponse);
|
||||
rv = showResponse->Init(requestId,
|
||||
nsIPaymentActionResponse::PAYMENT_REJECTED,
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
EmptyString(),
|
||||
EmptyString());
|
||||
nsCOMPtr<nsIPaymentActionResponse> response = do_QueryInterface(showResponse);
|
||||
MOZ_ASSERT(response);
|
||||
rv = RespondPayment(response);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
rv = GetPaymentRequestById(requestId, getter_AddRefs(mShowingRequest));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = CallTestingUIAction(requestId, type);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIPaymentActionRequest::ABORT_ACTION:
|
||||
case nsIPaymentActionRequest::COMPLETE_ACTION: {
|
||||
rv = CallTestingUIAction(requestId, type);
|
||||
@ -391,11 +426,26 @@ PaymentRequestService::RespondPayment(nsIPaymentActionResponse* aResponse)
|
||||
rv = response->IsSucceeded(&isSucceeded);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (isSucceeded) {
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIPaymentActionResponse::SHOW_ACTION: {
|
||||
nsCOMPtr<nsIPaymentShowActionResponse> response =
|
||||
do_QueryInterface(aResponse);
|
||||
MOZ_ASSERT(response);
|
||||
bool isAccepted;
|
||||
rv = response->IsAccepted(&isAccepted);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!isAccepted) {
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case nsIPaymentActionResponse::COMPLETE_ACTION: {
|
||||
mShowingRequest = nullptr;
|
||||
mRequestQueue.RemoveElement(request);
|
||||
break;
|
||||
}
|
||||
|
@ -51,6 +51,8 @@ private:
|
||||
nsInterfaceHashtable<nsStringHashKey, nsIPaymentActionCallback> mCallbackHashtable;
|
||||
|
||||
nsCOMPtr<nsIPaymentUIService> mTestingUIService;
|
||||
|
||||
nsCOMPtr<nsIPaymentRequest> mShowingRequest;
|
||||
};
|
||||
|
||||
} // end of namespace dom
|
||||
|
@ -106,7 +106,7 @@ Performance::CreateForMainThread(nsPIDOMWindowInner* aWindow,
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
RefPtr<Performance> performance =
|
||||
PerformanceMainThread::Create(aWindow, aDOMTiming, aChannel);
|
||||
new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
|
||||
return performance.forget();
|
||||
}
|
||||
|
||||
@ -277,13 +277,18 @@ Performance::Mark(const nsAString& aName, ErrorResult& aRv)
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsPerformanceTimingAttribute(aName)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<PerformanceMark> performanceMark =
|
||||
new PerformanceMark(GetParentObject(), aName, Now());
|
||||
new PerformanceMark(GetAsISupports(), aName, Now());
|
||||
InsertUserEntry(performanceMark);
|
||||
|
||||
if (profiler_is_active()) {
|
||||
@ -339,6 +344,12 @@ Performance::Measure(const nsAString& aName,
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't add the entry if the buffer is full. XXX should be removed by bug
|
||||
// 1159003.
|
||||
if (mUserEntries.Length() >= mResourceTimingBufferSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
DOMHighResTimeStamp startTime;
|
||||
DOMHighResTimeStamp endTime;
|
||||
|
||||
@ -369,7 +380,7 @@ Performance::Measure(const nsAString& aName,
|
||||
}
|
||||
|
||||
RefPtr<PerformanceMeasure> performanceMeasure =
|
||||
new PerformanceMeasure(GetParentObject(), aName, startTime, endTime);
|
||||
new PerformanceMeasure(GetAsISupports(), aName, startTime, endTime);
|
||||
InsertUserEntry(performanceMeasure);
|
||||
|
||||
if (profiler_is_active()) {
|
||||
@ -567,11 +578,5 @@ Performance::IsObserverEnabled(JSContext* aCx, JSObject* aGlobal)
|
||||
return runnable->Dispatch() && runnable->IsEnabled();
|
||||
}
|
||||
|
||||
void
|
||||
Performance::MemoryPressure()
|
||||
{
|
||||
mUserEntries.Clear();
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
@ -101,11 +101,6 @@ public:
|
||||
|
||||
virtual nsITimedChannel* GetChannel() const = 0;
|
||||
|
||||
void MemoryPressure();
|
||||
|
||||
// This method is currently called only on the main-thread.
|
||||
virtual void Shutdown() {}
|
||||
|
||||
protected:
|
||||
Performance();
|
||||
explicit Performance(nsPIDOMWindowInner* aWindow);
|
||||
@ -121,6 +116,8 @@ protected:
|
||||
DOMHighResTimeStamp ResolveTimestampFromName(const nsAString& aName,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual nsISupports* GetAsISupports() = 0;
|
||||
|
||||
virtual void DispatchBufferFullEvent() = 0;
|
||||
|
||||
virtual TimeStamp CreationTimeStamp() const = 0;
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "PerformanceMainThread.h"
|
||||
#include "PerformanceNavigation.h"
|
||||
#include "nsICacheInfoChannel.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -39,40 +38,18 @@ NS_IMPL_RELEASE_INHERITED(PerformanceMainThread, Performance)
|
||||
// QueryInterface implementation for PerformanceMainThread
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceMainThread)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END_INHERITING(Performance)
|
||||
|
||||
already_AddRefed<PerformanceMainThread>
|
||||
PerformanceMainThread::Create(nsPIDOMWindowInner* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aWindow, "Parent window object should be provided");
|
||||
|
||||
RefPtr<PerformanceMainThread> performance =
|
||||
new PerformanceMainThread(aWindow, aDOMTiming, aChannel);
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (NS_WARN_IF(!obs)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsresult rv = obs->AddObserver(performance, "memory-pressure", false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return performance.forget();
|
||||
}
|
||||
|
||||
PerformanceMainThread::PerformanceMainThread(nsPIDOMWindowInner* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel)
|
||||
: Performance(aWindow)
|
||||
, mDOMTiming(aDOMTiming)
|
||||
, mChannel(aChannel)
|
||||
{}
|
||||
{
|
||||
MOZ_ASSERT(aWindow, "Parent window object should be provided");
|
||||
}
|
||||
|
||||
PerformanceMainThread::~PerformanceMainThread()
|
||||
{
|
||||
@ -360,28 +337,5 @@ PerformanceMainThread::CreationTime() const
|
||||
return GetDOMTiming()->GetNavigationStart();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PerformanceMainThread::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
if (!strcmp(aTopic, "memory-pressure")) {
|
||||
MemoryPressure();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PerformanceMainThread::Shutdown()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "memory-pressure");
|
||||
}
|
||||
}
|
||||
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
|
@ -13,18 +13,16 @@ namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class PerformanceMainThread final : public Performance
|
||||
, public nsIObserver
|
||||
{
|
||||
public:
|
||||
PerformanceMainThread(nsPIDOMWindowInner* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIOBSERVER
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PerformanceMainThread,
|
||||
Performance)
|
||||
|
||||
static already_AddRefed<PerformanceMainThread>
|
||||
Create(nsPIDOMWindowInner* aWindow, nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel);
|
||||
|
||||
virtual PerformanceTiming* Timing() override;
|
||||
|
||||
virtual PerformanceNavigation* Navigation() override;
|
||||
@ -49,15 +47,14 @@ public:
|
||||
return mChannel;
|
||||
}
|
||||
|
||||
void Shutdown() override;
|
||||
|
||||
protected:
|
||||
PerformanceMainThread(nsPIDOMWindowInner* aWindow,
|
||||
nsDOMNavigationTiming* aDOMTiming,
|
||||
nsITimedChannel* aChannel);
|
||||
|
||||
~PerformanceMainThread();
|
||||
|
||||
nsISupports* GetAsISupports() override
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void InsertUserEntry(PerformanceEntry* aEntry) override;
|
||||
|
||||
bool IsPerformanceTimingAttribute(const nsAString& aName) override;
|
||||
|
@ -64,6 +64,11 @@ public:
|
||||
protected:
|
||||
~PerformanceWorker();
|
||||
|
||||
nsISupports* GetAsISupports() override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void InsertUserEntry(PerformanceEntry* aEntry) override;
|
||||
|
||||
void DispatchBufferFullEvent() override
|
||||
|
@ -424,7 +424,7 @@ nsresult nsPluginFile::FreePluginInfo(nsPluginInfo& info)
|
||||
PL_strfree(info.fFileName);
|
||||
|
||||
if (info.fVersion)
|
||||
mozilla::SmprintfFree(info.fVersion);
|
||||
free(info.fVersion);
|
||||
|
||||
ZeroMemory((void *)&info, sizeof(info));
|
||||
|
||||
|
@ -33,7 +33,7 @@ static void LogFunctionAndJSStack(const char* funcname) {
|
||||
"Call to %s. The JS stack is:\n%s\n",
|
||||
funcname,
|
||||
jsstack ? jsstack : "<no JS stack>");
|
||||
JS_smprintf_free(jsstack);
|
||||
js_free(jsstack);
|
||||
}
|
||||
// bug 839452
|
||||
#define LOG_FUNCTION_AND_JS_STACK() \
|
||||
|
@ -22,6 +22,7 @@ support-files =
|
||||
queryCaretRectUnix.html
|
||||
queryCaretRectWin.html
|
||||
selectAtPoint.html
|
||||
selectAtPoint-innerframe.html
|
||||
sizemode_attribute.xul
|
||||
window_activation.xul
|
||||
window_callback_wrapping.xul
|
||||
|
6
dom/tests/mochitest/chrome/selectAtPoint-innerframe.html
Normal file
6
dom/tests/mochitest/chrome/selectAtPoint-innerframe.html
Normal file
@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'>
|
||||
<div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div>
|
||||
<br/><br/>
|
||||
</body>
|
||||
</html>">
|
@ -267,7 +267,7 @@ body {
|
||||
|
||||
<br />
|
||||
|
||||
<iframe id="frame1" src="data:text/html,<html><body style='margin: 0; padding: 0; font-family: monospace;' onload='window.parent.onFrameLoad();'><div id='sel2'>ttestselection2 Lorem ipsum dolor sit amet, at duo debet graeci, vivendum vulputate per ut.</div><br/><br/></body></html>"></iframe>
|
||||
<iframe id="frame1" src="selectAtPoint-innerframe.html"></iframe>
|
||||
|
||||
<br/>
|
||||
|
||||
|
@ -6775,23 +6775,14 @@ WorkerPrivate::MemoryPressureInternal()
|
||||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
if (mScope) {
|
||||
RefPtr<Console> console = mScope->GetConsoleIfExists();
|
||||
if (console) {
|
||||
console->ClearStorage();
|
||||
}
|
||||
|
||||
RefPtr<Performance> performance = mScope->GetPerformanceIfExists();
|
||||
if (performance) {
|
||||
performance->MemoryPressure();
|
||||
}
|
||||
RefPtr<Console> console = mScope ? mScope->GetConsoleIfExists() : nullptr;
|
||||
if (console) {
|
||||
console->ClearStorage();
|
||||
}
|
||||
|
||||
if (mDebuggerScope) {
|
||||
RefPtr<Console> console = mDebuggerScope->GetConsoleIfExists();
|
||||
if (console) {
|
||||
console->ClearStorage();
|
||||
}
|
||||
console = mDebuggerScope ? mDebuggerScope->GetConsoleIfExists() : nullptr;
|
||||
if (console) {
|
||||
console->ClearStorage();
|
||||
}
|
||||
|
||||
for (uint32_t index = 0; index < mChildWorkers.Length(); index++) {
|
||||
|
@ -156,11 +156,6 @@ public:
|
||||
|
||||
Performance* GetPerformance();
|
||||
|
||||
Performance* GetPerformanceIfExists() const
|
||||
{
|
||||
return mPerformance;
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Fetch(const RequestOrUSVString& aInput, const RequestInit& aInit,
|
||||
CallerType aCallerType, ErrorResult& aRv);
|
||||
|
@ -1105,6 +1105,13 @@ CompositorD3D11::EndFrame()
|
||||
return;
|
||||
}
|
||||
|
||||
if (XRE_IsParentProcess() && mDevice->GetDeviceRemovedReason() != S_OK) {
|
||||
gfxCriticalNote << "GFX: D3D11 skip EndFrame with device-removed.";
|
||||
Compositor::EndFrame();
|
||||
mCurrentRT = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
LayoutDeviceIntSize oldSize = mSize;
|
||||
EnsureSize();
|
||||
if (mSize.width <= 0 || mSize.height <= 0) {
|
||||
|
@ -1651,37 +1651,37 @@ MLGDeviceD3D11::DrawInstanced(uint32_t aVertexCountPerInstance, uint32_t aInstan
|
||||
void
|
||||
MLGDeviceD3D11::SetPSTextures(uint32_t aSlot, uint32_t aNumTextures, TextureSource* const* aTextures)
|
||||
{
|
||||
StackArray<ID3D11ShaderResourceView*, 2> textures(aNumTextures);
|
||||
// TextureSource guarantees that the ID3D11ShaderResourceView will be cached,
|
||||
// so we don't hold a RefPtr here.
|
||||
StackArray<ID3D11ShaderResourceView*, 3> views(aNumTextures);
|
||||
|
||||
for (size_t i = 0; i < aNumTextures; i++) {
|
||||
if (!aTextures[i]) {
|
||||
gfxWarning() << "Null TextureRef in SetPSTextures";
|
||||
continue;
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView* view = nullptr;
|
||||
if (TextureSourceD3D11* source = aTextures[i]->AsSourceD3D11()) {
|
||||
ID3D11Texture2D* texture = source->GetD3D11Texture();
|
||||
if (!texture) {
|
||||
gfxWarning() << "No D3D11 texture present in SetPSTextures";
|
||||
continue;
|
||||
}
|
||||
MaybeLockTexture(texture);
|
||||
|
||||
view = source->GetShaderResourceView();
|
||||
} else {
|
||||
gfxWarning() << "Unknown texture type in SetPSTextures";
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!view) {
|
||||
gfxWarning() << "Failed to get shader resource view for texture";
|
||||
continue;
|
||||
}
|
||||
textures[i] = view;
|
||||
views[i] = ResolveTextureSourceForShader(aTextures[i]);
|
||||
}
|
||||
|
||||
mCtx->PSSetShaderResources(aSlot, aNumTextures, textures.data());
|
||||
mCtx->PSSetShaderResources(aSlot, aNumTextures, views.data());
|
||||
}
|
||||
|
||||
ID3D11ShaderResourceView*
|
||||
MLGDeviceD3D11::ResolveTextureSourceForShader(TextureSource* aTexture)
|
||||
{
|
||||
if (!aTexture) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (TextureSourceD3D11* source = aTexture->AsSourceD3D11()) {
|
||||
ID3D11Texture2D* texture = source->GetD3D11Texture();
|
||||
if (!texture) {
|
||||
gfxWarning() << "No D3D11 texture present in SetPSTextures";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MaybeLockTexture(texture);
|
||||
return source->GetShaderResourceView();
|
||||
}
|
||||
|
||||
gfxWarning() << "Unknown texture type in SetPSTextures";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -277,6 +277,10 @@ private:
|
||||
void SetInputLayout(ID3D11InputLayout* aLayout);
|
||||
void SetVertexShader(ID3D11VertexShader* aShader);
|
||||
|
||||
// Resolve a TextureSource to an ID3D11ShaderResourceView, locking the
|
||||
// texture if needed. The lock is released at the end of the frame.
|
||||
ID3D11ShaderResourceView* ResolveTextureSourceForShader(TextureSource* aSource);
|
||||
|
||||
private:
|
||||
RefPtr<ID3D11Device> mDevice;
|
||||
RefPtr<ID3D11DeviceContext> mCtx;
|
||||
|
@ -1662,7 +1662,7 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
|
||||
CrossProcessCompositorBridgeParent* cpcp = sIndirectLayerTrees[child].mCrossProcessParent;
|
||||
if (cpcp) {
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
cpcp->DidComposite(child, now, now);
|
||||
cpcp->DidCompositeLocked(child, now, now);
|
||||
}
|
||||
}
|
||||
parent = sIndirectLayerTrees[child].mApzcTreeManagerParent;
|
||||
@ -2005,7 +2005,7 @@ CompositorBridgeParent::NotifyDidComposite(uint64_t aTransactionId, TimeStamp& a
|
||||
ForEachIndirectLayerTree([&] (LayerTreeState* lts, const uint64_t& aLayersId) -> void {
|
||||
if (lts->mCrossProcessParent && lts->mParent == this) {
|
||||
CrossProcessCompositorBridgeParent* cpcp = lts->mCrossProcessParent;
|
||||
cpcp->DidComposite(aLayersId, aCompositeStart, aCompositeEnd);
|
||||
cpcp->DidCompositeLocked(aLayersId, aCompositeStart, aCompositeEnd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -361,6 +361,16 @@ CrossProcessCompositorBridgeParent::DidComposite(
|
||||
uint64_t aId,
|
||||
TimeStamp& aCompositeStart,
|
||||
TimeStamp& aCompositeEnd)
|
||||
{
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
DidCompositeLocked(aId, aCompositeStart, aCompositeEnd);
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessCompositorBridgeParent::DidCompositeLocked(
|
||||
uint64_t aId,
|
||||
TimeStamp& aCompositeStart,
|
||||
TimeStamp& aCompositeEnd)
|
||||
{
|
||||
sIndirectLayerTreesLock->AssertCurrentThreadOwns();
|
||||
if (LayerTransactionParent *layerTree = sIndirectLayerTrees[aId].mLayerTree) {
|
||||
|
@ -107,6 +107,12 @@ public:
|
||||
virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aParent) override;
|
||||
virtual mozilla::ipc::IPCResult RecvRemotePluginsReady() override { return IPC_FAIL_NO_REASON(this); }
|
||||
|
||||
// Use DidCompositeLocked if you already hold a lock on
|
||||
// sIndirectLayerTreesLock; Otherwise use DidComposite, which would request
|
||||
// the lock automatically.
|
||||
void DidCompositeLocked(uint64_t aId,
|
||||
TimeStamp& aCompositeStart,
|
||||
TimeStamp& aCompositeEnd);
|
||||
virtual void DidComposite(uint64_t aId,
|
||||
TimeStamp& aCompositeStart,
|
||||
TimeStamp& aCompositeEnd) override;
|
||||
|
@ -69,7 +69,9 @@ imgRequest::imgRequest(imgLoader* aLoader, const ImageCacheKey& aCacheKey)
|
||||
, mDecodeRequested(false)
|
||||
, mNewPartPending(false)
|
||||
, mHadInsecureRedirect(false)
|
||||
{ }
|
||||
{
|
||||
LOG_FUNC(gImgLog, "imgRequest::imgRequest()");
|
||||
}
|
||||
|
||||
imgRequest::~imgRequest()
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ imgRequestProxy::imgRequestProxy() :
|
||||
mHadDispatch(false)
|
||||
{
|
||||
/* member initializers and constructor code */
|
||||
|
||||
LOG_FUNC(gImgLog, "imgRequestProxy::imgRequestProxy");
|
||||
}
|
||||
|
||||
imgRequestProxy::~imgRequestProxy()
|
||||
@ -169,6 +169,8 @@ imgRequestProxy::~imgRequestProxy()
|
||||
mCanceled = true;
|
||||
GetOwner()->RemoveProxy(this, NS_OK);
|
||||
}
|
||||
|
||||
LOG_FUNC(gImgLog, "imgRequestProxy::~imgRequestProxy");
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
@ -168,6 +168,11 @@ MessageLoop* MessageLoop::current() {
|
||||
return get_tls_ptr().Get();
|
||||
}
|
||||
|
||||
// static
|
||||
void MessageLoop::set_current(MessageLoop* loop) {
|
||||
get_tls_ptr().Set(loop);
|
||||
}
|
||||
|
||||
static mozilla::Atomic<int32_t> message_loop_id_seq(0);
|
||||
|
||||
MessageLoop::MessageLoop(Type type, nsIThread* aThread)
|
||||
|
@ -219,6 +219,8 @@ public:
|
||||
// Returns the MessageLoop object for the current thread, or null if none.
|
||||
static MessageLoop* current();
|
||||
|
||||
static void set_current(MessageLoop* loop);
|
||||
|
||||
// Enables or disables the recursive task processing. This happens in the case
|
||||
// of recursive message loops. Some unwanted message loop may occurs when
|
||||
// using common controls or printer functions. By default, recursive task
|
||||
|
@ -17,18 +17,14 @@
|
||||
#include "mozilla/BufferList.h"
|
||||
#include "mozilla/mozalloc.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
|
||||
#ifdef FUZZING
|
||||
#include "base/singleton.h"
|
||||
#include "mozilla/ipc/Faulty.h"
|
||||
#endif
|
||||
|
||||
#if !defined(RELEASE_OR_BETA) || defined(DEBUG)
|
||||
#if (!defined(RELEASE_OR_BETA) && !defined(FUZZING)) || defined(DEBUG)
|
||||
#define MOZ_PICKLE_SENTINEL_CHECKING
|
||||
#endif
|
||||
|
||||
class Pickle;
|
||||
|
||||
class PickleIterator {
|
||||
public:
|
||||
explicit PickleIterator(const Pickle& pickle);
|
||||
|
@ -72,6 +72,8 @@ ProcessLink::~ProcessLink()
|
||||
void
|
||||
ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Side aSide)
|
||||
{
|
||||
mChan->AssertWorkerThread();
|
||||
|
||||
NS_PRECONDITION(aTransport, "need transport layer");
|
||||
|
||||
// FIXME need to check for valid channel
|
||||
@ -130,8 +132,12 @@ ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Sid
|
||||
&ProcessLink::OnTakeConnectedChannel));
|
||||
}
|
||||
|
||||
// Should not wait here if something goes wrong with the channel.
|
||||
while (!mChan->Connected() && mChan->mChannelState != ChannelError) {
|
||||
// Wait until one of the runnables above changes the state of the
|
||||
// channel. Note that the state could be changed again after that (to
|
||||
// ChannelClosing, for example, by the IO thread). We can rely on it not
|
||||
// changing back to Closed: only the worker thread changes it to closed,
|
||||
// and we're on the worker thread, blocked.
|
||||
while (mChan->mChannelState == ChannelClosed) {
|
||||
mChan->mMonitor->Wait();
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/BufferList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@ -339,6 +340,16 @@ class JS_PUBLIC_API(JSAutoStructuredCloneBuffer) {
|
||||
JS::CloneDataPolicy cloneDataPolicy,
|
||||
const JSStructuredCloneCallbacks* optionalCallbacks=nullptr, void* closure=nullptr);
|
||||
|
||||
size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
return data_.SizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
|
||||
}
|
||||
|
||||
private:
|
||||
// Copy and assignment are not supported.
|
||||
JSAutoStructuredCloneBuffer(const JSAutoStructuredCloneBuffer& other) = delete;
|
||||
|
@ -23,7 +23,6 @@ namespace JS {
|
||||
_(GetProp_DefiniteSlot) \
|
||||
_(GetProp_Unboxed) \
|
||||
_(GetProp_CommonGetter) \
|
||||
_(GetProp_Static) \
|
||||
_(GetProp_InlineAccess) \
|
||||
_(GetProp_Innerize) \
|
||||
_(GetProp_InlineCache) \
|
||||
|
@ -9516,15 +9516,6 @@ BytecodeEmitter::emitCallOrNew(ParseNode* pn, ValueUsage valueUsage /* = ValueUs
|
||||
if (pn2->as<PropertyAccess>().isSuper()) {
|
||||
if (!emitSuperPropOp(pn2, JSOP_GETPROP_SUPER, /* isCall = */ callop))
|
||||
return false;
|
||||
} else if ((pn->getOp() == JSOP_FUNCALL || pn->getOp() == JSOP_FUNAPPLY) &&
|
||||
pn2->expr()->getKind() == PNK_FUNCTION &&
|
||||
checkRunOnceContext()) {
|
||||
// Top level lambdas whose .call or .apply methods are immediately
|
||||
// invoked should be treated as run once lambdas.
|
||||
emittingRunOnceLambda = true;
|
||||
if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
|
||||
return false;
|
||||
emittingRunOnceLambda = false;
|
||||
} else {
|
||||
if (!emitPropOp(pn2, callop ? JSOP_CALLPROP : JSOP_GETPROP))
|
||||
return false;
|
||||
|
@ -362,9 +362,6 @@ js::gc::GCRuntime::traceRuntimeCommon(JSTracer* trc, TraceOrMarkRuntime traceOrM
|
||||
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next())
|
||||
c->traceRoots(trc, traceOrMark);
|
||||
|
||||
// Trace the Gecko Profiler.
|
||||
rt->geckoProfiler().trace(trc);
|
||||
|
||||
// Trace helper thread roots.
|
||||
HelperThreadState().trace(trc);
|
||||
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "jit/IonBuilder.h"
|
||||
#include "jit/JitCompartment.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
namespace js {
|
||||
|
||||
ZoneGroup::ZoneGroup(JSRuntime* runtime)
|
||||
@ -147,3 +149,26 @@ ZoneGroup::deleteEmptyZone(Zone* zone)
|
||||
}
|
||||
|
||||
} // namespace js
|
||||
|
||||
JS::AutoRelinquishZoneGroups::AutoRelinquishZoneGroups(JSContext* cx)
|
||||
: cx(cx)
|
||||
{
|
||||
MOZ_ASSERT(cx == TlsContext.get());
|
||||
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
for (ZoneGroupsIter group(cx->runtime()); !group.done(); group.next()) {
|
||||
while (group->ownerContext().context() == cx) {
|
||||
group->leave();
|
||||
if (!enterList.append(group))
|
||||
oomUnsafe.crash("AutoRelinquishZoneGroups");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::AutoRelinquishZoneGroups::~AutoRelinquishZoneGroups()
|
||||
{
|
||||
for (size_t i = 0; i < enterList.length(); i++) {
|
||||
ZoneGroup* group = static_cast<ZoneGroup*>(enterList[i]);
|
||||
group->enter(cx);
|
||||
}
|
||||
}
|
||||
|
@ -1,28 +0,0 @@
|
||||
// Test bailouts from loading particular non-singleton static objects.
|
||||
|
||||
function wrap(fun) {
|
||||
function wrapper() {
|
||||
return fun.apply(this, arguments);
|
||||
}
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
var adder = wrap(function(a, b) { return a + b; });
|
||||
var subber = wrap(function(a, b) { return a - b; });
|
||||
var tmp = adder;
|
||||
adder = subber;
|
||||
adder = tmp;
|
||||
|
||||
function foo() {
|
||||
var i = 0;
|
||||
var a = 0;
|
||||
for (var i = 0; i < 10000; i++) {
|
||||
a = adder(a, 1);
|
||||
a = subber(a, 1);
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
assertEq(foo(), 0);
|
||||
adder = subber;
|
||||
assertEq(foo(), -20000);
|
34
js/src/jit-test/tests/ion/idempotentCache.js
Normal file
34
js/src/jit-test/tests/ion/idempotentCache.js
Normal file
@ -0,0 +1,34 @@
|
||||
// Test that we don't attach ICs to idempotent caches that are incompatible
|
||||
// with the cache result type.
|
||||
|
||||
var missingObjs = [{a:1},Object.create({a:2}),{}];
|
||||
function testMissing(limit)
|
||||
{
|
||||
var res = 0;
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
for (var j = 0; j < missingObjs.length; j++) {
|
||||
var obj = missingObjs[j];
|
||||
if (j < limit)
|
||||
res += obj.a;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
assertEq(testMissing(2), 3000);
|
||||
assertEq(testMissing(3), NaN);
|
||||
|
||||
var lengthObjs = [{length:{a:1}},Object.create({length:{a:2}}),[0,1]];
|
||||
function testArrayLength(limit)
|
||||
{
|
||||
var res = 0;
|
||||
for (var i = 0; i < 1000; i++) {
|
||||
for (var j = 0; j < lengthObjs.length; j++) {
|
||||
var obj = lengthObjs[j];
|
||||
if (j < limit)
|
||||
res += obj.length.a;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
assertEq(testArrayLength(2), 3000);
|
||||
assertEq(testArrayLength(3), NaN);
|
@ -2003,7 +2003,6 @@ jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfo)
|
||||
case Bailout_Debugger:
|
||||
case Bailout_UninitializedThis:
|
||||
case Bailout_BadDerivedConstructorReturn:
|
||||
case Bailout_LoadStaticObject:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
|
@ -4808,7 +4808,8 @@ BaselineCompiler::emit_JSOP_RESUME()
|
||||
Label skip;
|
||||
AbsoluteAddress addressOfEnabled(cx->runtime()->geckoProfiler().addressOfEnabled());
|
||||
masm.branch32(Assembler::Equal, addressOfEnabled, Imm32(0), &skip);
|
||||
masm.loadPtr(AbsoluteAddress(cx->addressOfProfilingActivation()), scratchReg);
|
||||
masm.loadJSContext(scratchReg);
|
||||
masm.loadPtr(Address(scratchReg, JSContext::offsetOfProfilingActivation()), scratchReg);
|
||||
masm.storePtr(masm.getStackPointer(),
|
||||
Address(scratchReg, JitActivation::offsetOfLastProfilingFrame()));
|
||||
masm.bind(&skip);
|
||||
|
@ -810,8 +810,10 @@ DoGetElemFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback* stub_
|
||||
|
||||
if (stub->state().canAttachStub()) {
|
||||
ICStubEngine engine = ICStubEngine::Baseline;
|
||||
GetPropIRGenerator gen(cx, script, pc, CacheKind::GetElem, stub->state().mode(),
|
||||
&isTemporarilyUnoptimizable, lhs, rhs, lhs, CanAttachGetter::Yes);
|
||||
GetPropIRGenerator gen(cx, script, pc,
|
||||
CacheKind::GetElem, stub->state().mode(),
|
||||
&isTemporarilyUnoptimizable, lhs, rhs, lhs,
|
||||
GetPropertyResultFlags::All);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
BaselineCacheIRStubKind::Monitored,
|
||||
@ -884,7 +886,7 @@ DoGetElemSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetElem_Fallback*
|
||||
ICStubEngine engine = ICStubEngine::Baseline;
|
||||
GetPropIRGenerator gen(cx, script, pc, CacheKind::GetElemSuper, stub->state().mode(),
|
||||
&isTemporarilyUnoptimizable, lhs, rhs, receiver,
|
||||
CanAttachGetter::Yes);
|
||||
GetPropertyResultFlags::All);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
BaselineCacheIRStubKind::Monitored,
|
||||
|
@ -1040,7 +1040,7 @@ bool
|
||||
BaselineInspector::megamorphicGetterSetterFunction(jsbytecode* pc, bool isGetter,
|
||||
JSFunction** getterOrSetter)
|
||||
{
|
||||
if (!hasBaselineScript() || *pc == JSOP_SETALIASEDVAR)
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
*getterOrSetter = nullptr;
|
||||
@ -1191,7 +1191,7 @@ BaselineInspector::commonSetPropFunction(jsbytecode* pc, JSObject** holder, Shap
|
||||
ReceiverVector& receivers,
|
||||
ObjectGroupVector& convertUnboxedGroups)
|
||||
{
|
||||
if (!hasBaselineScript() || *pc == JSOP_SETALIASEDVAR)
|
||||
if (!hasBaselineScript())
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(receivers.empty());
|
||||
|
@ -1266,8 +1266,10 @@ jit::MarkActiveBaselineScripts(Zone* zone)
|
||||
if (zone->isAtomsZone())
|
||||
return;
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (JitActivationIterator iter(cx, zone->group()->ownerContext()); !iter.done(); ++iter) {
|
||||
if (iter->compartment()->zone() == zone)
|
||||
MarkActiveBaselineScripts(cx, iter);
|
||||
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
|
||||
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
|
||||
if (iter->compartment()->zone() == zone)
|
||||
MarkActiveBaselineScripts(cx, iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -48,13 +48,13 @@ GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, HandleScript script, jsbyt
|
||||
CacheKind cacheKind, ICState::Mode mode,
|
||||
bool* isTemporarilyUnoptimizable, HandleValue val,
|
||||
HandleValue idVal, HandleValue receiver,
|
||||
CanAttachGetter canAttachGetter)
|
||||
GetPropertyResultFlags resultFlags)
|
||||
: IRGenerator(cx, script, pc, cacheKind, mode),
|
||||
val_(val),
|
||||
idVal_(idVal),
|
||||
receiver_(receiver),
|
||||
isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
|
||||
canAttachGetter_(canAttachGetter),
|
||||
resultFlags_(resultFlags),
|
||||
preliminaryObjectAction_(PreliminaryObjectAction::None)
|
||||
{}
|
||||
|
||||
@ -247,11 +247,9 @@ GetPropIRGenerator::tryAttachStub()
|
||||
bool
|
||||
GetPropIRGenerator::tryAttachIdempotentStub()
|
||||
{
|
||||
// For idempotent ICs, only attach stubs for plain data properties.
|
||||
// This ensures (1) the lookup has no side-effects and (2) Ion has complete
|
||||
// static type information and we don't have to monitor the result. Because
|
||||
// of (2), we don't support for instance missing properties or array
|
||||
// lengths, as TI does not account for these cases.
|
||||
// For idempotent ICs, only attach stubs which we can be sure have no side
|
||||
// effects and produce a result which the MIR in the calling code is able
|
||||
// to handle, since we do not have a pc to explicitly monitor the result.
|
||||
|
||||
MOZ_ASSERT(idempotent());
|
||||
|
||||
@ -263,6 +261,10 @@ GetPropIRGenerator::tryAttachIdempotentStub()
|
||||
if (tryAttachNative(obj, objId, id))
|
||||
return true;
|
||||
|
||||
// Object lengths are supported only if int32 results are allowed.
|
||||
if ((resultFlags_ & GetPropertyResultFlags::AllowInt32) && tryAttachObjectLength(obj, objId, id))
|
||||
return true;
|
||||
|
||||
// Also support native data properties on DOMProxy prototypes.
|
||||
if (GetProxyStubType(cx_, obj, id) == ProxyStubType::DOMUnshadowed)
|
||||
return tryAttachDOMProxyUnshadowed(obj, objId, id);
|
||||
@ -272,22 +274,23 @@ GetPropIRGenerator::tryAttachIdempotentStub()
|
||||
|
||||
static bool
|
||||
IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
|
||||
jsbytecode* pc)
|
||||
jsbytecode* pc, GetPropertyResultFlags resultFlags)
|
||||
{
|
||||
if (shape)
|
||||
return false;
|
||||
|
||||
MOZ_ASSERT(!holder);
|
||||
|
||||
if (!pc) {
|
||||
// This is an idempotent IC, don't attach a missing-property stub.
|
||||
// See tryAttachStub.
|
||||
// Idempotent ICs may only attach missing-property stubs if undefined
|
||||
// results are explicitly allowed, since no monitoring is done of the
|
||||
// cache result.
|
||||
if (!pc && !(resultFlags & GetPropertyResultFlags::AllowUndefined))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we're doing a name lookup, we have to throw a ReferenceError. If
|
||||
// extra warnings are enabled, we may have to report a warning.
|
||||
if (*pc == JSOP_GETBOUNDNAME || cx->compartment()->behaviors().extraWarnings(cx))
|
||||
// Note that Ion does not generate idempotent caches for JSOP_GETBOUNDNAME.
|
||||
if ((pc && *pc == JSOP_GETBOUNDNAME) || cx->compartment()->behaviors().extraWarnings(cx))
|
||||
return false;
|
||||
|
||||
return CheckHasNoSuchProperty(cx, obj, id);
|
||||
@ -302,7 +305,7 @@ enum NativeGetPropCacheability {
|
||||
static NativeGetPropCacheability
|
||||
CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
|
||||
MutableHandleNativeObject holder, MutableHandleShape shape,
|
||||
jsbytecode* pc, CanAttachGetter canAttachGetter,
|
||||
jsbytecode* pc, GetPropertyResultFlags resultFlags,
|
||||
bool* isTemporarilyUnoptimizable)
|
||||
{
|
||||
MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_SYMBOL(id));
|
||||
@ -327,22 +330,17 @@ CanAttachNativeGetProp(JSContext* cx, HandleObject obj, HandleId id,
|
||||
if (IsCacheableGetPropReadSlotForIonOrCacheIR(obj, holder, prop))
|
||||
return CanAttachReadSlot;
|
||||
|
||||
// Idempotent ICs only support plain data properties, see
|
||||
// tryAttachIdempotentStub.
|
||||
if (!pc)
|
||||
return CanAttachNone;
|
||||
|
||||
if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc))
|
||||
if (IsCacheableNoProperty(cx, obj, holder, shape, id, pc, resultFlags))
|
||||
return CanAttachReadSlot;
|
||||
|
||||
if (canAttachGetter == CanAttachGetter::No)
|
||||
return CanAttachNone;
|
||||
// Idempotent ICs cannot call getters, see tryAttachIdempotentStub.
|
||||
if (pc && (resultFlags & GetPropertyResultFlags::Monitored)) {
|
||||
if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable))
|
||||
return CanAttachCallGetter;
|
||||
|
||||
if (IsCacheableGetPropCallScripted(obj, holder, shape, isTemporarilyUnoptimizable))
|
||||
return CanAttachCallGetter;
|
||||
|
||||
if (IsCacheableGetPropCallNative(obj, holder, shape))
|
||||
return CanAttachCallGetter;
|
||||
if (IsCacheableGetPropCallNative(obj, holder, shape))
|
||||
return CanAttachCallGetter;
|
||||
}
|
||||
|
||||
return CanAttachNone;
|
||||
}
|
||||
@ -582,10 +580,8 @@ GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId, Handle
|
||||
RootedNativeObject holder(cx_);
|
||||
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
|
||||
canAttachGetter_,
|
||||
resultFlags_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
MOZ_ASSERT_IF(idempotent(),
|
||||
type == CanAttachNone || (type == CanAttachReadSlot && holder));
|
||||
switch (type) {
|
||||
case CanAttachNone:
|
||||
return false;
|
||||
@ -613,6 +609,7 @@ GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId, Handle
|
||||
return true;
|
||||
case CanAttachCallGetter: {
|
||||
// |super.prop| accesses use a |this| value that differs from lookup object
|
||||
MOZ_ASSERT(!idempotent());
|
||||
ObjOperandId receiverId = isSuper() ? writer.guardIsObject(getSuperReceiverValueId())
|
||||
: objId;
|
||||
maybeEmitIdGuard(id);
|
||||
@ -651,7 +648,7 @@ GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, H
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
|
||||
canAttachGetter_,
|
||||
resultFlags_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
switch (type) {
|
||||
case CanAttachNone:
|
||||
@ -738,8 +735,8 @@ GetPropIRGenerator::tryAttachCrossCompartmentWrapper(HandleObject obj, ObjOperan
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability canCache =
|
||||
CanAttachNativeGetProp(cx_, unwrapped, id, &holder, &shape, pc_, canAttachGetter_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
CanAttachNativeGetProp(cx_, unwrapped, id, &holder, &shape, pc_,
|
||||
resultFlags_, isTemporarilyUnoptimizable_);
|
||||
if (canCache != CanAttachReadSlot)
|
||||
return false;
|
||||
|
||||
@ -963,7 +960,7 @@ GetPropIRGenerator::tryAttachDOMProxyExpando(HandleObject obj, ObjOperandId objI
|
||||
RootedShape propShape(cx_);
|
||||
NativeGetPropCacheability canCache =
|
||||
CanAttachNativeGetProp(cx_, expandoObj, id, &holder, &propShape, pc_,
|
||||
canAttachGetter_, isTemporarilyUnoptimizable_);
|
||||
resultFlags_, isTemporarilyUnoptimizable_);
|
||||
if (canCache != CanAttachReadSlot && canCache != CanAttachCallGetter)
|
||||
return false;
|
||||
if (!holder)
|
||||
@ -1054,10 +1051,8 @@ GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId o
|
||||
RootedNativeObject holder(cx_);
|
||||
RootedShape shape(cx_);
|
||||
NativeGetPropCacheability canCache = CanAttachNativeGetProp(cx_, checkObj, id, &holder, &shape,
|
||||
pc_, canAttachGetter_,
|
||||
pc_, resultFlags_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
MOZ_ASSERT_IF(idempotent(),
|
||||
canCache == CanAttachNone || (canCache == CanAttachReadSlot && holder));
|
||||
if (canCache == CanAttachNone)
|
||||
return false;
|
||||
|
||||
@ -1394,7 +1389,7 @@ GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId, HandleId id)
|
||||
RootedShape shape(cx_);
|
||||
RootedNativeObject holder(cx_);
|
||||
NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, proto, id, &holder, &shape, pc_,
|
||||
canAttachGetter_,
|
||||
resultFlags_,
|
||||
isTemporarilyUnoptimizable_);
|
||||
if (type != CanAttachReadSlot)
|
||||
return false;
|
||||
|
@ -1147,7 +1147,38 @@ class MOZ_RAII IRGenerator
|
||||
CacheKind cacheKind() const { return cacheKind_; }
|
||||
};
|
||||
|
||||
enum class CanAttachGetter { Yes, No };
|
||||
// Flags used to describe what values a GetProperty cache may produce.
|
||||
enum class GetPropertyResultFlags {
|
||||
None = 0,
|
||||
|
||||
// Values produced by this cache will go through a type barrier,
|
||||
// so the cache may produce any type of value that is compatible with its
|
||||
// result operand.
|
||||
Monitored = 1 << 0,
|
||||
|
||||
// Whether particular primitives may be produced by this cache.
|
||||
AllowUndefined = 1 << 1,
|
||||
AllowInt32 = 1 << 2,
|
||||
AllowDouble = 1 << 3,
|
||||
|
||||
All = Monitored | AllowUndefined | AllowInt32 | AllowDouble
|
||||
};
|
||||
|
||||
static inline bool operator&(GetPropertyResultFlags a, GetPropertyResultFlags b)
|
||||
{
|
||||
return static_cast<int>(a) & static_cast<int>(b);
|
||||
}
|
||||
|
||||
static inline GetPropertyResultFlags operator|(GetPropertyResultFlags a, GetPropertyResultFlags b)
|
||||
{
|
||||
return static_cast<GetPropertyResultFlags>(static_cast<int>(a) | static_cast<int>(b));
|
||||
}
|
||||
|
||||
static inline GetPropertyResultFlags& operator|=(GetPropertyResultFlags& lhs, GetPropertyResultFlags b)
|
||||
{
|
||||
lhs = lhs | b;
|
||||
return lhs;
|
||||
}
|
||||
|
||||
// GetPropIRGenerator generates CacheIR for a GetProp IC.
|
||||
class MOZ_RAII GetPropIRGenerator : public IRGenerator
|
||||
@ -1156,7 +1187,7 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
|
||||
HandleValue idVal_;
|
||||
HandleValue receiver_;
|
||||
bool* isTemporarilyUnoptimizable_;
|
||||
CanAttachGetter canAttachGetter_;
|
||||
GetPropertyResultFlags resultFlags_;
|
||||
|
||||
enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
|
||||
PreliminaryObjectAction preliminaryObjectAction_;
|
||||
@ -1233,7 +1264,8 @@ class MOZ_RAII GetPropIRGenerator : public IRGenerator
|
||||
public:
|
||||
GetPropIRGenerator(JSContext* cx, HandleScript script, jsbytecode* pc, CacheKind cacheKind,
|
||||
ICState::Mode mode, bool* isTemporarilyUnoptimizable, HandleValue val,
|
||||
HandleValue idVal, HandleValue receiver, CanAttachGetter canAttachGetter);
|
||||
HandleValue idVal, HandleValue receiver,
|
||||
GetPropertyResultFlags resultFlags);
|
||||
|
||||
bool tryAttachStub();
|
||||
bool tryAttachIdempotentStub();
|
||||
|
@ -10285,7 +10285,7 @@ void
|
||||
CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
|
||||
TypedOrValueRegister value, const ConstantOrRegister& id,
|
||||
TypedOrValueRegister output, Register maybeTemp,
|
||||
bool monitoredResult, bool allowDoubleResult,
|
||||
GetPropertyResultFlags resultFlags,
|
||||
jsbytecode* profilerLeavePc)
|
||||
{
|
||||
CacheKind kind = CacheKind::GetElem;
|
||||
@ -10295,8 +10295,7 @@ CodeGenerator::addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
|
||||
if (idString->isAtom() && !idString->asAtom().isIndex(&dummy))
|
||||
kind = CacheKind::GetProp;
|
||||
}
|
||||
IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, monitoredResult,
|
||||
allowDoubleResult);
|
||||
IonGetPropertyIC cache(kind, liveRegs, value, id, output, maybeTemp, resultFlags);
|
||||
addIC(ins, allocateIC(cache));
|
||||
}
|
||||
|
||||
@ -10333,6 +10332,35 @@ CodeGenerator::toConstantOrRegister(LInstruction* lir, size_t n, MIRType type)
|
||||
return TypedOrValueRegister(type, ToAnyRegister(value));
|
||||
}
|
||||
|
||||
static GetPropertyResultFlags
|
||||
IonGetPropertyICFlags(const MGetPropertyCache* mir)
|
||||
{
|
||||
GetPropertyResultFlags flags = GetPropertyResultFlags::None;
|
||||
if (mir->monitoredResult())
|
||||
flags |= GetPropertyResultFlags::Monitored;
|
||||
|
||||
if (mir->type() == MIRType::Value) {
|
||||
if (TemporaryTypeSet* types = mir->resultTypeSet()) {
|
||||
if (types->hasType(TypeSet::UndefinedType()))
|
||||
flags |= GetPropertyResultFlags::AllowUndefined;
|
||||
if (types->hasType(TypeSet::Int32Type()))
|
||||
flags |= GetPropertyResultFlags::AllowInt32;
|
||||
if (types->hasType(TypeSet::DoubleType()))
|
||||
flags |= GetPropertyResultFlags::AllowDouble;
|
||||
} else {
|
||||
flags |= GetPropertyResultFlags::AllowUndefined
|
||||
| GetPropertyResultFlags::AllowInt32
|
||||
| GetPropertyResultFlags::AllowDouble;
|
||||
}
|
||||
} else if (mir->type() == MIRType::Int32) {
|
||||
flags |= GetPropertyResultFlags::AllowInt32;
|
||||
} else if (mir->type() == MIRType::Double) {
|
||||
flags |= GetPropertyResultFlags::AllowInt32 | GetPropertyResultFlags::AllowDouble;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
void
|
||||
CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
|
||||
{
|
||||
@ -10340,12 +10368,11 @@ CodeGenerator::visitGetPropertyCacheV(LGetPropertyCacheV* ins)
|
||||
TypedOrValueRegister value =
|
||||
toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
|
||||
ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheV::Id, ins->mir()->idval()->type());
|
||||
bool monitoredResult = ins->mir()->monitoredResult();
|
||||
TypedOrValueRegister output = TypedOrValueRegister(GetValueOutput(ins));
|
||||
Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
|
||||
|
||||
addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
|
||||
ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
|
||||
addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp,
|
||||
IonGetPropertyICFlags(ins->mir()), ins->mir()->profilerLeavePc());
|
||||
}
|
||||
|
||||
void
|
||||
@ -10355,12 +10382,11 @@ CodeGenerator::visitGetPropertyCacheT(LGetPropertyCacheT* ins)
|
||||
TypedOrValueRegister value =
|
||||
toConstantOrRegister(ins, LGetPropertyCacheV::Value, ins->mir()->value()->type()).reg();
|
||||
ConstantOrRegister id = toConstantOrRegister(ins, LGetPropertyCacheT::Id, ins->mir()->idval()->type());
|
||||
bool monitoredResult = ins->mir()->monitoredResult();
|
||||
TypedOrValueRegister output(ins->mir()->type(), ToAnyRegister(ins->getDef(0)));
|
||||
Register maybeTemp = ins->temp()->isBogusTemp() ? InvalidReg : ToRegister(ins->temp());
|
||||
|
||||
addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp, monitoredResult,
|
||||
ins->mir()->allowDoubleResult(), ins->mir()->profilerLeavePc());
|
||||
addGetPropertyCache(ins, liveRegs, value, id, output, maybeTemp,
|
||||
IonGetPropertyICFlags(ins->mir()), ins->mir()->profilerLeavePc());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -7,6 +7,7 @@
|
||||
#ifndef jit_CodeGenerator_h
|
||||
#define jit_CodeGenerator_h
|
||||
|
||||
#include "jit/CacheIR.h"
|
||||
#include "jit/IonCaches.h"
|
||||
#if defined(JS_ION_PERF)
|
||||
# include "jit/PerfSpewer.h"
|
||||
@ -468,8 +469,8 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||
private:
|
||||
void addGetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs,
|
||||
TypedOrValueRegister value, const ConstantOrRegister& id,
|
||||
TypedOrValueRegister output, Register maybeTemp, bool monitoredResult,
|
||||
bool allowDoubleResult, jsbytecode* profilerLeavePc);
|
||||
TypedOrValueRegister output, Register maybeTemp,
|
||||
GetPropertyResultFlags flags, jsbytecode* profilerLeavePc);
|
||||
void addSetPropertyCache(LInstruction* ins, LiveRegisterSet liveRegs, Register objReg,
|
||||
Register temp, FloatRegister tempDouble,
|
||||
FloatRegister tempF32, const ConstantOrRegister& id,
|
||||
|
@ -37,7 +37,7 @@ CompileRuntime::jitRuntime()
|
||||
return runtime()->jitRuntime();
|
||||
}
|
||||
|
||||
GeckoProfiler&
|
||||
GeckoProfilerRuntime&
|
||||
CompileRuntime::geckoProfiler()
|
||||
{
|
||||
return runtime()->geckoProfiler();
|
||||
|
@ -34,7 +34,7 @@ class CompileRuntime
|
||||
const JitRuntime* jitRuntime();
|
||||
|
||||
// Compilation does not occur off thread when the Gecko Profiler is enabled.
|
||||
GeckoProfiler& geckoProfiler();
|
||||
GeckoProfilerRuntime& geckoProfiler();
|
||||
|
||||
bool jitSupportsFloatingPoint();
|
||||
bool hadOutOfMemory();
|
||||
|
@ -3125,10 +3125,12 @@ jit::InvalidateAll(FreeOp* fop, Zone* zone)
|
||||
if (zone->isAtomsZone())
|
||||
return;
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (JitActivationIterator iter(cx, zone->group()->ownerContext()); !iter.done(); ++iter) {
|
||||
if (iter->compartment()->zone() == zone) {
|
||||
JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
|
||||
InvalidateActivation(fop, iter, true);
|
||||
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
|
||||
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter) {
|
||||
if (iter->compartment()->zone() == zone) {
|
||||
JitSpew(JitSpew_IonInvalidate, "Invalidating all frames for GC");
|
||||
InvalidateActivation(fop, iter, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3179,8 +3181,10 @@ jit::Invalidate(TypeZone& types, FreeOp* fop,
|
||||
JSRuntime::AutoProhibitActiveContextChange apacc(fop->runtime());
|
||||
|
||||
JSContext* cx = TlsContext.get();
|
||||
for (JitActivationIterator iter(cx, types.zone()->group()->ownerContext()); !iter.done(); ++iter)
|
||||
InvalidateActivation(fop, iter, false);
|
||||
for (const CooperatingContext& target : cx->runtime()->cooperatingContexts()) {
|
||||
for (JitActivationIterator iter(cx, target); !iter.done(); ++iter)
|
||||
InvalidateActivation(fop, iter, false);
|
||||
}
|
||||
|
||||
// Drop the references added above. If a script was never active, its
|
||||
// IonScript will be immediately destroyed. Otherwise, it will be held live
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "jit/IonBuilder.h"
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/ScopeExit.h"
|
||||
#include "mozilla/SizePrintfMacros.h"
|
||||
|
||||
#include "builtin/Eval.h"
|
||||
@ -836,10 +837,12 @@ IonBuilder::build()
|
||||
|
||||
insertRecompileCheck();
|
||||
|
||||
MOZ_TRY(traverseBytecode());
|
||||
auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] {
|
||||
// Discard unreferenced & pre-allocated resume points.
|
||||
replaceMaybeFallbackFunctionGetter(nullptr);
|
||||
});
|
||||
|
||||
// Discard unreferenced & pre-allocated resume points.
|
||||
replaceMaybeFallbackFunctionGetter(nullptr);
|
||||
MOZ_TRY(traverseBytecode());
|
||||
|
||||
if (script_->hasBaselineScript() &&
|
||||
inlinedBytecodeLength_ > script_->baselineScript()->inlinedBytecodeLength())
|
||||
@ -998,10 +1001,13 @@ IonBuilder::buildInline(IonBuilder* callerBuilder, MResumePoint* callerResumePoi
|
||||
// initialized.
|
||||
MOZ_TRY(initEnvironmentChain(callInfo.fun()));
|
||||
|
||||
auto clearLastPriorResumePoint = mozilla::MakeScopeExit([&] {
|
||||
// Discard unreferenced & pre-allocated resume points.
|
||||
replaceMaybeFallbackFunctionGetter(nullptr);
|
||||
});
|
||||
|
||||
MOZ_TRY(traverseBytecode());
|
||||
|
||||
// Discard unreferenced & pre-allocated resume points.
|
||||
replaceMaybeFallbackFunctionGetter(nullptr);
|
||||
|
||||
MOZ_ASSERT(iterators_.empty(), "Iterators should be added to outer builder");
|
||||
|
||||
@ -7275,6 +7281,17 @@ IonBuilder::ensureDefiniteTypeSet(MDefinition* def, TemporaryTypeSet* types)
|
||||
return filter;
|
||||
}
|
||||
|
||||
static size_t
|
||||
NumFixedSlots(JSObject* object)
|
||||
{
|
||||
// Note: we can't use object->numFixedSlots() here, as this will read the
|
||||
// shape and can race with the active thread if we are building off thread.
|
||||
// The allocation kind and object class (which goes through the type) can
|
||||
// be read freely, however.
|
||||
gc::AllocKind kind = object->asTenured().getAllocKind();
|
||||
return gc::GetGCKindSlots(kind, object->getClass());
|
||||
}
|
||||
|
||||
static bool
|
||||
IsUninitializedGlobalLexicalSlot(JSObject* obj, PropertyName* name)
|
||||
{
|
||||
@ -7296,48 +7313,32 @@ IonBuilder::getStaticName(bool* emitted, JSObject* staticObject, PropertyName* n
|
||||
|
||||
bool isGlobalLexical = staticObject->is<LexicalEnvironmentObject>() &&
|
||||
staticObject->as<LexicalEnvironmentObject>().isGlobal();
|
||||
MOZ_ASSERT(isGlobalLexical ||
|
||||
staticObject->is<GlobalObject>() ||
|
||||
staticObject->is<CallObject>() ||
|
||||
staticObject->is<ModuleEnvironmentObject>());
|
||||
MOZ_ASSERT(staticObject->isSingleton());
|
||||
|
||||
// Always emit the lexical check. This could be optimized, but is
|
||||
// currently not for simplicity's sake.
|
||||
if (lexicalCheck)
|
||||
return Ok();
|
||||
|
||||
// Only optimize accesses on native objects.
|
||||
if (!staticObject->isNative())
|
||||
return Ok();
|
||||
|
||||
// Only optimize accesses on own data properties.
|
||||
Shape* propertyShape = staticObject->as<NativeObject>().lastProperty()->searchLinear(NameToId(name));
|
||||
if (!propertyShape || !propertyShape->isDataDescriptor() || !propertyShape->hasSlot())
|
||||
return Ok();
|
||||
uint32_t slot = propertyShape->slot();
|
||||
|
||||
TypeSet::ObjectKey* staticKey = TypeSet::ObjectKey::get(staticObject);
|
||||
if (analysisContext)
|
||||
staticKey->ensureTrackedProperty(analysisContext, NameToId(name));
|
||||
|
||||
// Make sure the property is a normal data property. This is not done for
|
||||
// call objects, as they are not tracked by TI and their data properties
|
||||
// cannot be dynamically reconfigured.
|
||||
Maybe<HeapTypeSetKey> property;
|
||||
if (!staticObject->is<CallObject>()) {
|
||||
if (staticKey->unknownProperties())
|
||||
return Ok();
|
||||
if (staticKey->unknownProperties())
|
||||
return Ok();
|
||||
|
||||
property.emplace(staticKey->property(id));
|
||||
|
||||
if (property.ref().nonData(constraints()) ||
|
||||
!property.ref().maybeTypes() ||
|
||||
!property.ref().maybeTypes()->definiteProperty())
|
||||
{
|
||||
// We can't be sure the slot will match at runtime, so include a
|
||||
// shape guard on the object.
|
||||
MInstruction* obj = MConstant::NewConstraintlessObject(alloc(), staticObject);
|
||||
current->add(obj);
|
||||
addShapeGuard(obj, staticObject->as<NativeObject>().lastProperty(), Bailout_ShapeGuard);
|
||||
} else {
|
||||
MOZ_ASSERT(slot == property.ref().maybeTypes()->definiteSlot());
|
||||
}
|
||||
HeapTypeSetKey property = staticKey->property(id);
|
||||
if (!property.maybeTypes() ||
|
||||
!property.maybeTypes()->definiteProperty() ||
|
||||
property.nonData(constraints()))
|
||||
{
|
||||
// The property has been reconfigured as non-configurable, non-enumerable
|
||||
// or non-writable.
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// Don't optimize global lexical bindings if they aren't initialized at
|
||||
@ -7363,37 +7364,13 @@ IonBuilder::getStaticName(bool* emitted, JSObject* staticObject, PropertyName* n
|
||||
|
||||
// Try to inline properties that have never been overwritten.
|
||||
Value constantValue;
|
||||
if (property.isSome() && property.ref().constant(constraints(), &constantValue)) {
|
||||
if (property.constant(constraints(), &constantValue)) {
|
||||
pushConstant(constantValue);
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_TRY(loadStaticSlot(staticObject, barrier, types, slot));
|
||||
|
||||
// If the static object has a function object stored in this property,
|
||||
// test that the result is that specific function. This is yet another
|
||||
// technique for trying to force a property load to be a specific value,
|
||||
// and is included because other mechanisms (property types and observed
|
||||
// types) do not always work, especially in polymorphic framework code.
|
||||
// We restrict this optimization to function properties, as they are less
|
||||
// likely to change over time and are more likely to require precise
|
||||
// information for inlining decisions.
|
||||
if (!outermostBuilder()->script()->hadFrequentBailouts()) {
|
||||
Value v = staticObject->as<NativeObject>().getSlot(slot);
|
||||
if (v.isObject() &&
|
||||
v.toObject().is<JSFunction>() &&
|
||||
v.toObject().as<JSFunction>().isInterpreted())
|
||||
{
|
||||
JSObject* result = checkNurseryObject(&v.toObject().as<JSFunction>());
|
||||
MDefinition* load = current->pop();
|
||||
MInstruction* expected = MConstant::NewConstraintlessObject(alloc(), result);
|
||||
expected->setResultTypeSet(MakeSingletonTypeSet(constraints(), result));
|
||||
current->add(expected);
|
||||
current->add(MGuardObjectIdentity::New(alloc(), load, expected, false, Bailout_LoadStaticObject));
|
||||
current->push(expected);
|
||||
}
|
||||
}
|
||||
MOZ_TRY(loadStaticSlot(staticObject, barrier, types, property.maybeTypes()->definiteSlot()));
|
||||
|
||||
return Ok();
|
||||
}
|
||||
@ -7421,7 +7398,7 @@ IonBuilder::loadStaticSlot(JSObject* staticObject, BarrierKind barrier, Temporar
|
||||
if (barrier != BarrierKind::NoBarrier)
|
||||
rvalType = MIRType::Value;
|
||||
|
||||
return loadSlot(obj, slot, staticObject->as<NativeObject>().numFixedSlots(), rvalType, barrier, types);
|
||||
return loadSlot(obj, slot, NumFixedSlots(staticObject), rvalType, barrier, types);
|
||||
}
|
||||
|
||||
// Whether a write of the given value may need a post-write barrier for GC purposes.
|
||||
@ -7486,8 +7463,7 @@ IonBuilder::setStaticName(JSObject* staticObject, PropertyName* name)
|
||||
slotType = knownType;
|
||||
|
||||
bool needsPreBarrier = property.needsBarrier(constraints());
|
||||
return storeSlot(obj, property.maybeTypes()->definiteSlot(),
|
||||
staticObject->as<NativeObject>().numFixedSlots(),
|
||||
return storeSlot(obj, property.maybeTypes()->definiteSlot(), NumFixedSlots(staticObject),
|
||||
value, needsPreBarrier, slotType);
|
||||
}
|
||||
|
||||
@ -10428,12 +10404,6 @@ IonBuilder::jsop_getprop(PropertyName* name)
|
||||
if (emitted)
|
||||
return Ok();
|
||||
|
||||
// Try to optimize for loads from a specific object.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_Static);
|
||||
MOZ_TRY(getPropTryStaticAccess(&emitted, obj, name, barrier, types));
|
||||
if (emitted)
|
||||
return Ok();
|
||||
|
||||
// Try to emit a monomorphic/polymorphic access based on baseline caches.
|
||||
trackOptimizationAttempt(TrackedStrategy::GetProp_InlineAccess);
|
||||
MOZ_TRY(getPropTryInlineAccess(&emitted, obj, name, barrier, types));
|
||||
@ -11233,17 +11203,6 @@ PropertyShapesHaveSameSlot(const BaselineInspector::ReceiverVector& receivers, j
|
||||
return firstShape;
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::getPropTryStaticAccess(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
BarrierKind barrier, TemporaryTypeSet* types)
|
||||
{
|
||||
if (!obj->isConstant() || obj->type() != MIRType::Object)
|
||||
return Ok();
|
||||
|
||||
obj->setImplicitlyUsedUnchecked();
|
||||
return getStaticName(emitted, &obj->toConstant()->toObject(), name);
|
||||
}
|
||||
|
||||
AbortReasonOr<Ok>
|
||||
IonBuilder::getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
BarrierKind barrier, TemporaryTypeSet* types)
|
||||
@ -12677,49 +12636,11 @@ IonBuilder::walkEnvironmentChain(unsigned hops)
|
||||
return env;
|
||||
}
|
||||
|
||||
static bool
|
||||
SearchEnvironmentChainForCallObject(JSObject* environment, JSScript* script, JSObject** pcall)
|
||||
{
|
||||
while (environment && !environment->is<GlobalObject>()) {
|
||||
if (environment->is<CallObject>() &&
|
||||
environment->as<CallObject>().callee().nonLazyScript() == script)
|
||||
{
|
||||
*pcall = environment;
|
||||
return true;
|
||||
}
|
||||
environment = environment->enclosingEnvironment();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
IonBuilder::hasStaticEnvironmentObject(EnvironmentCoordinate ec, JSObject** pcall)
|
||||
{
|
||||
JSScript* outerScript = EnvironmentCoordinateFunctionScript(script(), pc);
|
||||
if (!outerScript)
|
||||
return false;
|
||||
|
||||
// JSOP_SETALIASEDVAR only emits a cache when the outer script is a run
|
||||
// once script. To avoid problems with the generic jsop_setprop() paths,
|
||||
// only use static environment objects when a baseline cache exists.
|
||||
if (*pc == JSOP_SETALIASEDVAR && !outerScript->treatAsRunOnce())
|
||||
return false;
|
||||
|
||||
// If the callee is a specific JSFunction then there is a specific
|
||||
// environment object on its chain we can use.
|
||||
if (inlineCallInfo_) {
|
||||
MDefinition* calleeDef = inlineCallInfo_->fun();
|
||||
if (calleeDef->isConstant()) {
|
||||
JSFunction* callee = &calleeDef->toConstant()->toObject().template as<JSFunction>();
|
||||
JSObject* environment = callee->environment();
|
||||
if (SearchEnvironmentChainForCallObject(environment, outerScript, pcall))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, if the outer script will only run once then we can go looking
|
||||
// for its call object.
|
||||
if (!outerScript->treatAsRunOnce())
|
||||
if (!outerScript || !outerScript->treatAsRunOnce())
|
||||
return false;
|
||||
|
||||
TypeSet::ObjectKey* funKey =
|
||||
@ -12740,8 +12661,16 @@ IonBuilder::hasStaticEnvironmentObject(EnvironmentCoordinate ec, JSObject** pcal
|
||||
envDef->setImplicitlyUsedUnchecked();
|
||||
|
||||
JSObject* environment = script()->functionNonDelazifying()->environment();
|
||||
if (SearchEnvironmentChainForCallObject(environment, outerScript, pcall))
|
||||
return true;
|
||||
while (environment && !environment->is<GlobalObject>()) {
|
||||
if (environment->is<CallObject>() &&
|
||||
environment->as<CallObject>().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
MOZ_ASSERT(environment->isSingleton());
|
||||
*pcall = environment;
|
||||
return true;
|
||||
}
|
||||
environment = environment->enclosingEnvironment();
|
||||
}
|
||||
|
||||
// Look for the call object on the current frame, if we are compiling the
|
||||
// outer script itself. Don't do this if we are at entry to the outer
|
||||
@ -12750,8 +12679,14 @@ IonBuilder::hasStaticEnvironmentObject(EnvironmentCoordinate ec, JSObject** pcal
|
||||
|
||||
if (script() == outerScript && baselineFrame_ && info().osrPc()) {
|
||||
JSObject* singletonScope = baselineFrame_->singletonEnvChain;
|
||||
if (SearchEnvironmentChainForCallObject(singletonScope, outerScript, pcall))
|
||||
if (singletonScope &&
|
||||
singletonScope->is<CallObject>() &&
|
||||
singletonScope->as<CallObject>().callee().nonLazyScript() == outerScript)
|
||||
{
|
||||
MOZ_ASSERT(singletonScope->isSingleton());
|
||||
*pcall = singletonScope;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -246,8 +246,6 @@ class IonBuilder
|
||||
BarrierKind barrier, TemporaryTypeSet* types);
|
||||
AbortReasonOr<Ok> getPropTryCommonGetter(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
TemporaryTypeSet* types, bool innerized = false);
|
||||
AbortReasonOr<Ok> getPropTryStaticAccess(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
BarrierKind barrier, TemporaryTypeSet* types);
|
||||
AbortReasonOr<Ok> getPropTryInlineAccess(bool* emitted, MDefinition* obj, PropertyName* name,
|
||||
BarrierKind barrier, TemporaryTypeSet* types);
|
||||
AbortReasonOr<Ok> getPropTryTypedObject(bool* emitted, MDefinition* obj, PropertyName* name);
|
||||
|
@ -135,12 +135,11 @@ IonGetPropertyIC::update(JSContext* cx, HandleScript outerScript, IonGetProperty
|
||||
// needs a type barrier. Unfortunately, PropertyReadNeedsTypeBarrier
|
||||
// does not account for getters, so we should only attach a getter
|
||||
// stub if we inserted a type barrier.
|
||||
CanAttachGetter canAttachGetter =
|
||||
ic->monitoredResult() ? CanAttachGetter::Yes : CanAttachGetter::No;
|
||||
jsbytecode* pc = ic->idempotent() ? nullptr : ic->pc();
|
||||
bool isTemporarilyUnoptimizable = false;
|
||||
GetPropIRGenerator gen(cx, outerScript, pc, ic->kind(), ic->state().mode(),
|
||||
&isTemporarilyUnoptimizable, val, idVal, val, canAttachGetter);
|
||||
&isTemporarilyUnoptimizable, val, idVal, val,
|
||||
ic->resultFlags());
|
||||
if (ic->idempotent() ? gen.tryAttachIdempotentStub() : gen.tryAttachStub())
|
||||
ic->attachCacheIRStub(cx, gen.writerRef(), gen.cacheKind(), ionScript, &attached);
|
||||
|
||||
|
@ -178,6 +178,7 @@ class IonIC
|
||||
|
||||
class IonGetPropertyIC : public IonIC
|
||||
{
|
||||
private:
|
||||
LiveRegisterSet liveRegs_;
|
||||
|
||||
TypedOrValueRegister value_;
|
||||
@ -185,30 +186,29 @@ class IonGetPropertyIC : public IonIC
|
||||
TypedOrValueRegister output_;
|
||||
Register maybeTemp_; // Might be InvalidReg.
|
||||
|
||||
bool monitoredResult_ : 1;
|
||||
bool allowDoubleResult_ : 1;
|
||||
GetPropertyResultFlags resultFlags_;
|
||||
|
||||
public:
|
||||
IonGetPropertyIC(CacheKind kind, LiveRegisterSet liveRegs, TypedOrValueRegister value,
|
||||
const ConstantOrRegister& id, TypedOrValueRegister output, Register maybeTemp,
|
||||
bool monitoredResult, bool allowDoubleResult)
|
||||
GetPropertyResultFlags resultFlags)
|
||||
: IonIC(kind),
|
||||
liveRegs_(liveRegs),
|
||||
value_(value),
|
||||
id_(id),
|
||||
output_(output),
|
||||
maybeTemp_(maybeTemp),
|
||||
monitoredResult_(monitoredResult),
|
||||
allowDoubleResult_(allowDoubleResult)
|
||||
resultFlags_(resultFlags)
|
||||
{ }
|
||||
|
||||
bool monitoredResult() const { return monitoredResult_; }
|
||||
TypedOrValueRegister value() const { return value_; }
|
||||
ConstantOrRegister id() const { return id_; }
|
||||
TypedOrValueRegister output() const { return output_; }
|
||||
Register maybeTemp() const { return maybeTemp_; }
|
||||
LiveRegisterSet liveRegs() const { return liveRegs_; }
|
||||
bool allowDoubleResult() const { return allowDoubleResult_; }
|
||||
GetPropertyResultFlags resultFlags() const { return resultFlags_; }
|
||||
bool monitoredResult() const { return resultFlags_ & GetPropertyResultFlags::Monitored; }
|
||||
bool allowDoubleResult() const { return resultFlags_ & GetPropertyResultFlags::AllowDouble; }
|
||||
|
||||
static MOZ_MUST_USE bool update(JSContext* cx, HandleScript outerScript, IonGetPropertyIC* ic,
|
||||
HandleValue val, HandleValue idVal, MutableHandleValue res);
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
namespace js {
|
||||
|
||||
class GeckoProfiler;
|
||||
class GeckoProfilerRuntime;
|
||||
|
||||
namespace jit {
|
||||
|
||||
@ -20,7 +20,7 @@ typedef GeckoProfilerInstrumentation<MacroAssembler, Register> BaseInstrumentati
|
||||
class IonInstrumentation : public BaseInstrumentation
|
||||
{
|
||||
public:
|
||||
IonInstrumentation(GeckoProfiler* profiler, jsbytecode** pc)
|
||||
IonInstrumentation(GeckoProfilerRuntime* profiler, jsbytecode** pc)
|
||||
: BaseInstrumentation(profiler)
|
||||
{
|
||||
MOZ_ASSERT(pc != nullptr);
|
||||
|
@ -142,9 +142,6 @@ enum BailoutKind
|
||||
// Can also signal division by 0 (returns inf, a double).
|
||||
Bailout_DoubleOutput,
|
||||
|
||||
// Load of a value from a static object retrieved an unexpected value.
|
||||
Bailout_LoadStaticObject,
|
||||
|
||||
// END Invalid assumptions bailouts
|
||||
|
||||
|
||||
@ -236,8 +233,6 @@ BailoutKindString(BailoutKind kind)
|
||||
return "Bailout_NonStringInputInvalidate";
|
||||
case Bailout_DoubleOutput:
|
||||
return "Bailout_DoubleOutput";
|
||||
case Bailout_LoadStaticObject:
|
||||
return "Bailout_LoadStaticObject";
|
||||
|
||||
// Other bailouts.
|
||||
case Bailout_ArgumentCheck:
|
||||
|
@ -3900,7 +3900,7 @@ LIRGenerator::visitGuardObjectIdentity(MGuardObjectIdentity* ins)
|
||||
{
|
||||
LGuardObjectIdentity* guard = new(alloc()) LGuardObjectIdentity(useRegister(ins->object()),
|
||||
useRegister(ins->expected()));
|
||||
assignSnapshot(guard, ins->bailoutKind());
|
||||
assignSnapshot(guard, Bailout_ObjectIdentityOrTypeGuard);
|
||||
add(guard, ins);
|
||||
redefine(ins, ins->object());
|
||||
}
|
||||
|
@ -6197,18 +6197,9 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
|
||||
TypeSet::TypeList types;
|
||||
if (!property.maybeTypes()->enumerateTypes(&types))
|
||||
break;
|
||||
// If there is a single possible type for the property,
|
||||
// optimistically add it to the observed set. Don't do this
|
||||
// for the special uninitialized lexical type, which will
|
||||
// never actually be observed here and will cause problems
|
||||
// downstream during compilation.
|
||||
if (types.length() == 1 &&
|
||||
(!types[0].isPrimitive() ||
|
||||
types[0].primitive() != JSVAL_TYPE_MAGIC))
|
||||
{
|
||||
if (types.length() == 1) {
|
||||
// Note: the return value here is ignored.
|
||||
observed->addType(types[0], GetJitContext()->temp->lifoAlloc());
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -11490,13 +11490,10 @@ class MGuardObjectIdentity
|
||||
public SingleObjectPolicy::Data
|
||||
{
|
||||
bool bailOnEquality_;
|
||||
BailoutKind bailoutKind_;
|
||||
|
||||
MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality,
|
||||
BailoutKind bailoutKind = Bailout_ObjectIdentityOrTypeGuard)
|
||||
MGuardObjectIdentity(MDefinition* obj, MDefinition* expected, bool bailOnEquality)
|
||||
: MBinaryInstruction(obj, expected),
|
||||
bailOnEquality_(bailOnEquality),
|
||||
bailoutKind_(bailoutKind)
|
||||
bailOnEquality_(bailOnEquality)
|
||||
{
|
||||
setGuard();
|
||||
setMovable();
|
||||
@ -11511,16 +11508,11 @@ class MGuardObjectIdentity
|
||||
bool bailOnEquality() const {
|
||||
return bailOnEquality_;
|
||||
}
|
||||
BailoutKind bailoutKind() const {
|
||||
return bailoutKind_;
|
||||
}
|
||||
bool congruentTo(const MDefinition* ins) const override {
|
||||
if (!ins->isGuardObjectIdentity())
|
||||
return false;
|
||||
if (bailOnEquality() != ins->toGuardObjectIdentity()->bailOnEquality())
|
||||
return false;
|
||||
if (bailoutKind() != ins->toGuardObjectIdentity()->bailoutKind())
|
||||
return false;
|
||||
return congruentIfOperandsEqual(ins);
|
||||
}
|
||||
AliasSet getAliasSet() const override {
|
||||
|
@ -2069,7 +2069,8 @@ DoGetPropFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback* stub_
|
||||
if (stub->state().canAttachStub()) {
|
||||
RootedValue idVal(cx, StringValue(name));
|
||||
GetPropIRGenerator gen(cx, script, pc, CacheKind::GetProp, stub->state().mode(),
|
||||
&isTemporarilyUnoptimizable, val, idVal, val, CanAttachGetter::Yes);
|
||||
&isTemporarilyUnoptimizable, val, idVal, val,
|
||||
GetPropertyResultFlags::All);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
BaselineCacheIRStubKind::Monitored,
|
||||
@ -2140,7 +2141,7 @@ DoGetPropSuperFallback(JSContext* cx, BaselineFrame* frame, ICGetProp_Fallback*
|
||||
RootedValue idVal(cx, StringValue(name));
|
||||
GetPropIRGenerator gen(cx, script, pc, CacheKind::GetPropSuper, stub->state().mode(),
|
||||
&isTemporarilyUnoptimizable, val, idVal, receiver,
|
||||
CanAttachGetter::Yes);
|
||||
GetPropertyResultFlags::All);
|
||||
if (gen.tryAttachStub()) {
|
||||
ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), gen.cacheKind(),
|
||||
BaselineCacheIRStubKind::Monitored,
|
||||
|
@ -33,7 +33,7 @@ static const FloatRegisterSet NonVolatileFloatRegs =
|
||||
(1ULL << FloatRegisters::d15));
|
||||
|
||||
static void
|
||||
GenerateReturn(MacroAssembler& masm, int returnCode, GeckoProfiler* prof)
|
||||
GenerateReturn(MacroAssembler& masm, int returnCode)
|
||||
{
|
||||
// Restore non-volatile floating point registers.
|
||||
masm.transferMultipleByRuns(NonVolatileFloatRegs, IsLoad, StackPointer, IA);
|
||||
@ -377,7 +377,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
// JSReturnReg_Data, EDtrAddr(r5, EDtrOffImm(0)));
|
||||
|
||||
// Restore non-volatile registers and return.
|
||||
GenerateReturn(masm, true, &cx->runtime()->geckoProfiler());
|
||||
GenerateReturn(masm, true);
|
||||
|
||||
Linker linker(masm);
|
||||
AutoFlushICache afc("EnterJIT");
|
||||
|
@ -1030,6 +1030,23 @@ JS_ResumeCooperativeContext(JSContext* cx);
|
||||
extern JS_PUBLIC_API(JSContext*)
|
||||
JS_NewCooperativeContext(JSContext* siblingContext);
|
||||
|
||||
namespace JS {
|
||||
|
||||
// Class to relinquish exclusive access to all zone groups in use by this
|
||||
// thread. This allows other cooperative threads to enter the zone groups
|
||||
// and modify their contents.
|
||||
struct AutoRelinquishZoneGroups
|
||||
{
|
||||
explicit AutoRelinquishZoneGroups(JSContext* cx);
|
||||
~AutoRelinquishZoneGroups();
|
||||
|
||||
private:
|
||||
JSContext* cx;
|
||||
mozilla::Vector<void*> enterList;
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
|
||||
// Destroy a context allocated with JS_NewContext or JS_NewCooperativeContext.
|
||||
// The context must be the current active context in the runtime, and after
|
||||
// this call the runtime will have no active context.
|
||||
|
@ -1323,7 +1323,7 @@ js::array_join(JSContext* cx, unsigned argc, Value* vp)
|
||||
if (!CheckRecursionLimit(cx))
|
||||
return false;
|
||||
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.join");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.join");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -1583,7 +1583,7 @@ DefineBoxedOrUnboxedFunctor3(ArrayReverseDenseKernel,
|
||||
bool
|
||||
js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.reverse");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.reverse");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -2288,7 +2288,7 @@ js::NewbornArrayPush(JSContext* cx, HandleObject obj, const Value& v)
|
||||
bool
|
||||
js::array_push(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.push");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.push");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -2345,7 +2345,7 @@ js::array_push(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
js::array_pop(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.pop");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.pop");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -2450,7 +2450,7 @@ DefineBoxedOrUnboxedFunctor3(ArrayShiftDenseKernel,
|
||||
bool
|
||||
js::array_shift(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.shift");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.shift");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -2526,7 +2526,7 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.unshift");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.unshift");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
// Step 1.
|
||||
@ -2769,7 +2769,7 @@ CopyArrayElements(JSContext* cx, HandleObject obj, uint64_t begin, uint64_t coun
|
||||
static bool
|
||||
array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUsed)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.splice");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.splice");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
@ -3277,7 +3277,7 @@ ArraySliceOrdinary(JSContext* cx, HandleObject obj, uint64_t begin, uint64_t end
|
||||
bool
|
||||
js::array_slice(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx->runtime(), "Array.prototype.slice");
|
||||
AutoGeckoProfilerEntry pseudoFrame(cx, "Array.prototype.slice");
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Step 1. */
|
||||
|
@ -1590,6 +1590,7 @@ void
|
||||
JSContext::trace(JSTracer* trc)
|
||||
{
|
||||
cycleDetectorVector().trace(trc);
|
||||
geckoProfiler().trace(trc);
|
||||
|
||||
if (trc->isMarkingTracer() && compartment_)
|
||||
compartment_->mark();
|
||||
|
@ -390,9 +390,6 @@ struct JSContext : public JS::RootingContext,
|
||||
js::Activation* profilingActivation() const {
|
||||
return profilingActivation_;
|
||||
}
|
||||
void* addressOfProfilingActivation() {
|
||||
return (void*) &profilingActivation_;
|
||||
}
|
||||
static size_t offsetOfProfilingActivation() {
|
||||
return offsetof(JSContext, profilingActivation_);
|
||||
}
|
||||
@ -603,6 +600,12 @@ struct JSContext : public JS::RootingContext,
|
||||
suppressProfilerSampling = false;
|
||||
}
|
||||
|
||||
private:
|
||||
/* Gecko profiling metadata */
|
||||
js::UnprotectedData<js::GeckoProfilerThread> geckoProfiler_;
|
||||
public:
|
||||
js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_.ref(); }
|
||||
|
||||
#if defined(XP_DARWIN)
|
||||
js::wasm::MachExceptionHandler wasmMachExceptionHandler;
|
||||
#endif
|
||||
|
@ -6216,7 +6216,7 @@ AutoTraceSession::AutoTraceSession(JSRuntime* rt, JS::HeapState heapState)
|
||||
: lock(rt),
|
||||
runtime(rt),
|
||||
prevState(TlsContext.get()->heapState),
|
||||
pseudoFrame(rt, HeapStateToLabel(heapState), ProfileEntry::Category::GC)
|
||||
pseudoFrame(TlsContext.get(), HeapStateToLabel(heapState), ProfileEntry::Category::GC)
|
||||
{
|
||||
MOZ_ASSERT(prevState == JS::HeapState::Idle);
|
||||
MOZ_ASSERT(heapState != JS::HeapState::Idle);
|
||||
|
@ -29,11 +29,6 @@ JS_PUBLIC_API(JS::UniqueChars) JS_smprintf(const char* fmt, ...)
|
||||
return JS::UniqueChars(result.release());
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void) JS_smprintf_free(char* mem)
|
||||
{
|
||||
mozilla::SmprintfFree<js::SystemAllocPolicy>(mem);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
@ -20,8 +20,6 @@
|
||||
extern JS_PUBLIC_API(JS::UniqueChars) JS_smprintf(const char* fmt, ...)
|
||||
MOZ_FORMAT_PRINTF(1, 2);
|
||||
|
||||
extern JS_PUBLIC_API(void) JS_smprintf_free(char* mem);
|
||||
|
||||
extern JS_PUBLIC_API(JS::UniqueChars) JS_sprintf_append(JS::UniqueChars&& last,
|
||||
const char* fmt, ...)
|
||||
MOZ_FORMAT_PRINTF(2, 3);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user