зеркало из https://github.com/mozilla/pjs.git
Merge last green PGO from inbound to central
This commit is contained in:
Коммит
3d4f52ed01
|
@ -287,11 +287,12 @@ FocusManager::ProcessFocusEvent(AccEvent* aEvent)
|
|||
// if it's still focused and then update active item and emit focus event.
|
||||
nsAccessible* target = aEvent->GetAccessible();
|
||||
if (target != mActiveItem) {
|
||||
|
||||
// Check if still focused. Otherwise we can end up with storing the active
|
||||
// item for control that isn't focused anymore.
|
||||
nsAccessible* DOMFocus =
|
||||
GetAccService()->GetAccessibleOrContainer(FocusedDOMNode(),
|
||||
aEvent->GetDocAccessible());
|
||||
nsDocAccessible* document = aEvent->GetDocAccessible();
|
||||
nsAccessible* DOMFocus = document->GetAccessibleOrContainer(FocusedDOMNode());
|
||||
|
||||
if (target != DOMFocus)
|
||||
return;
|
||||
|
||||
|
|
|
@ -669,9 +669,8 @@ NotificationController::CoalesceTextChangeEventsFor(AccShowEvent* aTailEvent,
|
|||
void
|
||||
NotificationController::CreateTextChangeEventFor(AccMutationEvent* aEvent)
|
||||
{
|
||||
nsAccessible* container =
|
||||
GetAccService()->GetContainerAccessible(aEvent->mNode,
|
||||
aEvent->GetDocAccessible());
|
||||
nsDocAccessible* document = aEvent->GetDocAccessible();
|
||||
nsAccessible* container = document->GetContainerAccessible(aEvent->mNode);
|
||||
if (!container)
|
||||
return;
|
||||
|
||||
|
|
|
@ -283,38 +283,6 @@ nsAccessNode::ScrollTo(PRUint32 aScrollType)
|
|||
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
|
||||
}
|
||||
|
||||
// nsAccessNode public
|
||||
already_AddRefed<nsINode>
|
||||
nsAccessNode::GetCurrentFocus()
|
||||
{
|
||||
// XXX: consider to use nsFocusManager directly, it allows us to avoid
|
||||
// unnecessary query interface calls.
|
||||
nsIDocument* doc = GetDocumentNode();
|
||||
NS_ENSURE_TRUE(doc, nsnull);
|
||||
|
||||
nsIDOMWindow* win = doc->GetWindow();
|
||||
|
||||
nsCOMPtr<nsIDOMWindow> focusedWindow;
|
||||
nsCOMPtr<nsIDOMElement> focusedElement;
|
||||
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
||||
if (fm)
|
||||
fm->GetFocusedElementForWindow(win, true, getter_AddRefs(focusedWindow),
|
||||
getter_AddRefs(focusedElement));
|
||||
|
||||
nsINode *focusedNode = nsnull;
|
||||
if (focusedElement) {
|
||||
CallQueryInterface(focusedElement, &focusedNode);
|
||||
}
|
||||
else if (focusedWindow) {
|
||||
nsCOMPtr<nsIDOMDocument> doc;
|
||||
focusedWindow->GetDocument(getter_AddRefs(doc));
|
||||
if (doc)
|
||||
CallQueryInterface(doc, &focusedNode);
|
||||
}
|
||||
|
||||
return focusedNode;
|
||||
}
|
||||
|
||||
void
|
||||
nsAccessNode::Language(nsAString& aLanguage)
|
||||
{
|
||||
|
|
|
@ -95,14 +95,6 @@ public:
|
|||
*/
|
||||
nsRootAccessible* RootAccessible() const;
|
||||
|
||||
/**
|
||||
* Return focused node within accessible window.
|
||||
*
|
||||
* XXX: it shouldn't break us if we return focused node not depending on
|
||||
* window so that we can turn this method into util method.
|
||||
*/
|
||||
already_AddRefed<nsINode> GetCurrentFocus();
|
||||
|
||||
/**
|
||||
* Initialize the access node object, add it to the cache.
|
||||
*/
|
||||
|
|
|
@ -919,17 +919,6 @@ nsAccessibilityService::GetAccessible(nsINode* aNode, nsIPresShell* aPresShell)
|
|||
return document ? document->GetAccessible(aNode) : nsnull;
|
||||
}
|
||||
|
||||
nsAccessible*
|
||||
nsAccessibilityService::GetAccessibleOrContainer(nsINode* aNode, nsDocAccessible* aDoc)
|
||||
{
|
||||
if (!aNode)
|
||||
return nsnull;
|
||||
|
||||
NS_PRECONDITION(aDoc, "Must pass a document accessible.");
|
||||
|
||||
return aDoc ? aDoc->GetAccessibleOrContainer(aNode) : nsnull;
|
||||
}
|
||||
|
||||
static bool HasRelatedContent(nsIContent *aContent)
|
||||
{
|
||||
nsAutoString id;
|
||||
|
|
|
@ -197,24 +197,6 @@ public:
|
|||
*/
|
||||
nsAccessible* GetAccessible(nsINode* aNode, nsIPresShell* aPresShell);
|
||||
|
||||
/**
|
||||
* Return an accessible for the given DOM node or container accessible if
|
||||
* the node is not accessible.
|
||||
*
|
||||
* @param aNode [in] the given node
|
||||
* @param aDoc [in] the document accessible. Can't be null.
|
||||
*/
|
||||
nsAccessible* GetAccessibleOrContainer(nsINode* aNode, nsDocAccessible* aDoc);
|
||||
|
||||
/**
|
||||
* Return a container accessible for the given DOM node.
|
||||
*/
|
||||
nsAccessible* GetContainerAccessible(nsINode* aNode, nsDocAccessible* aDoc)
|
||||
{
|
||||
return aNode ?
|
||||
GetAccessibleOrContainer(aNode->GetNodeParent(), aDoc) : nsnull;
|
||||
}
|
||||
|
||||
private:
|
||||
// nsAccessibilityService creation is controlled by friend
|
||||
// NS_GetAccessibilityService, keep constructors private.
|
||||
|
|
|
@ -852,8 +852,7 @@ nsAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
|
|||
|
||||
// Get accessible for the node with the point or the first accessible in
|
||||
// the DOM parent chain.
|
||||
nsAccessible* accessible =
|
||||
GetAccService()->GetAccessibleOrContainer(content, accDocument);
|
||||
nsAccessible* accessible = accDocument->GetAccessibleOrContainer(content);
|
||||
if (!accessible)
|
||||
return fallbackAnswer;
|
||||
|
||||
|
@ -1147,7 +1146,7 @@ nsAccessible::TakeFocus()
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIDOMElement> element(do_QueryInterface(focusContent));
|
||||
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm)
|
||||
fm->SetFocus(element, 0);
|
||||
|
||||
|
|
|
@ -378,7 +378,7 @@ NS_IMETHODIMP nsDocAccessible::TakeFocus()
|
|||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Focus the document.
|
||||
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
NS_ENSURE_STATE(fm);
|
||||
|
||||
nsCOMPtr<nsIDOMElement> newFocus;
|
||||
|
|
|
@ -203,7 +203,7 @@ nsRootAccessible::NativeState()
|
|||
states |= states::MODAL;
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
if (fm) {
|
||||
nsCOMPtr<nsIDOMWindow> rootWindow;
|
||||
GetWindow(getter_AddRefs(rootWindow));
|
||||
|
|
|
@ -1628,8 +1628,16 @@ nsHyperTextAccessible::SetCaretOffset(PRInt32 aCaretOffset)
|
|||
NS_IMETHODIMP
|
||||
nsHyperTextAccessible::GetCaretOffset(PRInt32 *aCaretOffset)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aCaretOffset);
|
||||
*aCaretOffset = -1;
|
||||
|
||||
// Not focused focusable accessible except document accessible doesn't have
|
||||
// a caret.
|
||||
if (!IsDoc() && !FocusMgr()->IsFocused(this) &&
|
||||
(State() & states::FOCUSABLE)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// No caret if the focused node is not inside this DOM node and this DOM node
|
||||
// is not inside of focused node.
|
||||
FocusManager::FocusDisposition focusDisp =
|
||||
|
|
|
@ -46,21 +46,8 @@
|
|||
// gA11yEventDumpID = "eventdump"; // debug stuff
|
||||
//gA11yEventDumpToConsole = true;
|
||||
|
||||
function testCaretOffset(aAccOrElmOrID, aCaretOffset)
|
||||
{
|
||||
var acc = getAccessible(aAccOrElmOrID, [nsIAccessibleText]);
|
||||
is(acc.caretOffset, aCaretOffset,
|
||||
"Wrong caret offset for " + aAccOrElmOrID);
|
||||
}
|
||||
|
||||
function doTests()
|
||||
{
|
||||
todo(false, "enable commented tests Bug 510128 is fixed");
|
||||
// test no focused accessibles
|
||||
//testCaretOffset("textbox", -1);
|
||||
//testCaretOffset("textarea", -1);
|
||||
testCaretOffset("p", -1);
|
||||
|
||||
// test caret move events and caret offsets
|
||||
gQueue = new eventQueue();
|
||||
|
||||
|
|
|
@ -25,6 +25,16 @@
|
|||
prefs.setBoolPref("accessibility.browsewithcaret", aIsOn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test caret offset for the given accessible.
|
||||
*/
|
||||
function testCaretOffset(aID, aCaretOffset)
|
||||
{
|
||||
var acc = getAccessible(aID, [nsIAccessibleText]);
|
||||
is(acc.caretOffset, aCaretOffset,
|
||||
"Wrong caret offset for " + aID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do tests.
|
||||
*/
|
||||
|
@ -37,6 +47,12 @@
|
|||
{
|
||||
turnCaretBrowsing(true);
|
||||
|
||||
// test caret offsets
|
||||
testCaretOffset(document, 14);
|
||||
testCaretOffset("textbox", -1);
|
||||
testCaretOffset("textarea", -1);
|
||||
testCaretOffset("p", -1);
|
||||
|
||||
// test caret move events and caret offsets
|
||||
gQueue = new eventQueue();
|
||||
|
||||
|
@ -58,6 +74,11 @@
|
|||
|
||||
<body>
|
||||
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=448744"
|
||||
title="caretOffset should return -1 if the system caret is not currently with in that particular object">
|
||||
Mozilla Bug 448744
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=524115"
|
||||
title="HyperText accessible should get focus when the caret is positioned inside of it, text is changed or copied into clipboard by ATs">
|
||||
|
@ -68,12 +89,19 @@
|
|||
title="Position is not being updated when atk_text_set_caret_offset is used">
|
||||
Mozilla Bug 546068
|
||||
</a>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=725581"
|
||||
title="caretOffset for textarea should be -1 when textarea doesn't have a focus">
|
||||
Mozilla Bug 725581
|
||||
</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<input id="textbox" value="hello"/>
|
||||
<textarea id="textarea">text<br>text</textarea>
|
||||
<p id="p" contentEditable="true"><span>text</span><br/>text</p>
|
||||
<a id="link" href="about:">about mozilla</a>
|
||||
<h5 id="heading">heading</h5>
|
||||
|
||||
|
|
|
@ -8211,7 +8211,7 @@ dnl ========================================================
|
|||
dnl qcms
|
||||
dnl ========================================================
|
||||
|
||||
QCMS_LIBS='$(call EXPAND_LIBNAME_PATH,mozqcms,$(DEPTH)/gfx/qcms)'
|
||||
QCMS_LIBS='$(DEPTH)/gfx/qcms/$(LIB_PREFIX)mozqcms.$(LIB_SUFFIX)'
|
||||
AC_SUBST(QCMS_LIBS)
|
||||
|
||||
dnl ========================================================
|
||||
|
|
|
@ -266,10 +266,10 @@ AsyncClickHandler::Run()
|
|||
}
|
||||
|
||||
// Check if page is allowed to open the popup
|
||||
if (mPopupControlState != openAllowed) {
|
||||
if (mPopupControlState > openControlled) {
|
||||
nsCOMPtr<nsIPopupWindowManager> pm =
|
||||
do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
|
||||
|
||||
|
||||
if (!pm) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -763,7 +763,9 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
if (BasicManager()->IsTransactionIncomplete())
|
||||
return;
|
||||
|
||||
if (!IsHidden()) {
|
||||
gfxRect clipExtents;
|
||||
clipExtents = aContext->GetClipExtents();
|
||||
if (!IsHidden() && !clipExtents.IsEmpty()) {
|
||||
AutoSetOperator setOperator(aContext, GetOperator());
|
||||
mBuffer.DrawTo(this, aContext, opacity);
|
||||
}
|
||||
|
@ -1946,16 +1948,22 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
|
|||
NS_ABORT_IF_FALSE(untransformedSurface,
|
||||
"We should always allocate an untransformed surface with 3d transforms!");
|
||||
|
||||
gfxPoint offset;
|
||||
bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete ||
|
||||
aLayer->GetEffectiveOpacity() != 1.0f;
|
||||
nsRefPtr<gfxASurface> result =
|
||||
Transform3D(untransformedSurface, aTarget, bounds,
|
||||
effectiveTransform, offset, dontBlit);
|
||||
// Temporary fast fix for bug 725886
|
||||
// Revert these changes when 725886 is ready
|
||||
gfxRect clipExtents;
|
||||
clipExtents = aTarget->GetClipExtents();
|
||||
if (!clipExtents.IsEmpty()) {
|
||||
gfxPoint offset;
|
||||
bool dontBlit = needsClipToVisibleRegion || mTransactionIncomplete ||
|
||||
aLayer->GetEffectiveOpacity() != 1.0f;
|
||||
nsRefPtr<gfxASurface> result =
|
||||
Transform3D(untransformedSurface, aTarget, bounds,
|
||||
effectiveTransform, offset, dontBlit);
|
||||
|
||||
blitComplete = !result;
|
||||
if (result) {
|
||||
aTarget->SetSource(result, offset);
|
||||
blitComplete = !result;
|
||||
if (result) {
|
||||
aTarget->SetSource(result, offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we're doing our own double-buffering, we need to avoid drawing
|
||||
|
|
|
@ -44,7 +44,6 @@ MODULE = qcms
|
|||
LIBRARY_NAME = mozqcms
|
||||
LIBXUL_LIBRARY = 1
|
||||
GRE_MODULE = 1
|
||||
DIST_INSTALL = 1
|
||||
|
||||
EXPORTS = qcms.h qcmstypes.h
|
||||
|
||||
|
|
|
@ -604,7 +604,7 @@ check-malloc-function-usage: $(filter-out %jsalloc.h %jscntxt.h %jsutil.h, $(ALL
|
|||
|
||||
# We desire these numbers to go down, not up. See "User guide to memory
|
||||
# management within SpiderMonkey" in jsutil.h.
|
||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 58 \
|
||||
$(srcdir)/config/check_source_count.py OffTheBooks:: 71 \
|
||||
"in Makefile.in" "{cx,rt}->{new_,array_new,malloc_,calloc_,realloc_}" $^
|
||||
# This should go to zero, if possible.
|
||||
$(srcdir)/config/check_source_count.py UnwantedForeground:: 31 \
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
// |jit-test| mjitalways;
|
||||
gczeal(4);
|
||||
var optionNames = options().split(',');
|
||||
for (var i = 0; i < optionNames.length; i++)
|
||||
var optionName = optionNames[i];
|
||||
options(optionName);
|
||||
evaluate("\
|
||||
function addDebug(g, id) {\
|
||||
var debuggerGlobal = newGlobal('new-compartment');\
|
||||
debuggerGlobal.debuggee = g;\
|
||||
debuggerGlobal.id = id;\
|
||||
debuggerGlobal.print = function (s) { (g) += s; };\
|
||||
debuggerGlobal.eval('var dbg = new Debugger(debuggee);dbg.onDebuggerStatement = function () { print(id); debugger; };');\
|
||||
return debuggerGlobal;\
|
||||
}\
|
||||
var base = newGlobal('new-compartment');\
|
||||
var top = base;\
|
||||
for (var i = 0; i < 8; i++ )\
|
||||
top = addDebug(top, i);\
|
||||
base.eval('debugger;');\
|
||||
");
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
gczeal(4);
|
||||
var BUGNUMBER = 668024;
|
||||
var summary =
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
var arr = [0, 1, 2, 3, 4, 5, , 7];
|
||||
var seen = [];
|
||||
for (var p in arr) {
|
||||
if (seen.indexOf(unescape) >= 0) {}
|
||||
arr.splice(2, 3);
|
||||
seen.push(p);
|
||||
}
|
||||
|
|
@ -940,12 +940,15 @@ ScriptAnalysis::killVariable(JSContext *cx, LifetimeVariable &var, unsigned offs
|
|||
/*
|
||||
* The variable is live even before the write, due to an enclosing try
|
||||
* block. We need to split the lifetime to indicate there was a write.
|
||||
* We set the new interval's savedEnd to 0, since it will always be
|
||||
* adjacent to the old interval, so it never needs to be extended.
|
||||
*/
|
||||
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(start, offset, var.lifetime);
|
||||
var.lifetime = cx->typeLifoAlloc().new_<Lifetime>(start, 0, var.lifetime);
|
||||
if (!var.lifetime) {
|
||||
setOOM(cx);
|
||||
return;
|
||||
}
|
||||
var.lifetime->end = offset;
|
||||
} else {
|
||||
var.saved = var.lifetime;
|
||||
var.savedEnd = 0;
|
||||
|
@ -973,25 +976,43 @@ ScriptAnalysis::extendVariable(JSContext *cx, LifetimeVariable &var,
|
|||
var.lifetime->start = start;
|
||||
|
||||
/*
|
||||
* When walking backwards through loop bodies, we don't know which vars
|
||||
* are live at the loop's backedge. We save the endpoints for lifetime
|
||||
* segments which we *would* use if the variables were live at the backedge
|
||||
* and extend the variable with new lifetimes if we find the variable is
|
||||
* indeed live at the head of the loop.
|
||||
* Consider this code:
|
||||
*
|
||||
* while (...) {
|
||||
* if (x #1) { ... }
|
||||
* ...
|
||||
* if (... #2) { x = 0; #3}
|
||||
* }
|
||||
* while (...) { (#1)
|
||||
* use x; (#2)
|
||||
* ...
|
||||
* x = ...; (#3)
|
||||
* ...
|
||||
* } (#4)
|
||||
*
|
||||
* If x is not live after the loop, we treat it as dead in the walk and
|
||||
* make a point lifetime for the write at #3. At the beginning of that
|
||||
* basic block (#2), we save the loop endpoint; if we knew x was live in
|
||||
* the next iteration then a new lifetime would be made here. At #1 we
|
||||
* mark x live again, make a segment between the head of the loop and #1,
|
||||
* and then extend x with loop tail lifetimes from #1 to #2, and from #3
|
||||
* to the back edge.
|
||||
* Just before analyzing the while statement, there would be a live range
|
||||
* from #1..#2 and a "point range" at #3. The job of extendVariable is to
|
||||
* create a new live range from #3..#4.
|
||||
*
|
||||
* However, more extensions may be required if the definition of x is
|
||||
* conditional. Consider the following.
|
||||
*
|
||||
* while (...) { (#1)
|
||||
* use x; (#2)
|
||||
* ...
|
||||
* if (...) (#5)
|
||||
* x = ...; (#3)
|
||||
* ...
|
||||
* } (#4)
|
||||
*
|
||||
* Assume that x is not used after the loop. Then, before extendVariable is
|
||||
* run, the live ranges would be the same as before (#1..#2 and #3..#3). We
|
||||
* still need to create a range from #3..#4. But, since the assignment at #3
|
||||
* may never run, we also need to create a range from #2..#3. This is done
|
||||
* as follows.
|
||||
*
|
||||
* Each time we create a Lifetime, we store the start of the most recently
|
||||
* seen sequence of conditional code in the Lifetime's savedEnd field. So,
|
||||
* when creating the Lifetime at #2, we set the Lifetime's savedEnd to
|
||||
* #5. (The start of the most recent conditional is cached in each
|
||||
* variable's savedEnd field.) Consequently, extendVariable is able to
|
||||
* create a new interval from #2..#5 using the savedEnd field of the
|
||||
* existing #1..#2 interval.
|
||||
*/
|
||||
|
||||
Lifetime *segment = var.lifetime;
|
||||
|
|
|
@ -720,8 +720,6 @@ JSRuntime::JSRuntime()
|
|||
gcUserAvailableChunkListHead(NULL),
|
||||
gcKeepAtoms(0),
|
||||
gcBytes(0),
|
||||
gcTriggerBytes(0),
|
||||
gcLastBytes(0),
|
||||
gcMaxBytes(0),
|
||||
gcMaxMallocBytes(0),
|
||||
gcNumArenasFreeCommitted(0),
|
||||
|
|
|
@ -284,8 +284,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||
js::GCLocks gcLocksHash;
|
||||
jsrefcount gcKeepAtoms;
|
||||
size_t gcBytes;
|
||||
size_t gcTriggerBytes;
|
||||
size_t gcLastBytes;
|
||||
size_t gcMaxBytes;
|
||||
size_t gcMaxMallocBytes;
|
||||
|
||||
|
@ -540,9 +538,6 @@ struct JSRuntime : js::RuntimeFriendFields
|
|||
|
||||
JSRuntime *thisFromCtor() { return this; }
|
||||
|
||||
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||
void reduceGCTriggerBytes(size_t amount);
|
||||
|
||||
/*
|
||||
* Call the system malloc while checking for GC memory pressure and
|
||||
* reporting OOM error when cx is not null. We will not GC from here.
|
||||
|
|
|
@ -784,10 +784,8 @@ Chunk::releaseArena(ArenaHeader *aheader)
|
|||
JS_ASSERT(rt->gcBytes >= ArenaSize);
|
||||
JS_ASSERT(comp->gcBytes >= ArenaSize);
|
||||
#ifdef JS_THREADSAFE
|
||||
if (rt->gcHelperThread.sweeping()) {
|
||||
rt->reduceGCTriggerBytes(GC_HEAP_GROWTH_FACTOR * ArenaSize);
|
||||
if (rt->gcHelperThread.sweeping())
|
||||
comp->reduceGCTriggerBytes(GC_HEAP_GROWTH_FACTOR * ArenaSize);
|
||||
}
|
||||
#endif
|
||||
rt->gcBytes -= ArenaSize;
|
||||
comp->gcBytes -= ArenaSize;
|
||||
|
@ -893,12 +891,6 @@ js_InitGC(JSRuntime *rt, uint32_t maxbytes)
|
|||
rt->gcMaxBytes = maxbytes;
|
||||
rt->setGCMaxMallocBytes(maxbytes);
|
||||
|
||||
/*
|
||||
* The assigned value prevents GC from running when GC memory is too low
|
||||
* (during JS engine start).
|
||||
*/
|
||||
rt->setGCLastBytes(8192, GC_NORMAL);
|
||||
|
||||
rt->gcJitReleaseTime = PRMJ_Now() + JIT_SCRIPT_RELEASE_TYPES_INTERVAL;
|
||||
return true;
|
||||
}
|
||||
|
@ -1355,25 +1347,6 @@ js_MapGCRoots(JSRuntime *rt, JSGCRootMapFun map, void *data)
|
|||
return ct;
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
||||
{
|
||||
gcLastBytes = lastBytes;
|
||||
|
||||
size_t base = gckind == GC_SHRINK ? lastBytes : Max(lastBytes, GC_ALLOCATION_THRESHOLD);
|
||||
float trigger = float(base) * GC_HEAP_GROWTH_FACTOR;
|
||||
gcTriggerBytes = size_t(Min(float(gcMaxBytes), trigger));
|
||||
}
|
||||
|
||||
void
|
||||
JSRuntime::reduceGCTriggerBytes(size_t amount) {
|
||||
JS_ASSERT(amount > 0);
|
||||
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||
if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
|
||||
return;
|
||||
gcTriggerBytes -= amount;
|
||||
}
|
||||
|
||||
void
|
||||
JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
||||
{
|
||||
|
@ -1385,7 +1358,8 @@ JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
|||
}
|
||||
|
||||
void
|
||||
JSCompartment::reduceGCTriggerBytes(size_t amount) {
|
||||
JSCompartment::reduceGCTriggerBytes(size_t amount)
|
||||
{
|
||||
JS_ASSERT(amount > 0);
|
||||
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||
if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
|
||||
|
@ -1891,26 +1865,6 @@ gc_lock_traversal(const GCLocks::Entry &entry, JSTracer *trc)
|
|||
MarkRootGCThing(trc, entry.key, "locked object");
|
||||
}
|
||||
|
||||
void
|
||||
js_TraceStackFrame(JSTracer *trc, StackFrame *fp)
|
||||
{
|
||||
MarkRoot(trc, &fp->scopeChain(), "scope chain");
|
||||
if (fp->isDummyFrame())
|
||||
return;
|
||||
if (fp->hasArgsObj())
|
||||
MarkRoot(trc, &fp->argsObj(), "arguments");
|
||||
if (fp->isFunctionFrame()) {
|
||||
MarkRoot(trc, fp->fun(), "fun");
|
||||
if (fp->isEvalFrame()) {
|
||||
MarkRoot(trc, fp->script(), "eval script");
|
||||
}
|
||||
} else {
|
||||
MarkRoot(trc, fp->script(), "script");
|
||||
}
|
||||
fp->script()->compartment()->active = true;
|
||||
MarkRoot(trc, fp->returnValue(), "rval");
|
||||
}
|
||||
|
||||
void
|
||||
AutoIdArray::trace(JSTracer *trc)
|
||||
{
|
||||
|
@ -2121,6 +2075,12 @@ MarkRuntime(JSTracer *trc)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/* We need to expand inline frames before stack scanning. */
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
mjit::ExpandInlineFrames(c);
|
||||
#endif
|
||||
|
||||
rt->stackSpace.mark(trc);
|
||||
|
||||
/* The embedding can register additional roots here. */
|
||||
|
@ -2173,12 +2133,6 @@ TriggerCompartmentGC(JSCompartment *comp, gcreason::Reason reason)
|
|||
return;
|
||||
}
|
||||
|
||||
if (rt->gcBytes > 8192 && rt->gcBytes >= 3 * (rt->gcTriggerBytes / 2)) {
|
||||
/* If we're using significantly more than our quota, do a full GC. */
|
||||
TriggerGC(rt, reason);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Trigger the GC when it is safe to call an operation callback on any
|
||||
* thread.
|
||||
|
@ -2966,7 +2920,6 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
#endif
|
||||
|
||||
rt->gcMarkAndSweep = false;
|
||||
rt->setGCLastBytes(rt->gcBytes, gckind);
|
||||
rt->gcCurrentCompartment = NULL;
|
||||
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next())
|
||||
|
|
|
@ -1371,9 +1371,6 @@ IsAboutToBeFinalized(const js::gc::Cell *thing);
|
|||
extern bool
|
||||
IsAboutToBeFinalized(const js::Value &value);
|
||||
|
||||
extern void
|
||||
js_TraceStackFrame(JSTracer *trc, js::StackFrame *fp);
|
||||
|
||||
extern bool
|
||||
js_IsAddressableGCThing(JSRuntime *rt, uintptr_t w, js::gc::AllocKind *thingKind, void **thing);
|
||||
|
||||
|
|
|
@ -1029,6 +1029,12 @@ SuppressDeletedPropertyHelper(JSContext *cx, JSObject *obj, StringPredicate pred
|
|||
for (HeapPtr<JSFlatString> *p = idp; p + 1 != props_end; p++)
|
||||
*p = *(p + 1);
|
||||
ni->props_end = ni->end() - 1;
|
||||
|
||||
/*
|
||||
* Invoke the write barrier on this element, since it's
|
||||
* no longer going to be marked.
|
||||
*/
|
||||
ni->props_end->HeapPtr<JSFlatString>::~HeapPtr<JSFlatString>();
|
||||
}
|
||||
|
||||
/* Don't reuse modified native iterators. */
|
||||
|
@ -1379,7 +1385,7 @@ MarkGenerator(JSTracer *trc, JSGenerator *gen)
|
|||
* this code and save someone an hour later.
|
||||
*/
|
||||
MarkStackRangeConservatively(trc, gen->floatingStack, fp->formalArgsEnd());
|
||||
js_TraceStackFrame(trc, fp);
|
||||
fp->mark(trc);
|
||||
MarkStackRangeConservatively(trc, fp->slots(), gen->regs.sp);
|
||||
}
|
||||
|
||||
|
|
|
@ -410,7 +410,7 @@ mjit::Compiler::pushActiveFrame(JSScript *script, uint32_t argc)
|
|||
if (cx->runtime->profilingScripts && !script->pcCounters)
|
||||
script->initCounts(cx);
|
||||
|
||||
ActiveFrame *newa = cx->new_<ActiveFrame>(cx);
|
||||
ActiveFrame *newa = OffTheBooks::new_<ActiveFrame>(cx);
|
||||
if (!newa)
|
||||
return Compile_Error;
|
||||
|
||||
|
@ -459,7 +459,7 @@ mjit::Compiler::pushActiveFrame(JSScript *script, uint32_t argc)
|
|||
return Compile_Error;
|
||||
}
|
||||
|
||||
newa->jumpMap = (Label *)cx->malloc_(sizeof(Label) * script->length);
|
||||
newa->jumpMap = (Label *)OffTheBooks::malloc_(sizeof(Label) * script->length);
|
||||
if (!newa->jumpMap) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return Compile_Error;
|
||||
|
@ -618,7 +618,7 @@ mjit::Compiler::prepareInferenceTypes(JSScript *script, ActiveFrame *a)
|
|||
*/
|
||||
|
||||
a->varTypes = (VarType *)
|
||||
cx->calloc_(TotalSlots(script) * sizeof(VarType));
|
||||
OffTheBooks::calloc_(TotalSlots(script) * sizeof(VarType));
|
||||
if (!a->varTypes)
|
||||
return Compile_Error;
|
||||
|
||||
|
@ -871,7 +871,7 @@ MakeJITScript(JSContext *cx, JSScript *script, bool construct)
|
|||
size_t dataSize = sizeof(JITScript)
|
||||
+ (chunks.length() * sizeof(ChunkDescriptor))
|
||||
+ (edges.length() * sizeof(CrossChunkEdge));
|
||||
uint8_t *cursor = (uint8_t *) cx->calloc_(dataSize);
|
||||
uint8_t *cursor = (uint8_t *) OffTheBooks::calloc_(dataSize);
|
||||
if (!cursor)
|
||||
return NULL;
|
||||
|
||||
|
@ -1204,7 +1204,7 @@ mjit::Compiler::generatePrologue()
|
|||
|
||||
if (outerScript->pcCounters || Probes::wantNativeAddressInfo(cx)) {
|
||||
size_t length = ssa.frameLength(ssa.numFrames() - 1);
|
||||
pcLengths = (PCLengthEntry *) cx->calloc_(sizeof(pcLengths[0]) * length);
|
||||
pcLengths = (PCLengthEntry *) OffTheBooks::calloc_(sizeof(pcLengths[0]) * length);
|
||||
if (!pcLengths)
|
||||
return Compile_Error;
|
||||
}
|
||||
|
@ -1352,7 +1352,7 @@ mjit::Compiler::finishThisUp()
|
|||
#endif
|
||||
0;
|
||||
|
||||
uint8_t *cursor = (uint8_t *)cx->calloc_(dataSize);
|
||||
uint8_t *cursor = (uint8_t *)OffTheBooks::calloc_(dataSize);
|
||||
if (!cursor) {
|
||||
execPool->release();
|
||||
js_ReportOutOfMemory(cx);
|
||||
|
@ -1804,7 +1804,7 @@ mjit::Compiler::finishThisUp()
|
|||
ChunkJumpTableEdge nedge = chunkJumps[j];
|
||||
if (nedge.edge.source == edge.source && nedge.edge.target == edge.target) {
|
||||
if (!jumpTableEntries) {
|
||||
jumpTableEntries = cx->new_<CrossChunkEdge::JumpTableEntryVector>();
|
||||
jumpTableEntries = OffTheBooks::new_<CrossChunkEdge::JumpTableEntryVector>();
|
||||
if (!jumpTableEntries)
|
||||
failed = true;
|
||||
}
|
||||
|
@ -5627,16 +5627,18 @@ mjit::Compiler::jsop_setprop(PropertyName *name, bool popGuaranteed)
|
|||
if (script->pcCounters)
|
||||
bumpPropCounter(PC, OpcodeCounts::PROP_OTHER);
|
||||
|
||||
JSOp op = JSOp(*PC);
|
||||
|
||||
#ifdef JSGC_INCREMENTAL_MJ
|
||||
/* Write barrier. */
|
||||
if (cx->compartment->needsBarrier() && (!types || types->propertyNeedsBarrier(cx, id))) {
|
||||
/* Write barrier. We don't have type information for JSOP_SETNAME. */
|
||||
if (cx->compartment->needsBarrier() &&
|
||||
(!types || op == JSOP_SETNAME || types->propertyNeedsBarrier(cx, id)))
|
||||
{
|
||||
jsop_setprop_slow(name);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
JSOp op = JSOp(*PC);
|
||||
|
||||
ic::PICInfo::Kind kind = (op == JSOP_SETMETHOD)
|
||||
? ic::PICInfo::SETMETHOD
|
||||
: ic::PICInfo::SET;
|
||||
|
@ -6978,7 +6980,7 @@ mjit::Compiler::startLoop(jsbytecode *head, Jump entry, jsbytecode *entryTarget)
|
|||
loop->clearLoopRegisters();
|
||||
}
|
||||
|
||||
LoopState *nloop = cx->new_<LoopState>(cx, &ssa, this, &frame);
|
||||
LoopState *nloop = OffTheBooks::new_<LoopState>(cx, &ssa, this, &frame);
|
||||
if (!nloop || !nloop->init(head, entry, entryTarget))
|
||||
return false;
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ FrameState::pushActiveFrame(JSScript *script, uint32_t argc)
|
|||
size_t totalBytes = sizeof(FrameEntry) * nentries + // entries[]
|
||||
sizeof(FrameEntry *) * nentries + // tracker.entries
|
||||
sizeof(StackEntryExtra) * nentries; // extraArray
|
||||
uint8_t *cursor = (uint8_t *)cx->calloc_(totalBytes);
|
||||
uint8_t *cursor = (uint8_t *)OffTheBooks::calloc_(totalBytes);
|
||||
if (!cursor)
|
||||
return false;
|
||||
|
||||
|
@ -120,7 +120,7 @@ FrameState::pushActiveFrame(JSScript *script, uint32_t argc)
|
|||
/* We should have already checked that argc == nargs */
|
||||
JS_ASSERT_IF(a, argc == script->function()->nargs);
|
||||
|
||||
ActiveFrame *newa = cx->new_<ActiveFrame>();
|
||||
ActiveFrame *newa = OffTheBooks::new_<ActiveFrame>();
|
||||
if (!newa)
|
||||
return false;
|
||||
|
||||
|
@ -2885,7 +2885,7 @@ FrameState::getTemporaryCopies(Uses uses)
|
|||
FrameEntry *nfe = tracker[i];
|
||||
if (!deadEntry(nfe, uses.nuses) && nfe->isCopy() && nfe->copyOf() == fe) {
|
||||
if (!res)
|
||||
res = cx->new_< Vector<TemporaryCopy> >(cx);
|
||||
res = OffTheBooks::new_< Vector<TemporaryCopy> >(cx);
|
||||
res->append(TemporaryCopy(addressOf(nfe), addressOf(fe)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ ImmutableSync::init(JSContext *cx, const FrameState &frame, uint32_t nentries)
|
|||
this->cx = cx;
|
||||
this->frame = &frame;
|
||||
|
||||
entries = (SyncEntry *)cx->calloc_(sizeof(SyncEntry) * nentries);
|
||||
entries = (SyncEntry *)OffTheBooks::calloc_(sizeof(SyncEntry) * nentries);
|
||||
return !!entries;
|
||||
}
|
||||
|
||||
|
|
|
@ -197,7 +197,7 @@ class BasePolyIC : public BaseIC {
|
|||
if (isOnePool()) {
|
||||
JSC::ExecutablePool *oldPool = u.execPool;
|
||||
JS_ASSERT(!isTagged(oldPool));
|
||||
ExecPoolVector *execPools = cx->new_<ExecPoolVector>(SystemAllocPolicy());
|
||||
ExecPoolVector *execPools = OffTheBooks::new_<ExecPoolVector>(SystemAllocPolicy());
|
||||
if (!execPools)
|
||||
return false;
|
||||
if (!execPools->append(oldPool) || !execPools->append(pool)) {
|
||||
|
|
|
@ -3885,6 +3885,10 @@ MJitChunkLimit(JSContext *cx, uintN argc, jsval *vp)
|
|||
mjit::SetChunkLimit((uint32_t) t);
|
||||
#endif
|
||||
|
||||
// Clear out analysis information which might refer to code compiled with
|
||||
// the previous chunk limit.
|
||||
JS_GC(cx);
|
||||
|
||||
vp->setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -211,6 +211,31 @@ StackFrame::pcQuadratic(const ContextStack &stack, StackFrame *next, JSInlinedSi
|
|||
return next->prevpc(pinlined);
|
||||
}
|
||||
|
||||
void
|
||||
StackFrame::mark(JSTracer *trc)
|
||||
{
|
||||
/*
|
||||
* Normally we would use MarkRoot here, except that generators also take
|
||||
* this path. However, generators use a special write barrier when the stack
|
||||
* frame is copied to the floating frame. Therefore, no barrier is needed.
|
||||
*/
|
||||
gc::MarkObjectUnbarriered(trc, &scopeChain(), "scope chain");
|
||||
if (isDummyFrame())
|
||||
return;
|
||||
if (hasArgsObj())
|
||||
gc::MarkObjectUnbarriered(trc, &argsObj(), "arguments");
|
||||
if (isFunctionFrame()) {
|
||||
gc::MarkObjectUnbarriered(trc, fun(), "fun");
|
||||
if (isEvalFrame())
|
||||
gc::MarkScriptUnbarriered(trc, script(), "eval script");
|
||||
} else {
|
||||
gc::MarkScriptUnbarriered(trc, script(), "script");
|
||||
}
|
||||
if (IS_GC_MARKING_TRACER(trc))
|
||||
script()->compartment()->active = true;
|
||||
gc::MarkValueUnbarriered(trc, returnValue(), "rval");
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
bool
|
||||
|
@ -381,6 +406,51 @@ StackSpace::containingSegment(const StackFrame *target) const
|
|||
return *(StackSegment *)NULL;
|
||||
}
|
||||
|
||||
void
|
||||
StackSpace::markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc)
|
||||
{
|
||||
Value *slotsBegin = fp->slots();
|
||||
|
||||
if (!fp->isScriptFrame()) {
|
||||
JS_ASSERT(fp->isDummyFrame());
|
||||
gc::MarkRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's a scripted frame, we should have a pc. */
|
||||
JS_ASSERT(pc);
|
||||
|
||||
JSScript *script = fp->script();
|
||||
if (!script->hasAnalysis() || !script->analysis()->ranLifetimes()) {
|
||||
gc::MarkRootRange(trc, slotsBegin, slotsEnd, "vm_stack");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the JIT ran a lifetime analysis, then it may have left garbage in the
|
||||
* slots considered not live. We need to avoid marking them. Additionally,
|
||||
* in case the analysis information is thrown out later, we overwrite these
|
||||
* dead slots with valid values so that future GCs won't crash. Analysis
|
||||
* results are thrown away during the sweeping phase, so we always have at
|
||||
* least one GC to do this.
|
||||
*/
|
||||
analyze::AutoEnterAnalysis aea(script->compartment());
|
||||
analyze::ScriptAnalysis *analysis = script->analysis();
|
||||
uint32_t offset = pc - script->code;
|
||||
Value *fixedEnd = slotsBegin + script->nfixed;
|
||||
for (Value *vp = slotsBegin; vp < fixedEnd; vp++) {
|
||||
uint32_t slot = analyze::LocalSlot(script, vp - slotsBegin);
|
||||
|
||||
/* Will this slot be synced by the JIT? */
|
||||
if (!analysis->trackSlot(slot) || analysis->liveness(slot).live(offset))
|
||||
gc::MarkRoot(trc, *vp, "vm_stack");
|
||||
else
|
||||
*vp = UndefinedValue();
|
||||
}
|
||||
|
||||
gc::MarkRootRange(trc, fixedEnd, slotsEnd, "vm_stack");
|
||||
}
|
||||
|
||||
void
|
||||
StackSpace::mark(JSTracer *trc)
|
||||
{
|
||||
|
@ -401,15 +471,21 @@ StackSpace::mark(JSTracer *trc)
|
|||
* calls. Thus, marking can view the stack as the regex:
|
||||
* (segment slots (frame slots)*)*
|
||||
* which gets marked in reverse order.
|
||||
*
|
||||
*/
|
||||
Value *slotsEnd = nextSegEnd;
|
||||
jsbytecode *pc = seg->maybepc();
|
||||
for (StackFrame *fp = seg->maybefp(); (Value *)fp > (Value *)seg; fp = fp->prev()) {
|
||||
MarkStackRangeConservatively(trc, fp->slots(), slotsEnd);
|
||||
js_TraceStackFrame(trc, fp);
|
||||
/* Mark from fp->slots() to slotsEnd. */
|
||||
markFrameSlots(trc, fp, slotsEnd, pc);
|
||||
|
||||
fp->mark(trc);
|
||||
slotsEnd = (Value *)fp;
|
||||
|
||||
JSInlinedSite *site;
|
||||
pc = fp->prevpc(&site);
|
||||
JS_ASSERT_IF(fp->prev(), !site);
|
||||
}
|
||||
MarkStackRangeConservatively(trc, seg->slotsBegin(), slotsEnd);
|
||||
gc::MarkRootRange(trc, seg->slotsBegin(), slotsEnd, "vm_stack");
|
||||
nextSegEnd = (Value *)seg;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
|
@ -1193,6 +1193,9 @@ class StackFrame
|
|||
#endif
|
||||
|
||||
void methodjitStaticAsserts();
|
||||
|
||||
public:
|
||||
void mark(JSTracer *trc);
|
||||
};
|
||||
|
||||
static const size_t VALUES_PER_STACK_FRAME = sizeof(StackFrame) / sizeof(Value);
|
||||
|
@ -1365,6 +1368,10 @@ class StackSegment
|
|||
return regs_ ? regs_->fp() : NULL;
|
||||
}
|
||||
|
||||
jsbytecode *maybepc() const {
|
||||
return regs_ ? regs_->pc : NULL;
|
||||
}
|
||||
|
||||
CallArgsList &calls() const {
|
||||
JS_ASSERT(calls_);
|
||||
return *calls_;
|
||||
|
@ -1535,6 +1542,7 @@ class StackSpace
|
|||
|
||||
/* Called during GC: mark segments, frames, and slots under firstUnused. */
|
||||
void mark(JSTracer *trc);
|
||||
void markFrameSlots(JSTracer *trc, StackFrame *fp, Value *slotsEnd, jsbytecode *pc);
|
||||
|
||||
/* We only report the committed size; uncommitted size is uninteresting. */
|
||||
JS_FRIEND_API(size_t) sizeOfCommitted();
|
||||
|
|
|
@ -582,11 +582,19 @@ inline void XPCNativeSet::ASSERT_NotMarked()
|
|||
/***************************************************************************/
|
||||
|
||||
inline
|
||||
JSObject* XPCWrappedNativeTearOff::GetJSObject() const
|
||||
JSObject* XPCWrappedNativeTearOff::GetJSObjectPreserveColor() const
|
||||
{
|
||||
return mJSObject;
|
||||
}
|
||||
|
||||
inline
|
||||
JSObject* XPCWrappedNativeTearOff::GetJSObject()
|
||||
{
|
||||
JSObject *obj = GetJSObjectPreserveColor();
|
||||
xpc_UnmarkGrayObject(obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
inline
|
||||
void XPCWrappedNativeTearOff::SetJSObject(JSObject* JSObj)
|
||||
{
|
||||
|
@ -596,7 +604,7 @@ void XPCWrappedNativeTearOff::SetJSObject(JSObject* JSObj)
|
|||
inline
|
||||
XPCWrappedNativeTearOff::~XPCWrappedNativeTearOff()
|
||||
{
|
||||
NS_ASSERTION(!(GetInterface()||GetNative()||GetJSObject()), "tearoff not empty in dtor");
|
||||
NS_ASSERTION(!(GetInterface()||GetNative()||GetJSObjectPreserveColor()), "tearoff not empty in dtor");
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
@ -621,7 +629,7 @@ XPCWrappedNative::SweepTearOffs()
|
|||
|
||||
// If this tearoff does not have a live dedicated JSObject,
|
||||
// then let's recycle it.
|
||||
if (!to->GetJSObject()) {
|
||||
if (!to->GetJSObjectPreserveColor()) {
|
||||
nsISupports* obj = to->GetNative();
|
||||
if (obj) {
|
||||
obj->Release();
|
||||
|
|
|
@ -171,7 +171,7 @@ XPCWrappedNative::NoteTearoffs(nsCycleCollectionTraversalCallback& cb)
|
|||
for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
|
||||
XPCWrappedNativeTearOff* to = chunk->mTearOffs;
|
||||
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
|
||||
JSObject* jso = to->GetJSObject();
|
||||
JSObject* jso = to->GetJSObjectPreserveColor();
|
||||
if (!jso) {
|
||||
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "tearoff's mNative");
|
||||
cb.NoteXPCOMChild(to->GetNative());
|
||||
|
@ -1259,7 +1259,7 @@ XPCWrappedNative::FlatJSObjectFinalized()
|
|||
for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
|
||||
XPCWrappedNativeTearOff* to = chunk->mTearOffs;
|
||||
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
|
||||
JSObject* jso = to->GetJSObject();
|
||||
JSObject* jso = to->GetJSObjectPreserveColor();
|
||||
if (jso) {
|
||||
NS_ASSERTION(JS_IsAboutToBeFinalized(jso), "bad!");
|
||||
JS_SetPrivate(jso, nsnull);
|
||||
|
@ -1363,8 +1363,8 @@ XPCWrappedNative::SystemIsBeingShutDown()
|
|||
for (chunk = &mFirstChunk; chunk; chunk = chunk->mNextChunk) {
|
||||
XPCWrappedNativeTearOff* to = chunk->mTearOffs;
|
||||
for (int i = XPC_WRAPPED_NATIVE_TEAROFFS_PER_CHUNK-1; i >= 0; i--, to++) {
|
||||
if (to->GetJSObject()) {
|
||||
JS_SetPrivate(to->GetJSObject(), nsnull);
|
||||
if (JSObject *jso = to->GetJSObjectPreserveColor()) {
|
||||
JS_SetPrivate(jso, nsnull);
|
||||
to->SetJSObject(nsnull);
|
||||
}
|
||||
// We leak the tearoff mNative
|
||||
|
@ -1777,7 +1777,7 @@ XPCWrappedNative::FindTearOff(XPCCallContext& ccx,
|
|||
to < end;
|
||||
to++) {
|
||||
if (to->GetInterface() == aInterface) {
|
||||
if (needJSObject && !to->GetJSObject()) {
|
||||
if (needJSObject && !to->GetJSObjectPreserveColor()) {
|
||||
AutoMarkingWrappedNativeTearOffPtr tearoff(ccx, to);
|
||||
JSBool ok = InitTearOffJSObject(ccx, to);
|
||||
// During shutdown, we don't sweep tearoffs. So make sure
|
||||
|
|
|
@ -327,6 +327,8 @@ XPCWrappedNativeScope::GetPrototypeNoHelper(XPCCallContext& ccx)
|
|||
|
||||
NS_ASSERTION(mPrototypeNoHelper,
|
||||
"Failed to create prototype for wrappers w/o a helper");
|
||||
} else {
|
||||
xpc_UnmarkGrayObject(mPrototypeNoHelper);
|
||||
}
|
||||
|
||||
return mPrototypeNoHelper;
|
||||
|
|
|
@ -491,8 +491,10 @@ ListBase<LC>::getPrototype(JSContext *cx, XPCWrappedNativeScope *scope)
|
|||
|
||||
JSObject *interfacePrototype;
|
||||
if (cache.IsInitialized()) {
|
||||
if (cache.Get(sInterfaceClass.name, &interfacePrototype))
|
||||
if (cache.Get(sInterfaceClass.name, &interfacePrototype)) {
|
||||
xpc_UnmarkGrayObject(interfacePrototype);
|
||||
return interfacePrototype;
|
||||
}
|
||||
} else if (!cache.Init()) {
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -2382,7 +2382,8 @@ public:
|
|||
|
||||
XPCNativeInterface* GetInterface() const {return mInterface;}
|
||||
nsISupports* GetNative() const {return mNative;}
|
||||
JSObject* GetJSObject() const;
|
||||
JSObject* GetJSObject();
|
||||
JSObject* GetJSObjectPreserveColor() const;
|
||||
void SetInterface(XPCNativeInterface* Interface) {mInterface = Interface;}
|
||||
void SetNative(nsISupports* Native) {mNative = Native;}
|
||||
void SetJSObject(JSObject* JSObj);
|
||||
|
|
|
@ -103,8 +103,10 @@ WrapperFactory::WaiveXray(JSContext *cx, JSObject *obj)
|
|||
CompartmentPrivate *priv =
|
||||
(CompartmentPrivate *)JS_GetCompartmentPrivate(cx, js::GetObjectCompartment(obj));
|
||||
JSObject *wobj = nsnull;
|
||||
if (priv && priv->waiverWrapperMap)
|
||||
if (priv && priv->waiverWrapperMap) {
|
||||
wobj = priv->waiverWrapperMap->Find(obj);
|
||||
xpc_UnmarkGrayObject(wobj);
|
||||
}
|
||||
|
||||
// No wrapper yet, make one.
|
||||
if (!wobj) {
|
||||
|
|
|
@ -16,6 +16,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=36619
|
|||
<input id='a' type='file'>
|
||||
</div>
|
||||
<button id='b' onclick="document.getElementById('a').click();">Show Filepicker</button>
|
||||
<button id='c' onmousedown="document.getElementById('a').click();">Show Filepicker</button>
|
||||
<button id='d' onmouseup="document.getElementById('a').click();">Show Filepicker</button>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
|
@ -36,7 +38,7 @@ SpecialPowers.pushPrefEnv({'set': [
|
|||
// Tests that a click on 'b' calls the show method.
|
||||
var b = document.getElementById('b');
|
||||
b.focus(); // Be sure the element is visible.
|
||||
synthesizeMouse(b, 2, 2, {});
|
||||
synthesizeMouseAtCenter(b, {});
|
||||
SimpleTest.executeSoon(function() {
|
||||
ok(MockFilePicker.shown, "File picker show method should have been called");
|
||||
MockFilePicker.reset();
|
||||
|
@ -45,9 +47,21 @@ SpecialPowers.pushPrefEnv({'set': [
|
|||
document.getElementById("a").click();
|
||||
SimpleTest.executeSoon(function() {
|
||||
ok(!MockFilePicker.shown, "File picker show method should not have been called");
|
||||
MockFilePicker.cleanup();
|
||||
MockFilePicker.reset();
|
||||
|
||||
SimpleTest.finish();
|
||||
synthesizeMouseAtCenter(document.getElementById('c'), {});
|
||||
SimpleTest.executeSoon(function() {
|
||||
ok(!MockFilePicker.shown, "File picker show method should have been called");
|
||||
MockFilePicker.reset();
|
||||
|
||||
synthesizeMouseAtCenter(document.getElementById('d'), {});
|
||||
SimpleTest.executeSoon(function() {
|
||||
ok(MockFilePicker.shown, "File picker show method should have been called");
|
||||
|
||||
MockFilePicker.cleanup();
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1236,6 +1236,7 @@ nsCSSValue::SizeOfExcludingThis(nsMallocSizeOfFun aMallocSizeOf) const
|
|||
case eCSSUnit_Pixel:
|
||||
case eCSSUnit_Degree:
|
||||
case eCSSUnit_Grad:
|
||||
case eCSSUnit_Turn:
|
||||
case eCSSUnit_Radian:
|
||||
case eCSSUnit_Hertz:
|
||||
case eCSSUnit_Kilohertz:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
[testFlingCorrectness]
|
||||
[testOverscroll]
|
||||
[testAxisLocking]
|
||||
[testAboutPage]
|
||||
|
||||
# Used for Talos, please don't use in mochitest
|
||||
#[testPan]
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
|
||||
public class testAboutPage extends BaseTest {
|
||||
public void testAboutPage() {
|
||||
setTestType("mochitest");
|
||||
mActions.expectGeckoEvent("Gecko:Ready").blockForEvent();
|
||||
|
||||
// Load the about: page
|
||||
String url = "about:";
|
||||
loadUrl(url);
|
||||
|
||||
Element awesomebar = mDriver.findElement(getActivity(), "awesome_bar");
|
||||
mAsserter.ok(awesomebar.getText().matches("About (Fennec|Nightly|Aurora|Firefox)"), "page title match", "about: page title is correct");
|
||||
|
||||
// Open a new page to remove the about: page from the current tab
|
||||
url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
|
||||
loadUrl(url);
|
||||
|
||||
// Use the menu to open the Settings
|
||||
mActions.sendSpecialKey(Actions.SpecialKey.MENU);
|
||||
|
||||
// Look for the 'More' menu if this device/OS uses it
|
||||
if (mSolo.waitForText("^More$")) {
|
||||
mSolo.clickOnText("^More$");
|
||||
}
|
||||
|
||||
mSolo.waitForText("^Settings$");
|
||||
mSolo.clickOnText("^Settings$");
|
||||
|
||||
// Tap on the "About Xxxx" setting
|
||||
mSolo.waitForText("About (Fennec|Nightly|Aurora|Firefox)");
|
||||
mSolo.clickOnText("About (Fennec|Nightly|Aurora|Firefox)");
|
||||
|
||||
// Wait for the new tab and page to load
|
||||
mActions.expectGeckoEvent("Tab:Added").blockForEvent();
|
||||
mActions.expectGeckoEvent("DOMContentLoaded").blockForEvent();
|
||||
|
||||
// Grab the title to make sure the about: page was loaded
|
||||
awesomebar = mDriver.findElement(getActivity(), "awesome_bar");
|
||||
mAsserter.ok(awesomebar.getText().matches("About (Fennec|Nightly|Aurora|Firefox)"), "page title match", "about: page title is correct");
|
||||
}
|
||||
}
|
|
@ -416,7 +416,7 @@ ProcessSoftwareUpdateCommand(DWORD argc, LPWSTR *argv)
|
|||
GetLastError()));
|
||||
}
|
||||
}
|
||||
LocalFree(argv);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,8 @@ Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
|
|||
const PATH = "/submit/telemetry/test-ping";
|
||||
const SERVER = "http://localhost:4444";
|
||||
const IGNORE_HISTOGRAM = "test::ignore_me";
|
||||
const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED"
|
||||
const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also"
|
||||
const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
|
||||
const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also";
|
||||
|
||||
const BinaryInputStream = Components.Constructor(
|
||||
"@mozilla.org/binaryinputstream;1",
|
||||
|
@ -61,7 +61,7 @@ function checkHistograms(request, response) {
|
|||
.decodeFromStream(s, s.available());
|
||||
|
||||
do_check_eq(request.getHeader("content-type"), "application/json; charset=UTF-8");
|
||||
do_check_true(payload.simpleMeasurements.uptime >= 0)
|
||||
do_check_true(payload.simpleMeasurements.uptime >= 0);
|
||||
do_check_true(payload.simpleMeasurements.startupInterrupted === 1);
|
||||
// get rid of the non-deterministic field
|
||||
const expected_info = {
|
||||
|
@ -78,12 +78,19 @@ function checkHistograms(request, response) {
|
|||
do_check_eq(payload.info[f], expected_info[f]);
|
||||
}
|
||||
|
||||
var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
var isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
try {
|
||||
// If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
|
||||
// this test.
|
||||
var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
var isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
|
||||
var isOSX = ("nsILocalFileMac" in Components.interfaces);
|
||||
|
||||
if (isWindows || isOSX) {
|
||||
do_check_true("adapterVendorID" in payload.info);
|
||||
do_check_true("adapterDeviceID" in payload.info);
|
||||
if (isWindows || isOSX) {
|
||||
do_check_true("adapterVendorID" in payload.info);
|
||||
do_check_true("adapterDeviceID" in payload.info);
|
||||
}
|
||||
}
|
||||
catch (x) {
|
||||
}
|
||||
|
||||
const TELEMETRY_PING = "TELEMETRY_PING";
|
||||
|
@ -105,8 +112,8 @@ function checkHistograms(request, response) {
|
|||
histogram_type: 2,
|
||||
values: {0:1, 1:1, 2:0},
|
||||
sum: 1
|
||||
}
|
||||
let tc = payload.histograms[TELEMETRY_SUCCESS]
|
||||
};
|
||||
let tc = payload.histograms[TELEMETRY_SUCCESS];
|
||||
do_check_eq(uneval(tc),
|
||||
uneval(expected_tc));
|
||||
|
||||
|
@ -176,6 +183,14 @@ function dummyTheme(id) {
|
|||
}
|
||||
|
||||
function run_test() {
|
||||
try {
|
||||
var gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
|
||||
gfxInfo.spoofVendorID("0xabcd");
|
||||
gfxInfo.spoofDeviceID("0x1234");
|
||||
} catch (x) {
|
||||
// If we can't test gfxInfo, that's fine, we'll note it later.
|
||||
}
|
||||
|
||||
// Addon manager needs a profile directory
|
||||
do_get_profile();
|
||||
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
|
||||
|
@ -192,5 +207,5 @@ function run_test() {
|
|||
// spin the event loop
|
||||
do_test_pending();
|
||||
// ensure that test runs to completion
|
||||
do_register_cleanup(function () do_check_true(gFinished))
|
||||
do_register_cleanup(function () do_check_true(gFinished));
|
||||
}
|
||||
|
|
|
@ -85,16 +85,12 @@ CPPSRCS += \
|
|||
$(NULL)
|
||||
endif
|
||||
ifeq ($(OS_TARGET),Darwin)
|
||||
# For now we use platform-linux.cc because we can't unwind
|
||||
# another thread on mac using backtrace(), the implementation
|
||||
# for platform-macosx.cc is in the hg history and should be
|
||||
# used when we can stackwalk using a thread handle.
|
||||
|
||||
DEFINES += -DMOZ_ENABLE_PROFILER_SPS
|
||||
|
||||
CPPSRCS += \
|
||||
shared-libraries-macos.cc \
|
||||
platform-linux.cc \
|
||||
platform-macos.cc \
|
||||
TableTicker.cpp \
|
||||
$(NULL)
|
||||
endif
|
||||
|
|
|
@ -45,9 +45,10 @@
|
|||
#include "prenv.h"
|
||||
#include "shared-libraries.h"
|
||||
#include "mozilla/StringBuilder.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
|
||||
// we eventually want to make this runtime switchable
|
||||
#if defined(MOZ_PROFILING) && (defined(XP_MACOSX) || defined(XP_UNIX))
|
||||
#if defined(MOZ_PROFILING) && (defined(XP_UNIX) && !defined(XP_MACOSX))
|
||||
#ifndef ANDROID
|
||||
#define USE_BACKTRACE
|
||||
#endif
|
||||
|
@ -56,7 +57,7 @@
|
|||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_PROFILING) && defined(XP_WIN)
|
||||
#if defined(MOZ_PROFILING) && (defined(XP_MACOSX) || defined(XP_WIN))
|
||||
#define USE_NS_STACKWALK
|
||||
#endif
|
||||
#ifdef USE_NS_STACKWALK
|
||||
|
@ -353,7 +354,7 @@ class TableTicker: public Sampler {
|
|||
|
||||
private:
|
||||
// Not implemented on platforms which do not support backtracing
|
||||
void doBacktrace(Profile &aProfile);
|
||||
void doBacktrace(Profile &aProfile, Address pc);
|
||||
|
||||
private:
|
||||
Profile mProfile;
|
||||
|
@ -419,8 +420,9 @@ void TableTicker::HandleSaveRequest()
|
|||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_BACKTRACE
|
||||
void TableTicker::doBacktrace(Profile &aProfile)
|
||||
void TableTicker::doBacktrace(Profile &aProfile, Address pc)
|
||||
{
|
||||
void *array[100];
|
||||
int count = backtrace (array, 100);
|
||||
|
@ -434,6 +436,7 @@ void TableTicker::doBacktrace(Profile &aProfile)
|
|||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef USE_NS_STACKWALK
|
||||
typedef struct {
|
||||
void** array;
|
||||
|
@ -452,17 +455,23 @@ void StackWalkCallback(void* aPC, void* aClosure)
|
|||
array->array[array->count++] = aPC;
|
||||
}
|
||||
|
||||
void TableTicker::doBacktrace(Profile &aProfile)
|
||||
void TableTicker::doBacktrace(Profile &aProfile, Address fp)
|
||||
{
|
||||
#ifndef XP_MACOSX
|
||||
uintptr_t thread = GetThreadHandle(platform_data());
|
||||
MOZ_ASSERT(thread);
|
||||
#endif
|
||||
void* pc_array[1000];
|
||||
PCArray array = {
|
||||
pc_array,
|
||||
mozilla::ArrayLength(pc_array),
|
||||
0
|
||||
};
|
||||
#ifdef XP_MACOSX
|
||||
nsresult rv = FramePointerStackWalk(StackWalkCallback, 1, &array, reinterpret_cast<void**>(fp));
|
||||
#else
|
||||
nsresult rv = NS_StackWalk(StackWalkCallback, 0, &array, thread);
|
||||
#endif
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
aProfile.addTag(ProfileEntry('s', "(root)", 0));
|
||||
|
||||
|
@ -539,7 +548,7 @@ void TableTicker::Tick(TickSample* sample)
|
|||
|
||||
#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
|
||||
if (mUseStackWalk) {
|
||||
doBacktrace(mProfile);
|
||||
doBacktrace(mProfile, sample->fp);
|
||||
} else {
|
||||
doSampleStackTrace(mStack, mProfile, sample);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,309 @@
|
|||
#include <dlfcn.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <mach/mach_init.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <mach-o/getsect.h>
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <libkern/OSAtomic.h>
|
||||
#include <mach/mach.h>
|
||||
#include <mach/semaphore.h>
|
||||
#include <mach/task.h>
|
||||
#include <mach/vm_statistics.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
// this port is based off of v8 svn revision 9837
|
||||
|
||||
// XXX: this is a very stubbed out implementation
|
||||
// that only supports a single Sampler
|
||||
struct SamplerRegistry {
|
||||
static void AddActiveSampler(Sampler *sampler) {
|
||||
ASSERT(!SamplerRegistry::sampler);
|
||||
SamplerRegistry::sampler = sampler;
|
||||
}
|
||||
static void RemoveActiveSampler(Sampler *sampler) {
|
||||
SamplerRegistry::sampler = NULL;
|
||||
}
|
||||
static Sampler *sampler;
|
||||
};
|
||||
|
||||
Sampler *SamplerRegistry::sampler = NULL;
|
||||
|
||||
// 0 is never a valid thread id on MacOSX since a ptread_t is
|
||||
// a pointer.
|
||||
static const pthread_t kNoThread = (pthread_t) 0;
|
||||
|
||||
class MacOSMutex : public Mutex {
|
||||
public:
|
||||
MacOSMutex() {
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&mutex_, &attr);
|
||||
}
|
||||
|
||||
virtual ~MacOSMutex() { pthread_mutex_destroy(&mutex_); }
|
||||
|
||||
virtual int Lock() { return pthread_mutex_lock(&mutex_); }
|
||||
virtual int Unlock() { return pthread_mutex_unlock(&mutex_); }
|
||||
|
||||
virtual bool TryLock() {
|
||||
int result = pthread_mutex_trylock(&mutex_);
|
||||
// Return false if the lock is busy and locking failed.
|
||||
if (result == EBUSY) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(result == 0); // Verify no other errors.
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t mutex_;
|
||||
};
|
||||
|
||||
|
||||
Mutex* OS::CreateMutex() {
|
||||
return new MacOSMutex();
|
||||
}
|
||||
|
||||
void OS::Sleep(int milliseconds) {
|
||||
usleep(1000 * milliseconds);
|
||||
}
|
||||
|
||||
class Thread::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData() : thread_(kNoThread) {}
|
||||
pthread_t thread_; // Thread handle for pthread.
|
||||
};
|
||||
|
||||
Thread::Thread(const char* name)
|
||||
: data_(new PlatformData),
|
||||
stack_size_(0) {
|
||||
set_name(name);
|
||||
}
|
||||
|
||||
|
||||
Thread::~Thread() {
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
static void SetThreadName(const char* name) {
|
||||
// pthread_setname_np is only available in 10.6 or later, so test
|
||||
// for it at runtime.
|
||||
int (*dynamic_pthread_setname_np)(const char*);
|
||||
*reinterpret_cast<void**>(&dynamic_pthread_setname_np) =
|
||||
dlsym(RTLD_DEFAULT, "pthread_setname_np");
|
||||
if (!dynamic_pthread_setname_np)
|
||||
return;
|
||||
|
||||
// Mac OS X does not expose the length limit of the name, so hardcode it.
|
||||
static const int kMaxNameLength = 63;
|
||||
USE(kMaxNameLength);
|
||||
ASSERT(Thread::kMaxThreadNameLength <= kMaxNameLength);
|
||||
dynamic_pthread_setname_np(name);
|
||||
}
|
||||
|
||||
|
||||
static void* ThreadEntry(void* arg) {
|
||||
Thread* thread = reinterpret_cast<Thread*>(arg);
|
||||
// This is also initialized by the first argument to pthread_create() but we
|
||||
// don't know which thread will run first (the original thread or the new
|
||||
// one) so we initialize it here too.
|
||||
thread->data()->thread_ = pthread_self();
|
||||
SetThreadName(thread->name());
|
||||
ASSERT(thread->data()->thread_ != kNoThread);
|
||||
thread->Run();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void Thread::set_name(const char* name) {
|
||||
strncpy(name_, name, sizeof(name_));
|
||||
name_[sizeof(name_) - 1] = '\0';
|
||||
}
|
||||
|
||||
|
||||
void Thread::Start() {
|
||||
pthread_attr_t* attr_ptr = NULL;
|
||||
pthread_attr_t attr;
|
||||
if (stack_size_ > 0) {
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, static_cast<size_t>(stack_size_));
|
||||
attr_ptr = &attr;
|
||||
}
|
||||
pthread_create(&data_->thread_, attr_ptr, ThreadEntry, this);
|
||||
ASSERT(data_->thread_ != kNoThread);
|
||||
}
|
||||
|
||||
void Thread::Join() {
|
||||
pthread_join(data_->thread_, NULL);
|
||||
}
|
||||
|
||||
class Sampler::PlatformData : public Malloced {
|
||||
public:
|
||||
PlatformData() : profiled_thread_(mach_thread_self()) {}
|
||||
|
||||
~PlatformData() {
|
||||
// Deallocate Mach port for thread.
|
||||
mach_port_deallocate(mach_task_self(), profiled_thread_);
|
||||
}
|
||||
|
||||
thread_act_t profiled_thread() { return profiled_thread_; }
|
||||
|
||||
private:
|
||||
// Note: for profiled_thread_ Mach primitives are used instead of PThread's
|
||||
// because the latter doesn't provide thread manipulation primitives required.
|
||||
// For details, consult "Mac OS X Internals" book, Section 7.3.
|
||||
thread_act_t profiled_thread_;
|
||||
};
|
||||
|
||||
|
||||
class SamplerThread : public Thread {
|
||||
public:
|
||||
explicit SamplerThread(int interval)
|
||||
: Thread("SamplerThread"),
|
||||
interval_(interval) {}
|
||||
|
||||
static void AddActiveSampler(Sampler* sampler) {
|
||||
ScopedLock lock(mutex_);
|
||||
SamplerRegistry::AddActiveSampler(sampler);
|
||||
if (instance_ == NULL) {
|
||||
instance_ = new SamplerThread(sampler->interval());
|
||||
instance_->Start();
|
||||
} else {
|
||||
ASSERT(instance_->interval_ == sampler->interval());
|
||||
}
|
||||
}
|
||||
|
||||
static void RemoveActiveSampler(Sampler* sampler) {
|
||||
ScopedLock lock(mutex_);
|
||||
instance_->Join();
|
||||
//XXX: unlike v8 we need to remove the active sampler after doing the Join
|
||||
// because we drop the sampler immediately
|
||||
SamplerRegistry::RemoveActiveSampler(sampler);
|
||||
delete instance_;
|
||||
instance_ = NULL;
|
||||
/*
|
||||
if (SamplerRegistry::GetState() == SamplerRegistry::HAS_NO_SAMPLERS) {
|
||||
RuntimeProfiler::StopRuntimeProfilerThreadBeforeShutdown(instance_);
|
||||
delete instance_;
|
||||
instance_ = NULL;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Implement Thread::Run().
|
||||
virtual void Run() {
|
||||
while (SamplerRegistry::sampler->IsActive()) {
|
||||
SampleContext(SamplerRegistry::sampler);
|
||||
OS::Sleep(interval_);
|
||||
}
|
||||
}
|
||||
|
||||
void SampleContext(Sampler* sampler) {
|
||||
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
//TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
|
||||
//if (sample == NULL) sample = &sample_obj;
|
||||
|
||||
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
|
||||
|
||||
#if V8_HOST_ARCH_X64
|
||||
thread_state_flavor_t flavor = x86_THREAD_STATE64;
|
||||
x86_thread_state64_t state;
|
||||
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
|
||||
#if __DARWIN_UNIX03
|
||||
#define REGISTER_FIELD(name) __r ## name
|
||||
#else
|
||||
#define REGISTER_FIELD(name) r ## name
|
||||
#endif // __DARWIN_UNIX03
|
||||
#elif V8_HOST_ARCH_IA32
|
||||
thread_state_flavor_t flavor = i386_THREAD_STATE;
|
||||
i386_thread_state_t state;
|
||||
mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
|
||||
#if __DARWIN_UNIX03
|
||||
#define REGISTER_FIELD(name) __e ## name
|
||||
#else
|
||||
#define REGISTER_FIELD(name) e ## name
|
||||
#endif // __DARWIN_UNIX03
|
||||
#else
|
||||
#error Unsupported Mac OS X host architecture.
|
||||
#endif // V8_HOST_ARCH
|
||||
|
||||
if (thread_get_state(profiled_thread,
|
||||
flavor,
|
||||
reinterpret_cast<natural_t*>(&state),
|
||||
&count) == KERN_SUCCESS) {
|
||||
//sample->state = sampler->isolate()->current_vm_state();
|
||||
sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
|
||||
sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
|
||||
sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sampler->SampleStack(sample);
|
||||
sampler->Tick(sample);
|
||||
}
|
||||
thread_resume(profiled_thread);
|
||||
}
|
||||
|
||||
const int interval_;
|
||||
//RuntimeProfilerRateLimiter rate_limiter_;
|
||||
|
||||
// Protects the process wide state below.
|
||||
static Mutex* mutex_;
|
||||
static SamplerThread* instance_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SamplerThread);
|
||||
};
|
||||
|
||||
#undef REGISTER_FIELD
|
||||
|
||||
|
||||
Mutex* SamplerThread::mutex_ = OS::CreateMutex();
|
||||
SamplerThread* SamplerThread::instance_ = NULL;
|
||||
|
||||
|
||||
Sampler::Sampler(int interval, bool profiling)
|
||||
: // isolate_(isolate),
|
||||
interval_(interval),
|
||||
profiling_(profiling),
|
||||
active_(false) /*,
|
||||
samples_taken_(0)*/ {
|
||||
data_ = new PlatformData;
|
||||
}
|
||||
|
||||
|
||||
Sampler::~Sampler() {
|
||||
ASSERT(!IsActive());
|
||||
delete data_;
|
||||
}
|
||||
|
||||
|
||||
void Sampler::Start() {
|
||||
ASSERT(!IsActive());
|
||||
SetActive(true);
|
||||
SamplerThread::AddActiveSampler(this);
|
||||
}
|
||||
|
||||
|
||||
void Sampler::Stop() {
|
||||
ASSERT(IsActive());
|
||||
SetActive(false);
|
||||
SamplerThread::RemoveActiveSampler(this);
|
||||
}
|
|
@ -530,6 +530,8 @@ PuppetWidget::DispatchPaintEvent()
|
|||
DispatchEvent(&event, status);
|
||||
} else {
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(mSurface);
|
||||
ctx->Rectangle(gfxRect(0,0,0,0));
|
||||
ctx->Clip();
|
||||
AutoLayerManagerSetup setupLayerManager(this, ctx,
|
||||
BasicLayerManager::BUFFER_NONE);
|
||||
DispatchEvent(&event, status);
|
||||
|
|
|
@ -103,6 +103,7 @@ EXPORTS_mozilla = \
|
|||
MapsMemoryReporter.h \
|
||||
ClearOnShutdown.h \
|
||||
AvailableMemoryTracker.h \
|
||||
StackWalk.h \
|
||||
$(NULL)
|
||||
|
||||
ifeq (windows,$(MOZ_WIDGET_TOOLKIT))
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/* vim: set shiftwidth=4 tabstop=8 autoindent cindent expandtab: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Initial Developer of the Original Code is the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Jeff Muizelaar <jmuizelaar@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* API for getting a stack trace of the C/C++ */
|
||||
|
||||
#ifndef StackWalk_h_
|
||||
#define StackWalk_h_
|
||||
|
||||
// XXX: it would be nice to eventually remove this header dependency on nsStackWalk.h
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
void *aClosure, void **bp);
|
||||
|
||||
}
|
||||
|
||||
#endif /* !defined(StackWalk_h_) */
|
|
@ -141,10 +141,8 @@
|
|||
#include "prenv.h"
|
||||
#include "prprf.h"
|
||||
#include "plstr.h"
|
||||
#include "prtime.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/FunctionTimer.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
@ -312,6 +310,36 @@ static bool nsCycleCollector_shouldSuppress(nsISupports *s);
|
|||
static void InitMemHook(void);
|
||||
#endif
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
class TimeLog
|
||||
{
|
||||
public:
|
||||
TimeLog() : mLastCheckpoint(TimeStamp::Now()) {}
|
||||
|
||||
void
|
||||
Checkpoint(const char* aEvent)
|
||||
{
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
PRUint32 dur = (PRUint32) ((now - mLastCheckpoint).ToMilliseconds());
|
||||
if (dur > 0) {
|
||||
printf("cc: %s took %dms\n", aEvent, dur);
|
||||
}
|
||||
mLastCheckpoint = now;
|
||||
}
|
||||
|
||||
private:
|
||||
TimeStamp mLastCheckpoint;
|
||||
};
|
||||
#else
|
||||
class TimeLog
|
||||
{
|
||||
public:
|
||||
TimeLog() {}
|
||||
void Checkpoint(const char* aEvent) {}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Base types
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
@ -2197,6 +2225,7 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
|
|||
// - Unroot(whites), which returns the whites to normal GC.
|
||||
|
||||
nsresult rv;
|
||||
TimeLog timeLog;
|
||||
|
||||
NS_ASSERTION(mWhiteNodes->IsEmpty(),
|
||||
"FinishCollection wasn't called?");
|
||||
|
@ -2215,9 +2244,11 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
|
|||
}
|
||||
}
|
||||
}
|
||||
timeLog.Checkpoint("CollectWhite::Root");
|
||||
|
||||
if (mBeforeUnlinkCB) {
|
||||
mBeforeUnlinkCB();
|
||||
timeLog.Checkpoint("CollectWhite::BeforeUnlinkCB");
|
||||
}
|
||||
#if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
|
||||
struct _CrtMemState ms1, ms2;
|
||||
|
@ -2249,6 +2280,7 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
|
|||
#endif
|
||||
}
|
||||
}
|
||||
timeLog.Checkpoint("CollectWhite::Unlink");
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
PtrInfo *pinfo = mWhiteNodes->ElementAt(i);
|
||||
|
@ -2256,6 +2288,7 @@ nsCycleCollector::CollectWhite(nsICycleCollectorListener *aListener)
|
|||
if (NS_FAILED(rv))
|
||||
Fault("Failed unroot call while unlinking", pinfo);
|
||||
}
|
||||
timeLog.Checkpoint("CollectWhite::Unroot");
|
||||
|
||||
#if defined(DEBUG_CC) && !defined(__MINGW32__) && defined(WIN32)
|
||||
_CrtMemCheckpoint(&ms2);
|
||||
|
@ -2842,16 +2875,13 @@ nsCycleCollector::GCIfNeeded(bool aForceGC)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
PRTime start = PR_Now();
|
||||
#endif
|
||||
TimeLog timeLog;
|
||||
|
||||
// rt->Collect() must be called from the main thread,
|
||||
// because it invokes XPCJSRuntime::GCCallback(cx, JSGC_BEGIN)
|
||||
// which returns false if not in the main thread.
|
||||
rt->Collect(js::gcreason::CC_FORCED, nsGCNormal);
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: GC() took %lldms\n", (PR_Now() - start) / PR_USEC_PER_MSEC);
|
||||
#endif
|
||||
timeLog.Checkpoint("GC()");
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2866,11 +2896,8 @@ nsCycleCollector::PrepareForCollection(nsTArray<PtrInfo*> *aWhiteNodes)
|
|||
if (mCollectionInProgress)
|
||||
return false;
|
||||
|
||||
NS_TIME_FUNCTION;
|
||||
TimeLog timeLog;
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: nsCycleCollector::PrepareForCollection()\n");
|
||||
#endif
|
||||
mCollectionStart = TimeStamp::Now();
|
||||
mVisitedRefCounted = 0;
|
||||
mVisitedGCed = 0;
|
||||
|
@ -2887,6 +2914,8 @@ nsCycleCollector::PrepareForCollection(nsTArray<PtrInfo*> *aWhiteNodes)
|
|||
|
||||
mWhiteNodes = aWhiteNodes;
|
||||
|
||||
timeLog.Checkpoint("PrepareForCollection()");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2903,9 +2932,12 @@ nsCycleCollector::CleanupAfterCollection()
|
|||
_heapmin();
|
||||
#endif
|
||||
|
||||
PRUint32 interval((TimeStamp::Now() - mCollectionStart).ToMilliseconds());
|
||||
PRUint32 interval = (PRUint32) ((TimeStamp::Now() - mCollectionStart).ToMilliseconds());
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: CleanupAfterCollection(), total time %ums\n", interval);
|
||||
printf("cc: total cycle collector time was %ums\n", interval);
|
||||
printf("cc: visited %u ref counted and %u GCed objects, freed %d.\n",
|
||||
mVisitedRefCounted, mVisitedGCed, mWhiteNodeCount);
|
||||
printf("cc: \n");
|
||||
#endif
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR, interval);
|
||||
Telemetry::Accumulate(Telemetry::CYCLE_COLLECTOR_VISITED_REF_COUNTED, mVisitedRefCounted);
|
||||
|
@ -2948,6 +2980,8 @@ bool
|
|||
nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
// aListener should be Begin()'d before this
|
||||
TimeLog timeLog;
|
||||
|
||||
if (mParams.mDoNothing)
|
||||
return false;
|
||||
|
||||
|
@ -2955,20 +2989,12 @@ nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
|||
if (!builder.Initialized())
|
||||
return false;
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
PRTime now = PR_Now();
|
||||
#endif
|
||||
for (PRUint32 i = 0; i <= nsIProgrammingLanguage::MAX; ++i) {
|
||||
if (mRuntimes[i])
|
||||
mRuntimes[i]->BeginCycleCollection(builder, false);
|
||||
}
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: mRuntimes[*]->BeginCycleCollection() took %lldms\n",
|
||||
(PR_Now() - now) / PR_USEC_PER_MSEC);
|
||||
|
||||
now = PR_Now();
|
||||
#endif
|
||||
timeLog.Checkpoint("mRuntimes[*]->BeginCycleCollection()");
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
PRUint32 purpleStart = builder.Count();
|
||||
|
@ -2999,35 +3025,16 @@ nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: SelectPurple() took %lldms\n",
|
||||
(PR_Now() - now) / PR_USEC_PER_MSEC);
|
||||
#endif
|
||||
timeLog.Checkpoint("SelectPurple()");
|
||||
|
||||
if (builder.Count() > 0) {
|
||||
// The main Bacon & Rajan collection algorithm.
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
now = PR_Now();
|
||||
#endif
|
||||
|
||||
MarkRoots(builder);
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
{
|
||||
PRTime then = PR_Now();
|
||||
printf("cc: MarkRoots() took %lldms\n",
|
||||
(then - now) / PR_USEC_PER_MSEC);
|
||||
now = then;
|
||||
}
|
||||
#endif
|
||||
timeLog.Checkpoint("MarkRoots()");
|
||||
|
||||
ScanRoots();
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: ScanRoots() took %lldms\n",
|
||||
(PR_Now() - now) / PR_USEC_PER_MSEC);
|
||||
#endif
|
||||
timeLog.Checkpoint("ScanRoots()");
|
||||
|
||||
mScanInProgress = false;
|
||||
|
||||
|
@ -3069,6 +3076,7 @@ nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
|||
if (mRuntimes[i])
|
||||
mRuntimes[i]->FinishTraverse();
|
||||
}
|
||||
timeLog.Checkpoint("mRuntimes[*]->FinishTraverse()");
|
||||
}
|
||||
else {
|
||||
mScanInProgress = false;
|
||||
|
@ -3080,16 +3088,9 @@ nsCycleCollector::BeginCollection(nsICycleCollectorListener *aListener)
|
|||
bool
|
||||
nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
|
||||
{
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
PRTime now = PR_Now();
|
||||
#endif
|
||||
|
||||
TimeLog timeLog;
|
||||
bool collected = CollectWhite(aListener);
|
||||
|
||||
#ifdef COLLECT_TIME_DEBUG
|
||||
printf("cc: CollectWhite() took %lldms\n",
|
||||
(PR_Now() - now) / PR_USEC_PER_MSEC);
|
||||
#endif
|
||||
timeLog.Checkpoint("CollectWhite()");
|
||||
|
||||
#ifdef DEBUG_CC
|
||||
mStats.mCollection++;
|
||||
|
@ -3101,6 +3102,7 @@ nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
|
|||
if (mRuntimes[i])
|
||||
mRuntimes[i]->FinishCycleCollection();
|
||||
}
|
||||
timeLog.Checkpoint("mRuntimes[*]->FinishCycleCollection()");
|
||||
|
||||
mFollowupCollection = true;
|
||||
|
||||
|
@ -3125,6 +3127,7 @@ nsCycleCollector::FinishCollection(nsICycleCollectorListener *aListener)
|
|||
|
||||
mWhiteNodes->Clear();
|
||||
ClearGraph();
|
||||
timeLog.Checkpoint("ClearGraph()");
|
||||
|
||||
mParams.mDoNothing = false;
|
||||
|
||||
|
@ -3865,7 +3868,9 @@ nsCycleCollector_forgetSkippable()
|
|||
{
|
||||
if (sCollector) {
|
||||
SAMPLE_LABEL("CC", "nsCycleCollector_forgetSkippable");
|
||||
TimeLog timeLog;
|
||||
sCollector->ForgetSkippable();
|
||||
timeLog.Checkpoint("ForgetSkippable()");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,11 +41,14 @@
|
|||
/* API for getting a stack trace of the C/C++ stack on the current thread */
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "mozilla/StackWalk.h"
|
||||
#include "nsDebug.h"
|
||||
#include "nsStackWalkPrivate.h"
|
||||
|
||||
#include "nsStackWalk.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// The presence of this address is the stack must stop the stack walk. If
|
||||
// there is no such address, the structure will be {NULL, true}.
|
||||
struct CriticalAddress {
|
||||
|
@ -215,8 +218,6 @@ StackWalkInitCriticalAddress()
|
|||
#endif
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
// Define these as static pointers so that we can load the DLL on the
|
||||
// fly (and not introduce a link-time dependency on it). Tip o' the
|
||||
// hat to Matt Pietrick for this idea. See:
|
||||
|
@ -1572,9 +1573,6 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails,
|
|||
|
||||
#else // not __sun-specific
|
||||
|
||||
#define X86_OR_PPC (defined(__i386) || defined(PPC) || defined(__ppc__))
|
||||
#if X86_OR_PPC && (NSSTACKWALK_SUPPORTS_MACOSX || NSSTACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code
|
||||
|
||||
#if __GLIBC__ > 2 || __GLIBC_MINOR > 1
|
||||
#define HAVE___LIBC_STACK_END 1
|
||||
#else
|
||||
|
@ -1584,26 +1582,13 @@ NS_FormatCodeAddressDetails(void *aPC, const nsCodeAddressDetails *aDetails,
|
|||
#if HAVE___LIBC_STACK_END
|
||||
extern void *__libc_stack_end; // from ld-linux.so
|
||||
#endif
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread)
|
||||
namespace mozilla {
|
||||
nsresult
|
||||
FramePointerStackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
void *aClosure, void **bp)
|
||||
{
|
||||
MOZ_ASSERT(gCriticalAddress.mInit);
|
||||
MOZ_ASSERT(!aThread);
|
||||
// Stack walking code courtesy Kipp's "leaky".
|
||||
|
||||
// Get the frame pointer
|
||||
void **bp;
|
||||
#if defined(__i386)
|
||||
__asm__( "movl %%ebp, %0" : "=g"(bp));
|
||||
#else
|
||||
// It would be nice if this worked uniformly, but at least on i386 and
|
||||
// x86_64, it stopped working with gcc 4.1, because it points to the
|
||||
// end of the saved registers instead of the start.
|
||||
bp = (void**) __builtin_frame_address(0);
|
||||
#endif
|
||||
|
||||
int skip = aSkipFrames;
|
||||
while (1) {
|
||||
void **next = (void**)*bp;
|
||||
|
@ -1636,6 +1621,33 @@ NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define X86_OR_PPC (defined(__i386) || defined(PPC) || defined(__ppc__))
|
||||
#if X86_OR_PPC && (NSSTACKWALK_SUPPORTS_MACOSX || NSSTACKWALK_SUPPORTS_LINUX) // i386 or PPC Linux or Mac stackwalking code
|
||||
|
||||
EXPORT_XPCOM_API(nsresult)
|
||||
NS_StackWalk(NS_WalkStackCallback aCallback, PRUint32 aSkipFrames,
|
||||
void *aClosure, uintptr_t aThread)
|
||||
{
|
||||
MOZ_ASSERT(gCriticalAddress.mInit);
|
||||
MOZ_ASSERT(!aThread);
|
||||
|
||||
// Get the frame pointer
|
||||
void **bp;
|
||||
#if defined(__i386)
|
||||
__asm__( "movl %%ebp, %0" : "=g"(bp));
|
||||
#else
|
||||
// It would be nice if this worked uniformly, but at least on i386 and
|
||||
// x86_64, it stopped working with gcc 4.1, because it points to the
|
||||
// end of the saved registers instead of the start.
|
||||
bp = (void**) __builtin_frame_address(0);
|
||||
#endif
|
||||
return FramePointerStackWalk(aCallback, aSkipFrames,
|
||||
aClosure, bp);
|
||||
|
||||
}
|
||||
|
||||
#elif defined(HAVE__UNWIND_BACKTRACE)
|
||||
|
||||
// libgcc_s.so symbols _Unwind_Backtrace@@GCC_3.3 and _Unwind_GetIP@@GCC_3.0
|
||||
|
|
Загрузка…
Ссылка в новой задаче