зеркало из https://github.com/mozilla/pjs.git
Merge services-central with mozilla-central
This commit is contained in:
Коммит
b5eb25c5a9
|
@ -316,6 +316,10 @@ NotificationController::WillRefresh(mozilla::TimeStamp aTime)
|
|||
for (PRUint32 idx = 0; idx < eventCount; idx++) {
|
||||
AccEvent* accEvent = events[idx];
|
||||
if (accEvent->mEventRule != AccEvent::eDoNotEmit) {
|
||||
nsAccessible* target = accEvent->GetAccessible();
|
||||
if (!target || target->IsDefunct())
|
||||
continue;
|
||||
|
||||
// Dispatch the focus event if target is still focused.
|
||||
if (accEvent->mEventType == nsIAccessibleEvent::EVENT_FOCUS) {
|
||||
FocusMgr()->ProcessFocusEvent(accEvent);
|
||||
|
|
|
@ -1730,33 +1730,26 @@ nsDocAccessible::FireDelayedAccessibleEvent(AccEvent* aEvent)
|
|||
void
|
||||
nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
|
||||
{
|
||||
nsAccessible* accessible = aEvent->GetAccessible();
|
||||
if (!accessible)
|
||||
return;
|
||||
|
||||
PRUint32 eventType = aEvent->GetEventType();
|
||||
if (eventType == nsIAccessibleEvent::EVENT_TEXT_CARET_MOVED) {
|
||||
nsCOMPtr<nsIAccessibleText> accessibleText = do_QueryObject(accessible);
|
||||
nsHyperTextAccessible* hyperText = aEvent->GetAccessible()->AsHyperText();
|
||||
PRInt32 caretOffset;
|
||||
if (accessibleText &&
|
||||
NS_SUCCEEDED(accessibleText->GetCaretOffset(&caretOffset))) {
|
||||
if (hyperText &&
|
||||
NS_SUCCEEDED(hyperText->GetCaretOffset(&caretOffset))) {
|
||||
#ifdef DEBUG_A11Y
|
||||
PRUnichar chAtOffset;
|
||||
accessibleText->GetCharacterAtOffset(caretOffset, &chAtOffset);
|
||||
hyperText->GetCharacterAtOffset(caretOffset, &chAtOffset);
|
||||
printf("\nCaret moved to %d with char %c", caretOffset, chAtOffset);
|
||||
#endif
|
||||
nsRefPtr<AccEvent> caretMoveEvent =
|
||||
new AccCaretMoveEvent(accessible, caretOffset);
|
||||
if (!caretMoveEvent)
|
||||
return;
|
||||
|
||||
new AccCaretMoveEvent(hyperText, caretOffset);
|
||||
nsEventShell::FireEvent(caretMoveEvent);
|
||||
|
||||
PRInt32 selectionCount;
|
||||
accessibleText->GetSelectionCount(&selectionCount);
|
||||
hyperText->GetSelectionCount(&selectionCount);
|
||||
if (selectionCount) { // There's a selection so fire selection change as well
|
||||
nsEventShell::FireEvent(nsIAccessibleEvent::EVENT_TEXT_SELECTION_CHANGED,
|
||||
accessible);
|
||||
hyperText);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1765,7 +1758,7 @@ nsDocAccessible::ProcessPendingEvent(AccEvent* aEvent)
|
|||
|
||||
// Post event processing
|
||||
if (eventType == nsIAccessibleEvent::EVENT_HIDE)
|
||||
ShutdownChildrenInSubtree(accessible);
|
||||
ShutdownChildrenInSubtree(aEvent->GetAccessible());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -743,6 +743,10 @@ nsRefPtrHashtable<nsVoidPtrHashKey, nsDocAccessible> nsAccessNodeWrap::sHWNDCach
|
|||
LRESULT CALLBACK
|
||||
nsAccessNodeWrap::WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// Note, this window's message handling should not invoke any call that
|
||||
// may result in a cross-process ipc call. Doing so may violate RPC
|
||||
// message semantics.
|
||||
|
||||
switch (msg) {
|
||||
case WM_GETOBJECT:
|
||||
{
|
||||
|
|
|
@ -46,6 +46,10 @@
|
|||
#include "nsArrayUtils.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
|
||||
// Window property used by ipc related code in identifying accessible
|
||||
// tab windows.
|
||||
const PRUnichar* kPropNameTabContent = L"AccessibleTabWindow";
|
||||
|
||||
HRESULT
|
||||
nsWinUtils::ConvertToIA2Array(nsIArray *aGeckoArray, IUnknown ***aIA2Array,
|
||||
long *aIA2ArrayLen)
|
||||
|
@ -149,14 +153,19 @@ nsWinUtils::CreateNativeWindow(LPCWSTR aWindowClass, HWND aParentWnd,
|
|||
int aX, int aY, int aWidth, int aHeight,
|
||||
bool aIsActive)
|
||||
{
|
||||
return ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass,
|
||||
L"NetscapeDispatchWnd",
|
||||
WS_CHILD | (aIsActive ? WS_VISIBLE : 0),
|
||||
aX, aY, aWidth, aHeight,
|
||||
aParentWnd,
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
NULL);
|
||||
HWND hwnd = ::CreateWindowExW(WS_EX_TRANSPARENT, aWindowClass,
|
||||
L"NetscapeDispatchWnd",
|
||||
WS_CHILD | (aIsActive ? WS_VISIBLE : 0),
|
||||
aX, aY, aWidth, aHeight,
|
||||
aParentWnd,
|
||||
NULL,
|
||||
GetModuleHandle(NULL),
|
||||
NULL);
|
||||
if (hwnd) {
|
||||
// Mark this window so that ipc related code can identify it.
|
||||
::SetPropW(hwnd, kPropNameTabContent, (HANDLE)1);
|
||||
}
|
||||
return hwnd;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -40,8 +40,8 @@ nsTreeView.prototype =
|
|||
getCellText: function getCellText(aRow, aCol)
|
||||
{
|
||||
var data = this.getDataForIndex(aRow);
|
||||
if (aCol in data.colsText)
|
||||
return data.colsText[aCol];
|
||||
if (aCol.id in data.colsText)
|
||||
return data.colsText[aCol.id];
|
||||
|
||||
return data.text + aCol.id;
|
||||
},
|
||||
|
@ -120,7 +120,7 @@ nsTreeView.prototype =
|
|||
setCellText: function setCellText(aRow, aCol, aValue)
|
||||
{
|
||||
var data = this.getDataForIndex(aRow);
|
||||
data.colsText[aCol] = aValue;
|
||||
data.colsText[aCol.id] = aValue;
|
||||
},
|
||||
setCellValue: function setCellValue(aRow, aCol, aValue)
|
||||
{
|
||||
|
|
|
@ -170,9 +170,8 @@ pref("app.update.url", "https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%B
|
|||
//pref("app.update.url.override", "");
|
||||
|
||||
// app.update.interval is in branding section
|
||||
// app.update.promptWaitTime is in branding section
|
||||
|
||||
// Give the user x seconds to react before showing the big UI. default=12 hours
|
||||
pref("app.update.promptWaitTime", 43200);
|
||||
// Show the Update Checking/Ready UI when the user was idle for x seconds
|
||||
pref("app.update.idletime", 60);
|
||||
|
||||
|
|
|
@ -42,6 +42,9 @@
|
|||
|
||||
#highlighter-nodeinfobar-container {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#highlighter-nodeinfobar-container:not([locked]) {
|
||||
-moz-transition-property: top, left;
|
||||
-moz-transition-duration: 0.1s;
|
||||
-moz-transition-timing-function: linear;
|
||||
|
|
|
@ -7,6 +7,8 @@ pref("app.update.interval", 28800);
|
|||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// Give the user x seconds to react before showing the big UI. default=24 hours
|
||||
pref("app.update.promptWaitTime", 86400);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "http://www.mozilla.com/firefox/channel/");
|
||||
|
|
|
@ -5,6 +5,8 @@ pref("app.update.interval", 7200); // 2 hours
|
|||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// Give the user x seconds to react before showing the big UI. default=12 hours
|
||||
pref("app.update.promptWaitTime", 43200);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "http://nightly.mozilla.org/");
|
||||
|
|
|
@ -7,6 +7,8 @@ pref("app.update.interval", 86400);
|
|||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 600);
|
||||
// Give the user x seconds to react before showing the big UI. default=24 hours
|
||||
pref("app.update.promptWaitTime", 86400);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "http://www.firefox.com");
|
||||
|
|
|
@ -5,6 +5,8 @@ pref("app.update.interval", 86400); // 24 hours
|
|||
// The time interval between the downloading of mar file chunks in the
|
||||
// background (in seconds)
|
||||
pref("app.update.download.backgroundInterval", 60);
|
||||
// Give the user x seconds to react before showing the big UI. default=24 hours
|
||||
pref("app.update.promptWaitTime", 86400);
|
||||
// URL user can browse to manually if for some reason all update installation
|
||||
// attempts fail.
|
||||
pref("app.update.url.manual", "http://www.mozilla.org/products/%APP%/");
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
ac_add_options --enable-application=browser
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
ac_add_options --enable-application=browser
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
|
||||
ac_add_options --enable-tests
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
|
||||
ac_add_options --with-macos-sdk=/Developer/SDKs/MacOSX10.5.sdk
|
||||
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
|
|
@ -3,7 +3,6 @@ ac_add_options --host=x86_64-pc-mingw32
|
|||
|
||||
ac_add_options --enable-application=browser
|
||||
ac_add_options --enable-jemalloc
|
||||
ac_add_options --disable-optimize
|
||||
ac_add_options --enable-debug
|
||||
ac_add_options --enable-libxul
|
||||
ac_add_options --enable-trace-malloc
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -47,7 +47,7 @@ Cu.import("resource:///modules/domplate.jsm");
|
|||
Cu.import("resource:///modules/InsideOutBox.jsm");
|
||||
Cu.import("resource:///modules/Services.jsm");
|
||||
|
||||
var EXPORTED_SYMBOLS = ["TreePanel"];
|
||||
var EXPORTED_SYMBOLS = ["TreePanel", "DOMHelpers"];
|
||||
|
||||
const INSPECTOR_URI = "chrome://browser/content/inspector.html";
|
||||
|
||||
|
@ -96,6 +96,8 @@ TreePanel.prototype = {
|
|||
|
||||
domplateUtils.setDOM(this.window);
|
||||
|
||||
this.DOMHelpers = new DOMHelpers(this.window);
|
||||
|
||||
let isOpen = this.isOpen.bind(this);
|
||||
|
||||
this.registrationObject = {
|
||||
|
@ -139,6 +141,7 @@ TreePanel.prototype = {
|
|||
this.treeLoaded = true;
|
||||
this.treeIFrame.addEventListener("click", this.onTreeClick.bind(this), false);
|
||||
this.treeIFrame.addEventListener("dblclick", this.onTreeDblClick.bind(this), false);
|
||||
this.treeIFrame.addEventListener("keypress", this.IUI, false);
|
||||
delete this.initializingTreePanel;
|
||||
Services.obs.notifyObservers(null,
|
||||
this.IUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY, null);
|
||||
|
@ -315,93 +318,23 @@ TreePanel.prototype = {
|
|||
|
||||
getParentObject: function TP_getParentObject(node)
|
||||
{
|
||||
let parentNode = node ? node.parentNode : null;
|
||||
|
||||
if (!parentNode) {
|
||||
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
|
||||
// and Notation. top level windows have no parentNode
|
||||
if (node && node == this.window.Node.DOCUMENT_NODE) {
|
||||
// document type
|
||||
if (node.defaultView) {
|
||||
let embeddingFrame = node.defaultView.frameElement;
|
||||
if (embeddingFrame)
|
||||
return embeddingFrame.parentNode;
|
||||
}
|
||||
}
|
||||
// a Document object without a parentNode or window
|
||||
return null; // top level has no parent
|
||||
}
|
||||
|
||||
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
|
||||
if (parentNode.defaultView) {
|
||||
return parentNode.defaultView.frameElement;
|
||||
}
|
||||
// parent is document element, but no window at defaultView.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!parentNode.localName)
|
||||
return null;
|
||||
|
||||
return parentNode;
|
||||
return this.DOMHelpers.getParentObject(node);
|
||||
},
|
||||
|
||||
getChildObject: function TP_getChildObject(node, index, previousSibling)
|
||||
{
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
if (node.contentDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return node.contentDocument.documentElement; // the node's HTMLElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof this.window.GetSVGDocument) {
|
||||
let svgDocument = node.getSVGDocument();
|
||||
if (svgDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return svgDocument.documentElement; // the node's SVGElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let child = null;
|
||||
if (previousSibling) // then we are walking
|
||||
child = this.getNextSibling(previousSibling);
|
||||
else
|
||||
child = this.getFirstChild(node);
|
||||
|
||||
if (this.showTextNodesWithWhitespace)
|
||||
return child;
|
||||
|
||||
for (; child; child = this.getNextSibling(child)) {
|
||||
if (!domplateUtils.isWhitespaceText(child))
|
||||
return child;
|
||||
}
|
||||
|
||||
return null; // we have no children worth showing.
|
||||
return this.DOMHelpers.getChildObject(node, index, previousSibling,
|
||||
this.showTextNodesWithWhitespace);
|
||||
},
|
||||
|
||||
getFirstChild: function TP_getFirstChild(node)
|
||||
{
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
this.window.NodeFilter.SHOW_ALL, null, false);
|
||||
return this.treeWalker.firstChild();
|
||||
return this.DOMHelpers.getFirstChild(node);
|
||||
},
|
||||
|
||||
getNextSibling: function TP_getNextSibling(node)
|
||||
{
|
||||
let next = this.treeWalker.nextSibling();
|
||||
|
||||
if (!next)
|
||||
delete this.treeWalker;
|
||||
|
||||
return next;
|
||||
return this.DOMHelpers.getNextSibling(node);
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
@ -747,7 +680,11 @@ TreePanel.prototype = {
|
|||
domplateUtils.setDOM(null);
|
||||
|
||||
delete this.resizer;
|
||||
delete this.treeWalker;
|
||||
|
||||
if (this.DOMHelpers) {
|
||||
this.DOMHelpers.destroy();
|
||||
delete this.DOMHelpers;
|
||||
}
|
||||
|
||||
if (this.treePanelDiv) {
|
||||
this.treePanelDiv.ownerPanel = null;
|
||||
|
@ -758,6 +695,7 @@ TreePanel.prototype = {
|
|||
}
|
||||
|
||||
if (this.treeIFrame) {
|
||||
this.treeIFrame.removeEventListener("keypress", this.IUI, false);
|
||||
this.treeIFrame.removeEventListener("dblclick", this.onTreeDblClick, false);
|
||||
this.treeIFrame.removeEventListener("click", this.onTreeClick, false);
|
||||
let parent = this.treeIFrame.parentNode;
|
||||
|
@ -777,3 +715,122 @@ TreePanel.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* DOMHelpers
|
||||
* Makes DOM traversal easier. Goes through iframes.
|
||||
*
|
||||
* @constructor
|
||||
* @param nsIDOMWindow aWindow
|
||||
* The content window, owning the document to traverse.
|
||||
*/
|
||||
function DOMHelpers(aWindow) {
|
||||
this.window = aWindow;
|
||||
};
|
||||
|
||||
DOMHelpers.prototype = {
|
||||
getParentObject: function Helpers_getParentObject(node)
|
||||
{
|
||||
let parentNode = node ? node.parentNode : null;
|
||||
|
||||
if (!parentNode) {
|
||||
// Documents have no parentNode; Attr, Document, DocumentFragment, Entity,
|
||||
// and Notation. top level windows have no parentNode
|
||||
if (node && node == this.window.Node.DOCUMENT_NODE) {
|
||||
// document type
|
||||
if (node.defaultView) {
|
||||
let embeddingFrame = node.defaultView.frameElement;
|
||||
if (embeddingFrame)
|
||||
return embeddingFrame.parentNode;
|
||||
}
|
||||
}
|
||||
// a Document object without a parentNode or window
|
||||
return null; // top level has no parent
|
||||
}
|
||||
|
||||
if (parentNode.nodeType == this.window.Node.DOCUMENT_NODE) {
|
||||
if (parentNode.defaultView) {
|
||||
return parentNode.defaultView.frameElement;
|
||||
}
|
||||
// parent is document element, but no window at defaultView.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!parentNode.localName)
|
||||
return null;
|
||||
|
||||
return parentNode;
|
||||
},
|
||||
|
||||
getChildObject: function Helpers_getChildObject(node, index, previousSibling,
|
||||
showTextNodesWithWhitespace)
|
||||
{
|
||||
if (!node)
|
||||
return null;
|
||||
|
||||
if (node.contentDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return node.contentDocument.documentElement; // the node's HTMLElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (node instanceof this.window.GetSVGDocument) {
|
||||
let svgDocument = node.getSVGDocument();
|
||||
if (svgDocument) {
|
||||
// then the node is a frame
|
||||
if (index == 0) {
|
||||
return svgDocument.documentElement; // the node's SVGElement
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
let child = null;
|
||||
if (previousSibling) // then we are walking
|
||||
child = this.getNextSibling(previousSibling);
|
||||
else
|
||||
child = this.getFirstChild(node);
|
||||
|
||||
if (showTextNodesWithWhitespace)
|
||||
return child;
|
||||
|
||||
for (; child; child = this.getNextSibling(child)) {
|
||||
if (!this.isWhitespaceText(child))
|
||||
return child;
|
||||
}
|
||||
|
||||
return null; // we have no children worth showing.
|
||||
},
|
||||
|
||||
getFirstChild: function Helpers_getFirstChild(node)
|
||||
{
|
||||
let SHOW_ALL = Components.interfaces.nsIDOMNodeFilter.SHOW_ALL;
|
||||
this.treeWalker = node.ownerDocument.createTreeWalker(node,
|
||||
SHOW_ALL, null, false);
|
||||
return this.treeWalker.firstChild();
|
||||
},
|
||||
|
||||
getNextSibling: function Helpers_getNextSibling(node)
|
||||
{
|
||||
let next = this.treeWalker.nextSibling();
|
||||
|
||||
if (!next)
|
||||
delete this.treeWalker;
|
||||
|
||||
return next;
|
||||
},
|
||||
|
||||
isWhitespaceText: function Helpers_isWhitespaceText(node)
|
||||
{
|
||||
return node.nodeType == this.window.Node.TEXT_NODE &&
|
||||
!/[^\s]/.exec(node.nodeValue);
|
||||
},
|
||||
|
||||
destroy: function Helpers_destroy()
|
||||
{
|
||||
delete this.window;
|
||||
delete this.treeWalker;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -887,8 +887,7 @@ InspectorUI.prototype = {
|
|||
initTools: function IUI_initTools()
|
||||
{
|
||||
// Style inspector
|
||||
// XXX bug 689164, remove /false &&/ from below when bug 689160 fixed.
|
||||
if (false && Services.prefs.getBoolPref("devtools.styleinspector.enabled") &&
|
||||
if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") &&
|
||||
!this.toolRegistered("styleinspector")) {
|
||||
let stylePanel = StyleInspector.createPanel(true);
|
||||
this.registerTool({
|
||||
|
@ -990,6 +989,7 @@ InspectorUI.prototype = {
|
|||
}
|
||||
|
||||
this.stopInspecting();
|
||||
this.browser.removeEventListener("keypress", this, true);
|
||||
|
||||
this.saveToolState(this.winID);
|
||||
this.toolsDo(function IUI_toolsHide(aTool) {
|
||||
|
@ -997,6 +997,9 @@ InspectorUI.prototype = {
|
|||
}.bind(this));
|
||||
|
||||
if (this.highlighter) {
|
||||
this.highlighter.highlighterContainer.removeEventListener("keypress",
|
||||
this,
|
||||
true);
|
||||
this.highlighter.destroy();
|
||||
this.highlighter = null;
|
||||
}
|
||||
|
@ -1027,10 +1030,16 @@ InspectorUI.prototype = {
|
|||
this.treePanel.closeEditor();
|
||||
|
||||
this.inspectToolbutton.checked = true;
|
||||
this.attachPageListeners();
|
||||
// Attach event listeners to content window and child windows to enable
|
||||
// highlighting and click to stop inspection.
|
||||
this.browser.addEventListener("keypress", this, true);
|
||||
this.highlighter.highlighterContainer.addEventListener("keypress", this, true);
|
||||
this.highlighter.attachInspectListeners();
|
||||
|
||||
this.inspecting = true;
|
||||
this.toolsDim(true);
|
||||
this.highlighter.veilContainer.removeAttribute("locked");
|
||||
this.highlighter.nodeInfo.container.removeAttribute("locked");
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1046,7 +1055,12 @@ InspectorUI.prototype = {
|
|||
}
|
||||
|
||||
this.inspectToolbutton.checked = false;
|
||||
this.detachPageListeners();
|
||||
// Detach event listeners from content window and child windows to disable
|
||||
// highlighting. We still want to be notified if the user presses "ESCAPE"
|
||||
// to unlock the node, so we don't remove the "keypress" event until
|
||||
// the highlighter is removed.
|
||||
this.highlighter.detachInspectListeners();
|
||||
|
||||
this.inspecting = false;
|
||||
this.toolsDim(false);
|
||||
if (this.highlighter.node) {
|
||||
|
@ -1055,6 +1069,7 @@ InspectorUI.prototype = {
|
|||
this.select(null, true, true);
|
||||
}
|
||||
this.highlighter.veilContainer.setAttribute("locked", true);
|
||||
this.highlighter.nodeInfo.container.setAttribute("locked", true);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1165,11 +1180,9 @@ InspectorUI.prototype = {
|
|||
switch (event.keyCode) {
|
||||
case this.chromeWin.KeyEvent.DOM_VK_RETURN:
|
||||
case this.chromeWin.KeyEvent.DOM_VK_ESCAPE:
|
||||
if (this.inspecting) {
|
||||
this.stopInspecting();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
this.toggleInspection();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
break;
|
||||
case this.chromeWin.KeyEvent.DOM_VK_LEFT:
|
||||
let node;
|
||||
|
@ -1239,26 +1252,6 @@ InspectorUI.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Attach event listeners to content window and child windows to enable
|
||||
* highlighting and click to stop inspection.
|
||||
*/
|
||||
attachPageListeners: function IUI_attachPageListeners()
|
||||
{
|
||||
this.browser.addEventListener("keypress", this, true);
|
||||
this.highlighter.attachInspectListeners();
|
||||
},
|
||||
|
||||
/**
|
||||
* Detach event listeners from content window and child windows
|
||||
* to disable highlighting.
|
||||
*/
|
||||
detachPageListeners: function IUI_detachPageListeners()
|
||||
{
|
||||
this.browser.removeEventListener("keypress", this, true);
|
||||
this.highlighter.detachInspectListeners();
|
||||
},
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//// Utility Methods
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ _BROWSER_FILES = \
|
|||
browser_inspector_infobar.js \
|
||||
browser_inspector_bug_690361.js \
|
||||
browser_inspector_bug_672902_keyboard_shortcuts.js \
|
||||
browser_inspector_keybindings.js \
|
||||
$(NULL)
|
||||
|
||||
# Disabled due to constant failures
|
||||
|
|
|
@ -77,6 +77,8 @@ function runInspectorTests()
|
|||
ok(InspectorUI.inspecting, "Inspector is inspecting");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is not open");
|
||||
ok(InspectorUI.highlighter, "Highlighter is up");
|
||||
InspectorUI.inspectNode(doc.body);
|
||||
InspectorUI.stopInspecting();
|
||||
|
||||
InspectorUI.treePanel.open();
|
||||
}
|
||||
|
@ -85,14 +87,29 @@ function treePanelTests()
|
|||
{
|
||||
Services.obs.removeObserver(treePanelTests,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.TREEPANELREADY);
|
||||
Services.obs.addObserver(runContextMenuTest,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
Services.obs.addObserver(stylePanelTests,
|
||||
"StyleInspector-opened", false);
|
||||
|
||||
ok(InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is open");
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.stylePanel.showTool(doc.body);
|
||||
});
|
||||
}
|
||||
|
||||
function stylePanelTests()
|
||||
{
|
||||
Services.obs.removeObserver(stylePanelTests, "StyleInspector-opened");
|
||||
Services.obs.addObserver(runContextMenuTest,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
|
||||
ok(InspectorUI.stylePanel.isOpen(), "Style Panel is Open");
|
||||
ok(InspectorUI.stylePanel.cssHtmlTree, "Style Panel has a cssHtmlTree");
|
||||
|
||||
executeSoon(function() {
|
||||
InspectorUI.closeInspectorUI();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function runContextMenuTest()
|
||||
|
@ -121,9 +138,8 @@ function inspectNodesFromContextTest()
|
|||
Services.obs.addObserver(openInspectorForContextTest, InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
ok(!InspectorUI.inspecting, "Inspector is not actively highlighting");
|
||||
is(InspectorUI.selection, salutation, "Inspector is highlighting salutation");
|
||||
ok(!InspectorUI.isTreePanelOpen, "Inspector Tree Panel is closed");
|
||||
// TODO: These tests depend on the style inspector patches.
|
||||
todo(InspectorUI.isStylePanelOpen, "Inspector Style Panel is open");
|
||||
ok(!InspectorUI.treePanel.isOpen(), "Inspector Tree Panel is closed");
|
||||
ok(!InspectorUI.stylePanel.isOpen(), "Inspector Style Panel is closed");
|
||||
executeSoon(function() {
|
||||
InspectorUI.closeInspectorUI(true);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
|
||||
let doc;
|
||||
let node;
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
doc = content.document;
|
||||
waitForFocus(setupKeyBindingsTest, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,<h1>foobar</h1>";
|
||||
|
||||
function setupKeyBindingsTest()
|
||||
{
|
||||
node = doc.querySelector("h1");
|
||||
Services.obs.addObserver(highlightNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED, false);
|
||||
InspectorUI.toggleInspectorUI();
|
||||
}
|
||||
|
||||
function highlightNode()
|
||||
{
|
||||
Services.obs.removeObserver(highlightNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.OPENED);
|
||||
|
||||
executeSoon(function() {
|
||||
Services.obs.addObserver(lockNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING, false);
|
||||
|
||||
InspectorUI.inspectNode(node);
|
||||
});
|
||||
}
|
||||
|
||||
function lockNode()
|
||||
{
|
||||
Services.obs.removeObserver(lockNode,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.HIGHLIGHTING);
|
||||
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
|
||||
executeSoon(isTheNodeLocked);
|
||||
}
|
||||
|
||||
function isTheNodeLocked()
|
||||
{
|
||||
is(InspectorUI.selection, node, "selection matches node");
|
||||
ok(!InspectorUI.inspecting, "the node is locked");
|
||||
unlockNode();
|
||||
}
|
||||
|
||||
function unlockNode() {
|
||||
EventUtils.synthesizeKey("VK_ESCAPE", { });
|
||||
|
||||
executeSoon(isTheNodeUnlocked);
|
||||
}
|
||||
|
||||
function isTheNodeUnlocked()
|
||||
{
|
||||
ok(InspectorUI.inspecting, "the node is unlocked");
|
||||
|
||||
Services.obs.addObserver(finishUp,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED, false);
|
||||
InspectorUI.closeInspectorUI();
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
Services.obs.removeObserver(finishUp,
|
||||
InspectorUI.INSPECTOR_NOTIFICATIONS.CLOSED);
|
||||
doc = node = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -328,6 +328,34 @@ CssHtmlTree.prototype = {
|
|||
CssHtmlTree.propertyNames.push.apply(CssHtmlTree.propertyNames,
|
||||
mozProps.sort());
|
||||
},
|
||||
|
||||
/**
|
||||
* Destructor for CssHtmlTree.
|
||||
*/
|
||||
destroy: function CssHtmlTree_destroy()
|
||||
{
|
||||
delete this.viewedElement;
|
||||
|
||||
// Nodes used in templating
|
||||
delete this.root;
|
||||
delete this.path;
|
||||
delete this.templateRoot;
|
||||
delete this.templatePath;
|
||||
delete this.propertyContainer;
|
||||
delete this.templateProperty;
|
||||
delete this.panel;
|
||||
|
||||
// The document in which we display the results (csshtmltree.xhtml).
|
||||
delete this.styleDocument;
|
||||
|
||||
// The element that we're inspecting, and the document that it comes from.
|
||||
delete this.propertyViews;
|
||||
delete this.getRTLAttr;
|
||||
delete this.styleWin;
|
||||
delete this.cssLogic;
|
||||
delete this.doc;
|
||||
delete this.win;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -66,8 +66,7 @@ var StyleInspector = {
|
|||
{
|
||||
let win = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
let popupSet = win.document.getElementById("mainPopupSet");
|
||||
let ns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
let panel = win.document.createElementNS(ns, "panel");
|
||||
let panel = win.document.createElement("panel");
|
||||
|
||||
panel.setAttribute("class", "styleInspector");
|
||||
panel.setAttribute("orient", "vertical");
|
||||
|
@ -84,7 +83,7 @@ var StyleInspector = {
|
|||
vbox.setAttribute("flex", "1");
|
||||
panel.appendChild(vbox);
|
||||
|
||||
let iframe = win.document.createElementNS(ns, "iframe");
|
||||
let iframe = win.document.createElement("iframe");
|
||||
iframe.setAttribute("flex", "1");
|
||||
iframe.setAttribute("tooltip", "aHTMLTooltip");
|
||||
iframe.setAttribute("src", "chrome://browser/content/csshtmltree.xhtml");
|
||||
|
@ -145,8 +144,8 @@ var StyleInspector = {
|
|||
}
|
||||
}
|
||||
|
||||
panel.addEventListener("popupshown", SI_popupShown);
|
||||
panel.addEventListener("popuphidden", SI_popupHidden);
|
||||
panel.addEventListener("popupshown", SI_popupShown, false);
|
||||
panel.addEventListener("popuphidden", SI_popupHidden, false);
|
||||
panel.preserveOnHide = !!aPreserveOnHide;
|
||||
|
||||
/**
|
||||
|
@ -176,15 +175,21 @@ var StyleInspector = {
|
|||
*/
|
||||
panel.destroy = function SI_destroy()
|
||||
{
|
||||
if (!this.cssLogic)
|
||||
return;
|
||||
if (this.isOpen())
|
||||
this.hideTool();
|
||||
this.cssLogic = null;
|
||||
this.cssHtmlTree = null;
|
||||
this.removeEventListener("popupshown", SI_popupShown);
|
||||
this.removeEventListener("popuphidden", SI_popupHidden);
|
||||
this.parentNode.removeChild(this);
|
||||
if (panel.cssHtmlTree)
|
||||
panel.cssHtmlTree.destroy();
|
||||
if (iframe) {
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
iframe = null;
|
||||
}
|
||||
|
||||
delete panel.cssLogic;
|
||||
delete panel.cssHtmlTree;
|
||||
panel.removeEventListener("popupshown", SI_popupShown, false);
|
||||
panel.removeEventListener("popuphidden", SI_popupHidden, false);
|
||||
panel.parentNode.removeChild(panel);
|
||||
panel = null;
|
||||
Services.obs.notifyObservers(null, "StyleInspector-closed", null);
|
||||
};
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ function test()
|
|||
|
||||
function tabLoaded()
|
||||
{
|
||||
browser.removeEventListener("load", tabLoaded, true);
|
||||
ok(window.StyleInspector, "StyleInspector exists");
|
||||
ok(StyleInspector.isEnabled, "style inspector preference is enabled");
|
||||
stylePanel = StyleInspector.createPanel();
|
||||
|
|
|
@ -47,6 +47,7 @@ confirmRepostPrompt=To display this page, %S must send information that will rep
|
|||
resendButton.label=Resend
|
||||
unknownSocketType=Firefox doesn't know how to communicate with the server.
|
||||
netReset=The connection to the server was reset while the page was loading.
|
||||
notCached=This document is no longer available.
|
||||
netOffline=Firefox is currently in offline mode and can't browse the Web.
|
||||
isprinting=The document cannot change while Printing or in Print Preview.
|
||||
deniedPortAccess=This address uses a network port which is normally used for purposes other than Web browsing. Firefox has canceled the request for your protection.
|
||||
|
|
|
@ -52,6 +52,9 @@
|
|||
<!ENTITY netInterrupt.title "The connection was interrupted">
|
||||
<!ENTITY netInterrupt.longDesc "&sharedLongDesc;">
|
||||
|
||||
<!ENTITY notCached.title "Document Expired">
|
||||
<!ENTITY notCached.longDesc "<p>The requested document is not available in Firefox's cache.</p><ul><li>As a security precuation, Firefox does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
|
||||
|
||||
<!ENTITY netOffline.title "Offline mode">
|
||||
<!ENTITY netOffline.longDesc2 "
|
||||
<ul>
|
||||
|
|
|
@ -285,8 +285,10 @@ class DeviceManagerADB(DeviceManager):
|
|||
# success: output of pullfile, string
|
||||
# failure: None
|
||||
def getFile(self, remoteFile, localFile = 'tmpfile_dm_adb'):
|
||||
# TODO: add debug flags and allow for printing stdout
|
||||
# self.runCmd(["pull", remoteFile, localFile])
|
||||
try:
|
||||
self.checkCmd(["pull", remoteFile, localFile])
|
||||
self.runCmd(["pull", remoteFile, localFile]).stdout.read()
|
||||
f = open(localFile)
|
||||
ret = f.read()
|
||||
f.close()
|
||||
|
|
28
configure.in
28
configure.in
|
@ -7126,17 +7126,6 @@ if test -n "$MOZ_TRACEVIS"; then
|
|||
AC_DEFINE(MOZ_TRACEVIS)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use GCTimer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(gctimer,
|
||||
[ --enable-gctimer Enable GC timer (default=no)],
|
||||
MOZ_GCTIMER=1,
|
||||
MOZ_GCTIMER= )
|
||||
if test -n "$MOZ_GCTIMER"; then
|
||||
AC_DEFINE(MOZ_GCTIMER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl ETW - Event Tracing for Windows
|
||||
dnl ========================================================
|
||||
|
@ -7404,6 +7393,23 @@ if test -z "$SKIP_LIBRARY_CHECKS"; then
|
|||
MOZ_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace))
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl JIT observers
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_WITH_STRING(jitreport-granularity,
|
||||
[ --jitreport-granularity=N
|
||||
Default granularity at which to report JIT code
|
||||
to external tools
|
||||
0 - no info
|
||||
1 - code ranges for whole functions only
|
||||
2 - per-line information
|
||||
3 - per-op information],
|
||||
JITREPORT_GRANULARITY=$withval,
|
||||
JITREPORT_GRANULARITY=3)
|
||||
|
||||
AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY)
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Misc. Options
|
||||
|
|
|
@ -126,8 +126,8 @@ class Element;
|
|||
} // namespace mozilla
|
||||
|
||||
#define NS_IDOCUMENT_IID \
|
||||
{ 0xd76bcf5f, 0xd02f, 0x459a, \
|
||||
{ 0xb1, 0x23, 0x8e, 0x2c, 0x9a, 0x0d, 0x84, 0x68 } }
|
||||
{ 0x448c396a, 0x013c, 0x47b8, \
|
||||
{ 0x95, 0xf4, 0x56, 0x68, 0x0f, 0x5f, 0x12, 0xf8 } }
|
||||
|
||||
// Flag for AddStyleSheet().
|
||||
#define NS_STYLESHEET_FROM_CATALOG (1 << 0)
|
||||
|
@ -1321,17 +1321,17 @@ public:
|
|||
* OnPageShow() having been called already and OnPageHide() not having been
|
||||
* called yet.
|
||||
*/
|
||||
bool IsShowing() { return mIsShowing; }
|
||||
bool IsShowing() const { return mIsShowing; }
|
||||
/**
|
||||
* Return whether the document is currently visible (in the sense of
|
||||
* OnPageHide having been called and OnPageShow not yet having been called)
|
||||
*/
|
||||
bool IsVisible() { return mVisible; }
|
||||
bool IsVisible() const { return mVisible; }
|
||||
/**
|
||||
* Return true when this document is active, i.e., the active document
|
||||
* in a content viewer.
|
||||
*/
|
||||
bool IsActive() { return mDocumentContainer && !mRemovedFromDocShell; }
|
||||
bool IsActive() const { return mDocumentContainer && !mRemovedFromDocShell; }
|
||||
|
||||
void RegisterFreezableElement(nsIContent* aContent);
|
||||
bool UnregisterFreezableElement(nsIContent* aContent);
|
||||
|
@ -1573,6 +1573,8 @@ public:
|
|||
#undef DEPRECATED_OPERATION
|
||||
void WarnOnceAbout(DeprecatedOperations aOperation);
|
||||
|
||||
virtual void PostVisibilityUpdateEvent() = 0;
|
||||
|
||||
private:
|
||||
PRUint64 mWarnedAbout;
|
||||
|
||||
|
|
|
@ -1526,6 +1526,7 @@ nsDocument::nsDocument(const char* aContentType)
|
|||
: nsIDocument()
|
||||
, mAnimatingImages(PR_TRUE)
|
||||
, mIsFullScreen(PR_FALSE)
|
||||
, mVisibilityState(eHidden)
|
||||
{
|
||||
SetContentTypeInternal(nsDependentCString(aContentType));
|
||||
|
||||
|
@ -3837,6 +3838,13 @@ nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|||
// having to QI every time it's asked for.
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
|
||||
mWindow = window;
|
||||
|
||||
// Set our visibility state, but do not fire the event. This is correct
|
||||
// because either we're coming out of bfcache (in which case IsVisible() will
|
||||
// still test false at this point and no state change will happen) or we're
|
||||
// doing the initial document load and don't want to fire the event for this
|
||||
// change.
|
||||
mVisibilityState = GetVisibilityState();
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject*
|
||||
|
@ -7322,6 +7330,8 @@ nsDocument::OnPageShow(bool aPersisted,
|
|||
SetImagesNeedAnimating(PR_TRUE);
|
||||
}
|
||||
|
||||
UpdateVisibilityState();
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target = aDispatchStartTarget;
|
||||
if (!target) {
|
||||
target = do_QueryInterface(GetWindow());
|
||||
|
@ -7383,6 +7393,9 @@ nsDocument::OnPageHide(bool aPersisted,
|
|||
DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
|
||||
|
||||
mVisible = PR_FALSE;
|
||||
|
||||
UpdateVisibilityState();
|
||||
|
||||
EnumerateExternalResources(NotifyPageHide, &aPersisted);
|
||||
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
|
||||
}
|
||||
|
@ -8658,3 +8671,61 @@ nsDocument::SizeOf() const
|
|||
#undef DOCUMENT_ONLY_EVENT
|
||||
#undef TOUCH_EVENT
|
||||
#undef EVENT
|
||||
|
||||
void
|
||||
nsDocument::UpdateVisibilityState()
|
||||
{
|
||||
VisibilityState oldState = mVisibilityState;
|
||||
mVisibilityState = GetVisibilityState();
|
||||
if (oldState != mVisibilityState) {
|
||||
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
|
||||
NS_LITERAL_STRING("mozvisibilitychange"),
|
||||
false, false);
|
||||
}
|
||||
}
|
||||
|
||||
nsDocument::VisibilityState
|
||||
nsDocument::GetVisibilityState() const
|
||||
{
|
||||
// We have to check a few pieces of information here:
|
||||
// 1) Are we in bfcache (!IsVisible())? If so, nothing else matters.
|
||||
// 2) Do we have an outer window? If not, we're hidden. Note that we don't
|
||||
// want to use GetWindow here because it does weird groveling for windows
|
||||
// in some cases.
|
||||
// 3) Is our outer window background? If so, we're hidden.
|
||||
// Otherwise, we're visible.
|
||||
if (!IsVisible() || !mWindow || !mWindow->GetOuterWindow() ||
|
||||
mWindow->GetOuterWindow()->IsBackground()) {
|
||||
return eHidden;
|
||||
}
|
||||
|
||||
return eVisible;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsDocument::PostVisibilityUpdateEvent()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState);
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozHidden(bool* aHidden)
|
||||
{
|
||||
*aHidden = mVisibilityState != eVisible;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozVisibilityState(nsAString& aState)
|
||||
{
|
||||
// This needs to stay in sync with the VisibilityState enum.
|
||||
static const char states[][8] = {
|
||||
"hidden",
|
||||
"visible"
|
||||
};
|
||||
PR_STATIC_ASSERT(NS_ARRAY_LENGTH(states) == eVisibilityStateCount);
|
||||
aState.AssignASCII(states[mVisibilityState]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -948,6 +948,12 @@ public:
|
|||
virtual void UpdateFullScreenStatus(bool aIsFullScreen);
|
||||
virtual bool IsFullScreenDoc();
|
||||
|
||||
// This method may fire a DOM event; if it does so it will happen
|
||||
// synchronously.
|
||||
void UpdateVisibilityState();
|
||||
// Posts an event to call UpdateVisibilityState
|
||||
virtual void PostVisibilityUpdateEvent();
|
||||
|
||||
protected:
|
||||
friend class nsNodeUtils;
|
||||
|
||||
|
@ -1150,6 +1156,14 @@ protected:
|
|||
nsRefPtr<nsDOMNavigationTiming> mTiming;
|
||||
private:
|
||||
friend class nsUnblockOnloadEvent;
|
||||
// This needs to stay in sync with the list in GetMozVisibilityState.
|
||||
enum VisibilityState {
|
||||
eHidden = 0,
|
||||
eVisible,
|
||||
eVisibilityStateCount
|
||||
};
|
||||
// Recomputes the visibility state but doesn't set the new value.
|
||||
VisibilityState GetVisibilityState() const;
|
||||
|
||||
void PostUnblockOnloadEvent();
|
||||
void DoUnblockOnload();
|
||||
|
@ -1230,6 +1244,8 @@ private:
|
|||
// Tracking for images in the document.
|
||||
nsDataHashtable< nsPtrHashKey<imgIRequest>, PRUint32> mImageTracker;
|
||||
|
||||
VisibilityState mVisibilityState;
|
||||
|
||||
#ifdef DEBUG
|
||||
protected:
|
||||
bool mWillReparent;
|
||||
|
|
|
@ -516,6 +516,7 @@ _TEST_FILES2 = \
|
|||
test_bug684671.html \
|
||||
test_bug685798.html \
|
||||
test_bug686449.xhtml \
|
||||
test_bug690056.html \
|
||||
test_bug692434.html \
|
||||
file_bug692434.xml \
|
||||
$(NULL)
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=690056
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 690056</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=690056">Mozilla Bug 690056</a>
|
||||
<p id="display">
|
||||
<iframe id="x"></iframe>
|
||||
<iframe style="display: none" id="y"></iframe>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 690056 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
is(document.mozHidden, false, "Document should not be hidden during load");
|
||||
is(document.mozVisibilityState, "visible",
|
||||
"Document should be visible during load");
|
||||
|
||||
addLoadEvent(function() {
|
||||
var doc = document.implementation.createDocument("", "", null);
|
||||
is(doc.mozHidden, true, "Data documents should be hidden");
|
||||
is(doc.mozVisibilityState, "hidden", "Data documents really should be hidden");
|
||||
|
||||
is(document.mozHidden, false, "Document should not be hidden onload");
|
||||
is(document.mozVisibilityState, "visible",
|
||||
"Document should be visible onload");
|
||||
|
||||
is($("x").contentDocument.mozHidden, false,
|
||||
"Subframe document should not be hidden onload");
|
||||
is($("x").contentDocument.mozVisibilityState, "visible",
|
||||
"Subframe document should be visible onload");
|
||||
is($("y").contentDocument.mozHidden, false,
|
||||
"display:none subframe document should not be hidden onload");
|
||||
is($("y").contentDocument.mozVisibilityState, "visible",
|
||||
"display:none subframe document should be visible onload");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -77,8 +77,8 @@ public:
|
|||
class txACompileObserver
|
||||
{
|
||||
public:
|
||||
virtual void AddRef() = 0;
|
||||
virtual void Release() = 0;
|
||||
NS_IMETHOD_(nsrefcnt) AddRef() = 0;
|
||||
NS_IMETHOD_(nsrefcnt) Release() = 0;
|
||||
|
||||
virtual nsresult loadURI(const nsAString& aUri,
|
||||
const nsAString& aReferrerUri,
|
||||
|
|
|
@ -3974,10 +3974,12 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||
error.AssignLiteral("netReset");
|
||||
break;
|
||||
case NS_ERROR_DOCUMENT_NOT_CACHED:
|
||||
// Doc failed to load because we are offline and the cache does not
|
||||
// contain a copy of the document.
|
||||
// Doc failed to load because the cache does not contain a copy of
|
||||
// the document.
|
||||
error.AssignLiteral("notCached");
|
||||
break;
|
||||
case NS_ERROR_OFFLINE:
|
||||
// Doc failed to load because we are offline
|
||||
// Doc failed to load because we are offline.
|
||||
error.AssignLiteral("netOffline");
|
||||
break;
|
||||
case NS_ERROR_DOCUMENT_IS_PRINTMODE:
|
||||
|
@ -4882,6 +4884,10 @@ nsDocShell::SetIsActive(bool aIsActive)
|
|||
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mScriptGlobal);
|
||||
if (win) {
|
||||
win->SetIsBackground(!aIsActive);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(win->GetExtantDocument());
|
||||
if (doc) {
|
||||
doc->PostVisibilityUpdateEvent();
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively tell all of our children
|
||||
|
@ -6366,109 +6372,17 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
|
|||
aStatus == NS_ERROR_PHISHING_URI ||
|
||||
aStatus == NS_ERROR_UNSAFE_CONTENT_TYPE ||
|
||||
aStatus == NS_ERROR_REMOTE_XUL ||
|
||||
aStatus == NS_ERROR_OFFLINE ||
|
||||
NS_ERROR_GET_MODULE(aStatus) == NS_ERROR_MODULE_SECURITY) {
|
||||
DisplayLoadError(aStatus, url, nsnull, aChannel);
|
||||
}
|
||||
else if (aStatus == NS_ERROR_DOCUMENT_NOT_CACHED) {
|
||||
/* A document that was requested to be fetched *only* from
|
||||
* the cache is not in cache. May be this is one of those
|
||||
* postdata results. Throw a dialog to the user,
|
||||
* saying that the page has expired from cache and ask if
|
||||
* they wish to refetch the page from the net. Do this only
|
||||
* if the request is a form post.
|
||||
*/
|
||||
nsCAutoString method;
|
||||
if (httpChannel)
|
||||
httpChannel->GetRequestMethod(method);
|
||||
if (method.Equals("POST") && !NS_IsOffline()) {
|
||||
bool repost;
|
||||
rv = ConfirmRepost(&repost);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
// If the user pressed cancel in the dialog, return. Don't try
|
||||
// to load the page without the post data.
|
||||
if (!repost)
|
||||
return NS_OK;
|
||||
|
||||
// The user wants to repost the data to the server.
|
||||
// If the page was loaded due to a back/forward/go
|
||||
// operation, update the session history index.
|
||||
// This is similar to the updating done in
|
||||
// nsDocShell::OnNewURI() for regular pages
|
||||
nsCOMPtr<nsISHistory> rootSH=mSessionHistory;
|
||||
if (!mSessionHistory) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> root;
|
||||
//Get the root docshell
|
||||
GetSameTypeRootTreeItem(getter_AddRefs(root));
|
||||
if (root) {
|
||||
// QI root to nsIWebNavigation
|
||||
nsCOMPtr<nsIWebNavigation> rootAsWebnav =
|
||||
do_QueryInterface(root);
|
||||
if (rootAsWebnav) {
|
||||
// Get the handle to SH from the root docshell
|
||||
rootAsWebnav->GetSessionHistory(getter_AddRefs(rootSH));
|
||||
}
|
||||
}
|
||||
} // mSessionHistory
|
||||
|
||||
if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) {
|
||||
nsCOMPtr<nsISHistoryInternal> shInternal =
|
||||
do_QueryInterface(rootSH);
|
||||
if (shInternal) {
|
||||
rootSH->GetIndex(&mPreviousTransIndex);
|
||||
shInternal->UpdateIndex();
|
||||
rootSH->GetIndex(&mLoadedTransIndex);
|
||||
#ifdef DEBUG_PAGE_CACHE
|
||||
printf("Previous index: %d, Loaded index: %d\n\n",
|
||||
mPreviousTransIndex, mLoadedTransIndex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Make it look like we really did honestly finish loading the
|
||||
// history page we were loading, since the "reload" load we're
|
||||
// about to kick off will reload our current history entry.
|
||||
// This is a bit of a hack, and if the force-load fails I think
|
||||
// we'll end up being confused about what page we're on... but
|
||||
// we would anyway, since we've updated the session history
|
||||
// index above.
|
||||
SetHistoryEntry(&mOSHE, loadingSHE);
|
||||
|
||||
// The user does want to repost the data to the server.
|
||||
// Initiate a new load again.
|
||||
|
||||
// Get the postdata if any from the channel.
|
||||
nsCOMPtr<nsIInputStream> inputStream;
|
||||
nsCOMPtr<nsIURI> referrer;
|
||||
if (httpChannel) {
|
||||
httpChannel->GetReferrer(getter_AddRefs(referrer));
|
||||
nsCOMPtr<nsIUploadChannel> uploadChannel =
|
||||
do_QueryInterface(aChannel);
|
||||
if (uploadChannel) {
|
||||
uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsISeekableStream> postDataSeekable =
|
||||
do_QueryInterface(inputStream);
|
||||
if (postDataSeekable) {
|
||||
postDataSeekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
}
|
||||
InternalLoad(url, // URI
|
||||
referrer, // Referring URI
|
||||
nsnull, // Owner
|
||||
INTERNAL_LOAD_FLAGS_INHERIT_OWNER, // Inherit owner
|
||||
nsnull, // No window target
|
||||
nsnull, // No type hint
|
||||
inputStream, // Post data stream
|
||||
nsnull, // No headers stream
|
||||
LOAD_RELOAD_BYPASS_PROXY_AND_CACHE,// Load type
|
||||
nsnull, // No SHEntry
|
||||
PR_TRUE, // first party site
|
||||
nsnull, // No nsIDocShell
|
||||
nsnull); // No nsIRequest
|
||||
}
|
||||
else {
|
||||
DisplayLoadError(aStatus, url, nsnull, aChannel);
|
||||
}
|
||||
// Non-caching channels will simply return NS_ERROR_OFFLINE.
|
||||
// Caching channels would have to look at their flags to work
|
||||
// out which error to return. Or we can fix up the error here.
|
||||
if (!(mLoadType & LOAD_CMD_HISTORY))
|
||||
aStatus = NS_ERROR_OFFLINE;
|
||||
DisplayLoadError(aStatus, url, nsnull, aChannel);
|
||||
}
|
||||
} // if we have a host
|
||||
|
||||
|
|
|
@ -323,6 +323,7 @@
|
|||
<h1 id="et_redirectLoop">&redirectLoop.title;</h1>
|
||||
<h1 id="et_unknownSocketType">&unknownSocketType.title;</h1>
|
||||
<h1 id="et_netReset">&netReset.title;</h1>
|
||||
<h1 id="et_notCached">¬Cached.title;</h1>
|
||||
<h1 id="et_netOffline">&netOffline.title;</h1>
|
||||
<h1 id="et_netInterrupt">&netInterrupt.title;</h1>
|
||||
<h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
|
||||
|
@ -348,6 +349,7 @@
|
|||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
<div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
|
||||
<div id="ed_netReset">&netReset.longDesc;</div>
|
||||
<div id="ed_notCached">¬Cached.longDesc;</div>
|
||||
<div id="ed_netOffline">&netOffline.longDesc2;</div>
|
||||
<div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
|
||||
<div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
|
||||
|
|
|
@ -120,6 +120,8 @@ _TEST_FILES = \
|
|||
662200a.html \
|
||||
662200b.html \
|
||||
662200c.html \
|
||||
test_bug690056.xul \
|
||||
bug690056_window.xul \
|
||||
$(NULL)
|
||||
|
||||
_DOCSHELL_SUBHARNESS = \
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<window id="690056Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
width="600"
|
||||
height="600"
|
||||
onload="setTimeout(nextTest,0);"
|
||||
title="bug 6500056 test">
|
||||
|
||||
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
|
||||
<script type="application/javascript" src="docshell_helpers.js" />
|
||||
<script type="application/javascript"><![CDATA[
|
||||
var tests = testIterator();
|
||||
|
||||
function nextTest() {
|
||||
tests.next();
|
||||
}
|
||||
|
||||
// Makes sure that we fire the visibilitychange events
|
||||
function testIterator() {
|
||||
// Enable bfcache
|
||||
enableBFCache(8);
|
||||
|
||||
// Load something for a start
|
||||
doPageNavigation({
|
||||
uri: 'data:text/html,<title>initial load</title>',
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Now load a new page
|
||||
doPageNavigation({
|
||||
uri: 'data:text/html,<title>new load</title>',
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
// No visibilitychange events fired for initial pageload
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: false }, // false on initial load
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Now go back
|
||||
doPageNavigation({
|
||||
back: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// And forward
|
||||
doPageNavigation({
|
||||
forward: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
function generateDetector(state, hidden, title, name) {
|
||||
var detector = function (event) {
|
||||
is(event.target.mozHidden, hidden,
|
||||
name + " hidden value does not match");
|
||||
is(event.target.mozVisibilityState, state,
|
||||
name + " state value does not match");
|
||||
is(event.target.title, title,
|
||||
name + " title value does not match");
|
||||
document.getElementById("content")
|
||||
.removeEventListener("mozvisibilitychange",
|
||||
detector,
|
||||
true);
|
||||
nextTest();
|
||||
}
|
||||
|
||||
document.getElementById("content")
|
||||
.addEventListener("mozvisibilitychange", detector, true);
|
||||
}
|
||||
|
||||
generateDetector("hidden", true, "new load", "Going hidden");
|
||||
|
||||
// Now flip our docshell to not active
|
||||
document.getElementById("content").docShellIsActive = false;
|
||||
yield;
|
||||
|
||||
// And navigate back; there should be no visibility state transitions
|
||||
doPageNavigation({
|
||||
back: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
{ type: "pageshow",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
],
|
||||
unexpectedEvents: [ "mozvisibilitychange" ],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
generateDetector("visible", false, "initial load", "Going visible");
|
||||
|
||||
// Now set the docshell active again
|
||||
document.getElementById("content").docShellIsActive = true;
|
||||
yield;
|
||||
|
||||
// And forward
|
||||
doPageNavigation({
|
||||
forward: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Tell the framework the test is finished. Include the final 'yield'
|
||||
// statement to prevent a StopIteration exception from being thrown.
|
||||
finish();
|
||||
yield;
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
|
||||
</window>
|
|
@ -18,6 +18,8 @@ const NAV_RELOAD = 4;
|
|||
|
||||
var gExpectedEvents; // an array of events which are expected to
|
||||
// be triggered by this navigation
|
||||
var gUnexpectedEvents; // an array of event names which are NOT expected
|
||||
// to be triggered by this navigation
|
||||
var gFinalEvent; // true if the last expected event has fired
|
||||
var gUrisNotInBFCache = []; // an array of uri's which shouldn't be stored
|
||||
// in the bfcache
|
||||
|
@ -95,6 +97,8 @@ function doPageNavigation(params) {
|
|||
params.eventsToListenFor : ["pageshow"];
|
||||
gExpectedEvents = typeof(params.eventsToListenFor) == "undefined" ||
|
||||
eventsToListenFor.length == 0 ? undefined : params.expectedEvents;
|
||||
gUnexpectedEvents = typeof(params.eventsToListenFor) == "undefined" ||
|
||||
eventsToListenFor.length == 0 ? undefined : params.unexpectedEvents;
|
||||
let preventBFCache = (typeof[params.preventBFCache] == "undefined") ?
|
||||
false : params.preventBFCache;
|
||||
let waitOnly = (typeof(params.waitForEventsOnly) == "boolean"
|
||||
|
@ -129,6 +133,10 @@ function doPageNavigation(params) {
|
|||
if (anExpectedEvent.type == anEventType)
|
||||
eventFound = true;
|
||||
}
|
||||
for each (let anExpectedEventType in gUnexpectedEvents) {
|
||||
if (anExpectedEventType == anEventType)
|
||||
eventFound = true;
|
||||
}
|
||||
if (!eventFound)
|
||||
throw "Event type " + anEventType + " is specified in " +
|
||||
"eventsToListenFor, but not in expectedEvents";
|
||||
|
@ -260,7 +268,12 @@ function pageEventListener(event) {
|
|||
"though it was loaded with .preventBFCache previously\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (typeof(gUnexpectedEvents) != "undefined") {
|
||||
is(gUnexpectedEvents.indexOf(event.type), -1,
|
||||
"Should not get unexpected event " + event.type);
|
||||
}
|
||||
|
||||
// If no expected events were specified, mark the final event as having been
|
||||
// triggered when a pageshow event is fired; this will allow
|
||||
// doPageNavigation() to return.
|
||||
|
@ -301,6 +314,18 @@ function pageEventListener(event) {
|
|||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
if ("visibilityState" in expected) {
|
||||
is(event.originalTarget.mozVisibilityState, expected.visibilityState,
|
||||
"The visibilityState property of the document on page " +
|
||||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
if ("hidden" in expected) {
|
||||
is(event.originalTarget.mozHidden, expected.hidden,
|
||||
"The hidden property of the document on page " +
|
||||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
// If we're out of expected events, let doPageNavigation() return.
|
||||
if (gExpectedEvents.length == 0)
|
||||
setTimeout(function() { gFinalEvent = true; }, 0);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=690056
|
||||
-->
|
||||
<window title="Mozilla Bug 690056"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=690056"
|
||||
target="_blank">Mozilla Bug 690056</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for Bug 690056 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.open("bug690056_window.xul", "bug690056",
|
||||
"chrome,width=600,height=600");
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -207,7 +207,7 @@ ConsoleAPI.prototype = {
|
|||
switch (spec[spec.length-1]) {
|
||||
case "o":
|
||||
case "s":
|
||||
return args.shift().toString();
|
||||
return String(args.shift());
|
||||
case "d":
|
||||
case "i":
|
||||
return parseInt(args.shift());
|
||||
|
|
|
@ -97,21 +97,29 @@ public:
|
|||
|
||||
virtual void SetActive(bool aActive)
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"active state is only maintained on outer windows");
|
||||
mIsActive = aActive;
|
||||
}
|
||||
|
||||
bool IsActive()
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"active state is only maintained on outer windows");
|
||||
return mIsActive;
|
||||
}
|
||||
|
||||
virtual void SetIsBackground(bool aIsBackground)
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"background state is only maintained on outer windows");
|
||||
mIsBackground = aIsBackground;
|
||||
}
|
||||
|
||||
bool IsBackground()
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"background state is only maintained on outer windows");
|
||||
return mIsBackground;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ interface nsIDOMLocation;
|
|||
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
|
||||
*/
|
||||
|
||||
[scriptable, uuid(3f845f32-cb34-459c-8f79-2dfaa3088bbf)]
|
||||
[scriptable, uuid(CD4CD7C3-C688-4E50-9A72-4A00EABE66AB)]
|
||||
interface nsIDOMDocument : nsIDOMNode
|
||||
{
|
||||
readonly attribute nsIDOMDocumentType doctype;
|
||||
|
@ -411,4 +411,10 @@ interface nsIDOMDocument : nsIDOMNode
|
|||
|
||||
[implicit_jscontext] attribute jsval onmouseenter;
|
||||
[implicit_jscontext] attribute jsval onmouseleave;
|
||||
|
||||
/**
|
||||
* Visibility API implementation.
|
||||
*/
|
||||
readonly attribute boolean mozHidden;
|
||||
readonly attribute DOMString mozVisibilityState;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "nsIDOMDocument.idl"
|
||||
|
||||
[scriptable, uuid(9f566fd8-8bd7-49eb-be8b-16fb50d00d32)]
|
||||
[scriptable, uuid(BB4D4D76-3802-4191-88E2-933BA609C4E1)]
|
||||
interface nsIDOMXMLDocument : nsIDOMDocument
|
||||
{
|
||||
// DOM Level 3 Load & Save, DocumentLS
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
*/
|
||||
interface nsISelection;
|
||||
|
||||
[scriptable, uuid(280857b8-c52c-455e-8b47-c56ad96614f7)]
|
||||
[scriptable, uuid(C94A5F14-F79F-4054-A93C-E8FF35623460)]
|
||||
interface nsIDOMHTMLDocument : nsIDOMDocument
|
||||
{
|
||||
readonly attribute DOMString URL;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
interface nsIDOMSVGSVGElement;
|
||||
|
||||
[scriptable, uuid(78ebe55f-631f-4b3b-9eba-c3689ff5ccbc)]
|
||||
[scriptable, uuid(B3806DF6-7ED4-4426-84E6-545EEFE5AA9A)]
|
||||
interface nsIDOMSVGDocument : nsIDOMDocument
|
||||
{
|
||||
readonly attribute DOMString domain;
|
||||
|
|
|
@ -46,6 +46,7 @@ confirmRepostPrompt=To display this page, the application must send information
|
|||
resendButton.label=Resend
|
||||
unknownSocketType=This document cannot be displayed unless you install the Personal Security Manager (PSM). Download and install PSM and try again, or contact your system administrator.
|
||||
netReset=The document contains no data.
|
||||
notCached=This document is no longer available.
|
||||
netOffline=This document cannot be displayed while offline. To go online, uncheck Work Offline from the File menu.
|
||||
isprinting=The document cannot change while Printing or in Print Preview.
|
||||
deniedPortAccess=Access to the port number given has been disabled for security reasons.
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
<!ENTITY netInterrupt.title "Data Transfer Interrupted">
|
||||
<!ENTITY netInterrupt.longDesc "<p>The browser connected successfully, but the connection was interrupted while transferring information. Please try again.</p><ul><li>Are you unable to browse other sites? Check the computer's network connection.</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>">
|
||||
|
||||
<!ENTITY notCached.title "Document Expired">
|
||||
<!ENTITY notCached.longDesc "<p>The requested document is not available in the browser's cache.</p><ul><li>As a security precuation, the browser does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
|
||||
|
||||
<!ENTITY netOffline.title "Offline Mode">
|
||||
<!ENTITY netOffline.longDesc2 "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Press "Try Again" to switch to online mode and reload the page.</li></ul>">
|
||||
|
||||
|
|
|
@ -160,9 +160,6 @@ static JSBool
|
|||
NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp);
|
||||
|
||||
static JSBool
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
||||
|
||||
static void
|
||||
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
|
@ -183,7 +180,7 @@ static JSClass sNPObjectJSWrapperClass =
|
|||
NPObjWrapper_AddProperty, NPObjWrapper_DelProperty,
|
||||
NPObjWrapper_GetProperty, NPObjWrapper_SetProperty,
|
||||
(JSEnumerateOp)NPObjWrapper_newEnumerate,
|
||||
(JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert,
|
||||
(JSResolveOp)NPObjWrapper_NewResolve, JS_ConvertStub,
|
||||
NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call,
|
||||
NPObjWrapper_Construct, nsnull, nsnull
|
||||
};
|
||||
|
@ -1683,18 +1680,6 @@ NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
// The sole reason we implement this hook is to prevent the JS
|
||||
// engine from calling valueOf() on NPObject's. Some NPObject's may
|
||||
// actually implement a method named valueOf, but it's unlikely to
|
||||
// behave as the JS engine expects it to. IOW, this is an empty hook
|
||||
// that overrides what the default hook does.
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
|
@ -2195,6 +2180,9 @@ NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|||
case JSTYPE_BOOLEAN:
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = memberPrivate->fieldValue;
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp)) {
|
||||
return JS_ConvertStub(cx, JSVAL_TO_OBJECT(*vp), type, vp);
|
||||
}
|
||||
return JS_TRUE;
|
||||
case JSTYPE_FUNCTION:
|
||||
// Leave this to NPObjectMember_Call.
|
||||
|
|
|
@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_MOCHITEST_FILES = \
|
||||
utils.js \
|
||||
test_defaultValue.html \
|
||||
test_getauthenticationinfo.html \
|
||||
test_npobject_getters.html \
|
||||
test_npruntime_npnevaluate.html \
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>NPObject [[DefaultValue]] implementation</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body onload="run()">
|
||||
|
||||
<embed id="plugin" type="application/x-test" wmode="window"></embed>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function run() {
|
||||
var plugin = document.getElementById("plugin");
|
||||
var pluginProto = Object.getPrototypeOf(plugin);
|
||||
|
||||
plugin.propertyAndMethod = {};
|
||||
plugin.propertyAndMethod + "baz";
|
||||
ok(true, "|plugin.propertyAndMethod + \"baz\"| shouldn't assert");
|
||||
pluginProto.propertyAndMethod = {};
|
||||
pluginProto.propertyAndMethod + "quux";
|
||||
ok(true, "|pluginProto.propertyAndMethod + \"quux\"| shouldn't assert");
|
||||
|
||||
plugin + "foo";
|
||||
ok(true, "|plugin + \"foo\"| shouldn't assert");
|
||||
pluginProto + "bar";
|
||||
ok(true, "|pluginProto + \"bar\"| shouldn't assert");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -9,8 +9,6 @@
|
|||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<iframe id="subframe" src="npruntime_identifiers_subpage.html"></iframe>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
////
|
||||
// This test exercises NP identifiers by querying the reflector to make sure
|
||||
|
@ -20,8 +18,6 @@
|
|||
|
||||
var testsRun = 0;
|
||||
|
||||
document.getElementById('subframe').addEventListener('load', doTest, false);
|
||||
|
||||
function doTest() {
|
||||
SpecialPowers.gc();
|
||||
|
||||
|
@ -56,5 +52,8 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe id="subframe" src="npruntime_identifiers_subpage.html" onload="doTest()"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -220,6 +220,10 @@ function observeConsoleTest() {
|
|||
expect("log", "2, a, %l", 3);
|
||||
win.console.log("%d, %s, %l", 2, "a", 3);
|
||||
|
||||
// bug #692550 handle null and undefined
|
||||
expect("log", "null, undefined");
|
||||
win.console.log("%s, %s", null, undefined);
|
||||
|
||||
expect("dir", win.toString());
|
||||
win.console.dir(win);
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include "Events.h"
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ abstract public class GeckoApp
|
|||
|
||||
public static AbsoluteLayout mainLayout;
|
||||
public static GeckoSurfaceView surfaceView;
|
||||
public static SurfaceView cameraView;
|
||||
public static GeckoApp mAppContext;
|
||||
public static boolean mFullscreen = false;
|
||||
public static File sGREDir = null;
|
||||
|
@ -377,6 +378,11 @@ abstract public class GeckoApp
|
|||
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
if (cameraView == null) {
|
||||
cameraView = new SurfaceView(this);
|
||||
cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
}
|
||||
|
||||
if (surfaceView == null)
|
||||
surfaceView = new GeckoSurfaceView(this);
|
||||
else
|
||||
|
@ -388,6 +394,10 @@ abstract public class GeckoApp
|
|||
AbsoluteLayout.LayoutParams.MATCH_PARENT,
|
||||
0,
|
||||
0));
|
||||
|
||||
// Some phones (eg. nexus S) need at least a 8x16 preview size
|
||||
mainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
|
||||
|
||||
setContentView(mainLayout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
|
|
|
@ -1531,7 +1531,7 @@ public class GeckoAppShell
|
|||
|
||||
static int kPreferedFps = 25;
|
||||
static byte[] sCameraBuffer = null;
|
||||
|
||||
|
||||
static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
|
||||
Log.i("GeckoAppJava", "initCamera(" + aContentType + ", " + aWidth + "x" + aHeight + ") on thread " + Thread.currentThread().getId());
|
||||
|
||||
|
@ -1585,6 +1585,14 @@ public class GeckoAppShell
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sCamera.setPreviewDisplay(GeckoApp.cameraView.getHolder());
|
||||
} catch(IOException e) {
|
||||
Log.e("GeckoAppJava", "Error setPreviewDisplay:", e);
|
||||
} catch(RuntimeException e) {
|
||||
Log.e("GeckoAppJava", "Error setPreviewDisplay:", e);
|
||||
}
|
||||
|
||||
sCamera.setParameters(params);
|
||||
sCameraBuffer = new byte[(bufferSize * 12) / 8];
|
||||
sCamera.addCallbackBuffer(sCameraBuffer);
|
||||
|
|
|
@ -46,9 +46,7 @@ MODULE = embedcomponents
|
|||
LIBRARY_NAME = windowwatcher_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
CPPSRCS = \
|
||||
nsWWJSUtils.cpp \
|
||||
nsWindowWatcher.cpp \
|
||||
nsAutoWindowStateHelper.cpp \
|
||||
$(NULL)
|
||||
|
@ -62,5 +60,7 @@ endif
|
|||
# static lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
# For nsJSUtils
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/base
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** 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 Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
/* This file is a small subset of nsJSUtils utility functions,
|
||||
from the dom directory.
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsWWJSUtils.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
||||
nsIScriptGlobalObject *
|
||||
nsWWJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)
|
||||
{
|
||||
nsISupports* supports;
|
||||
JSClass* clazz;
|
||||
JSObject* parent;
|
||||
JSObject* glob = aObj; // starting point for search
|
||||
|
||||
if (!glob)
|
||||
return nsnull;
|
||||
|
||||
while (nsnull != (parent = JS_GetParent(aContext, glob)))
|
||||
glob = parent;
|
||||
|
||||
clazz = JS_GET_CLASS(aContext, glob);
|
||||
|
||||
if (!clazz ||
|
||||
!(clazz->flags & JSCLASS_HAS_PRIVATE) ||
|
||||
!(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
|
||||
!(supports = (nsISupports*) JS_GetPrivate(aContext, glob))) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(supports));
|
||||
NS_ENSURE_TRUE(wrapper, nsnull);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
|
||||
|
||||
// This will return a pointer to something we're about to release,
|
||||
// but that's ok here.
|
||||
return sgo;
|
||||
}
|
||||
|
||||
nsIScriptContext *
|
||||
nsWWJSUtils::GetDynamicScriptContext(JSContext *aContext)
|
||||
{
|
||||
return GetScriptContextFromJSContext(aContext);
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject *
|
||||
nsWWJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
|
||||
{
|
||||
nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
|
||||
if (!scriptCX)
|
||||
return nsnull;
|
||||
return scriptCX->GetGlobalObject();
|
||||
}
|
||||
|
||||
nsIScriptContext *
|
||||
nsWWJSUtils::GetStaticScriptContext(JSContext* aContext,
|
||||
JSObject* aObj)
|
||||
{
|
||||
nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aContext, aObj);
|
||||
if (!nativeGlobal)
|
||||
return nsnull;
|
||||
return nativeGlobal->GetContext();
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include "nsCRT.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsWWJSUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "nsIBaseWindow.h"
|
||||
|
@ -316,7 +316,7 @@ nsresult JSContextAutoPopper::Push(JSContext *cx)
|
|||
// Save cx in mContext to indicate need to pop.
|
||||
if (cx && NS_SUCCEEDED(mService->Push(cx))) {
|
||||
mContext = cx;
|
||||
mContextKungFuDeathGrip = nsWWJSUtils::GetDynamicScriptContext(cx);
|
||||
mContextKungFuDeathGrip = nsJSUtils::GetDynamicScriptContext(cx);
|
||||
}
|
||||
}
|
||||
return mContext ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -925,7 +925,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
|||
|
||||
// get its document, if any
|
||||
if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) {
|
||||
nsIScriptGlobalObject *sgo = nsWWJSUtils::GetDynamicScriptGlobal(ccx);
|
||||
nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(ccx);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo));
|
||||
if (w) {
|
||||
|
@ -1374,7 +1374,7 @@ nsWindowWatcher::URIfromURL(const char *aURL,
|
|||
in nsGlobalWindow.cpp.) */
|
||||
JSContext *cx = GetJSContextFromCallStack();
|
||||
if (cx) {
|
||||
nsIScriptContext *scriptcx = nsWWJSUtils::GetDynamicScriptContext(cx);
|
||||
nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
|
||||
if (scriptcx) {
|
||||
baseWindow = do_QueryInterface(scriptcx->GetGlobalObject());
|
||||
}
|
||||
|
@ -1717,7 +1717,7 @@ nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
|
|||
|
||||
if (cx) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
||||
do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx));
|
||||
do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
|
||||
|
||||
if (callerWebNav) {
|
||||
CallQueryInterface(callerWebNav, &callerItem);
|
||||
|
|
|
@ -147,8 +147,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
|
|||
|
||||
if (passes == 2) {
|
||||
ComponentAlphaTextureLayerProgram *alphaProgram;
|
||||
NS_ASSERTION(!mTexImage->IsRGB() && !mTexImageOnWhite->IsRGB(),
|
||||
"Only BGR image surported with component alpha (currently!)");
|
||||
if (pass == 1) {
|
||||
alphaProgram = aManager->GetComponentAlphaPass1LayerProgram();
|
||||
gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
|
||||
|
|
|
@ -775,7 +775,6 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
|
|||
aFrom + nsIntPoint(xPos, yPos));
|
||||
}
|
||||
mShaderType = mImages[0]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[0]->IsRGB();
|
||||
mTextureState = Valid;
|
||||
return result;
|
||||
}
|
||||
|
@ -888,7 +887,6 @@ TiledTextureImage::EndUpdate()
|
|||
mInUpdate = PR_FALSE;
|
||||
mTextureState = Valid;
|
||||
mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[mCurrentImage]->IsRGB();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -916,7 +914,6 @@ TiledTextureImage::EndUpdate()
|
|||
mUpdateSurface = nsnull;
|
||||
mInUpdate = PR_FALSE;
|
||||
mShaderType = mImages[0]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[0]->IsRGB();
|
||||
mTextureState = Valid;
|
||||
}
|
||||
|
||||
|
|
|
@ -321,8 +321,6 @@ public:
|
|||
virtual bool InUpdate() const = 0;
|
||||
GLenum GetWrapMode() const { return mWrapMode; }
|
||||
|
||||
bool IsRGB() const { return mIsRGBFormat; }
|
||||
|
||||
void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
|
||||
|
||||
protected:
|
||||
|
@ -340,7 +338,6 @@ protected:
|
|||
: mSize(aSize)
|
||||
, mWrapMode(aWrapMode)
|
||||
, mContentType(aContentType)
|
||||
, mIsRGBFormat(aIsRGB)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -352,7 +349,6 @@ protected:
|
|||
nsIntSize mSize;
|
||||
GLenum mWrapMode;
|
||||
ContentType mContentType;
|
||||
bool mIsRGBFormat;
|
||||
ShaderProgramType mShaderType;
|
||||
gfxPattern::GraphicsFilter mFilter;
|
||||
};
|
||||
|
|
|
@ -1207,7 +1207,7 @@ public:
|
|||
// for RGB24. No easy way to upload that to GL.
|
||||
//
|
||||
// Note that if we start using RGB565 here, we'll need to
|
||||
// watch for a) setting mIsRGBFormat to TRUE; and b) getting
|
||||
// watch for a) setting the correct format; and b) getting
|
||||
// the stride right.
|
||||
if (mUpdateFormat == gfxASurface::ImageFormatRGB24) {
|
||||
mUpdateFormat = gfxASurface::ImageFormatARGB32;
|
||||
|
@ -1275,9 +1275,6 @@ public:
|
|||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
// if we get this far, then we're using Cairo's byte order
|
||||
mIsRGBFormat = PR_FALSE;
|
||||
|
||||
//printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
|
||||
|
||||
mUpdateSurface =
|
||||
|
@ -1646,7 +1643,6 @@ public:
|
|||
}
|
||||
|
||||
mBackingSurface = xsurface;
|
||||
mIsRGBFormat = PR_TRUE;
|
||||
#endif
|
||||
|
||||
return mBackingSurface != nsnull;
|
||||
|
|
|
@ -801,15 +801,26 @@ gfxRect gfx3DMatrix::ProjectRectBounds(const gfxRect& aRect) const
|
|||
|
||||
gfxPoint3D gfx3DMatrix::GetNormalVector() const
|
||||
{
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0));
|
||||
gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0));
|
||||
gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0));
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0));
|
||||
gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0));
|
||||
gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0));
|
||||
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
gfxPoint3D ab = b - a;
|
||||
gfxPoint3D ac = c - a;
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
gfxPoint3D ab = b - a;
|
||||
gfxPoint3D ac = c - a;
|
||||
|
||||
return ac.CrossProduct(ab);
|
||||
return ac.CrossProduct(ab);
|
||||
}
|
||||
|
||||
bool gfx3DMatrix::IsBackfaceVisible() const
|
||||
{
|
||||
// Inverse()._33 < 0;
|
||||
gfxFloat det = Determinant();
|
||||
float _33 = _12*_24*_41 - _14*_22*_41 +
|
||||
_14*_21*_42 - _11*_24*_42 -
|
||||
_12*_21*_44 + _11*_22*_44;
|
||||
return (_33 * det) < 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -306,6 +306,12 @@ public:
|
|||
*/
|
||||
gfxPoint3D GetNormalVector() const;
|
||||
|
||||
/**
|
||||
* Returns true if a plane transformed by this matrix will
|
||||
* have it's back face visible.
|
||||
*/
|
||||
bool IsBackfaceVisible() const;
|
||||
|
||||
/**
|
||||
* Check if matrix is singular (no inverse exists).
|
||||
*/
|
||||
|
|
|
@ -101,6 +101,10 @@ using namespace mozilla::ipc::windows;
|
|||
|
||||
// pulled from widget's nsAppShell
|
||||
extern const PRUnichar* kAppShellEventId;
|
||||
#if defined(ACCESSIBILITY)
|
||||
// pulled from accessibility's win utils
|
||||
extern const PRUnichar* kPropNameTabContent;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -379,6 +383,14 @@ WindowIsDeferredWindow(HWND hWnd)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
// Tab content creates a window that responds to accessible WM_GETOBJECT
|
||||
// calls. This window can safely be ignored.
|
||||
if (::GetPropW(hWnd, kPropNameTabContent)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Common mozilla windows we must defer messages to.
|
||||
nsDependentString className(buffer, length);
|
||||
if (StringBeginsWith(className, NS_LITERAL_STRING("Mozilla")) ||
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jscntxt.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
#include "mozilla/jetpack/JetpackActorCommon.h"
|
||||
#include "mozilla/jetpack/PJetpack.h"
|
||||
|
|
|
@ -43,9 +43,8 @@
|
|||
#ifndef jshashtable_h_
|
||||
#define jshashtable_h_
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsutil.h"
|
||||
#include "TemplateLib.h"
|
||||
#include "Utility.h"
|
||||
|
||||
namespace js {
|
||||
|
|
@ -14,18 +14,19 @@
|
|||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* July 16, 2009.
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Luke Wagner <lw@mozilla.com>
|
||||
* Luke Wagner <luke@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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"),
|
||||
* 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
|
||||
|
@ -37,20 +38,20 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jstl_h_
|
||||
#define jstl_h_
|
||||
#ifndef js_template_lib_h__
|
||||
#define js_template_lib_h__
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "jsstdint.h"
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
/*
|
||||
* Library of reusable template meta-functions (that is, functions on types and
|
||||
* compile-time values). Meta-functions are placed inside the 'tl' namespace to
|
||||
* avoid conflict with non-meta functions that logically have the same name
|
||||
* (e.g., js::tl::Min vs. js::Min).
|
||||
*/
|
||||
|
||||
namespace js {
|
||||
|
||||
/* JavaScript Template Library. */
|
||||
namespace tl {
|
||||
|
||||
/* Compute min/max/clamp. */
|
||||
|
@ -178,270 +179,6 @@ template <bool cond, typename T, T v1, T v2> struct If { static const T r
|
|||
template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; };
|
||||
|
||||
} /* namespace tl */
|
||||
|
||||
/* Useful for implementing containers that assert non-reentrancy */
|
||||
class ReentrancyGuard
|
||||
{
|
||||
/* ReentrancyGuard is not copyable. */
|
||||
ReentrancyGuard(const ReentrancyGuard &);
|
||||
void operator=(const ReentrancyGuard &);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool &entered;
|
||||
#endif
|
||||
public:
|
||||
template <class T>
|
||||
#ifdef DEBUG
|
||||
ReentrancyGuard(T &obj)
|
||||
: entered(obj.entered)
|
||||
#else
|
||||
ReentrancyGuard(T &/*obj*/)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!entered);
|
||||
entered = true;
|
||||
#endif
|
||||
}
|
||||
~ReentrancyGuard()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
entered = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Round x up to the nearest power of 2. This function assumes that the most
|
||||
* significant bit of x is not set, which would lead to overflow.
|
||||
*/
|
||||
STATIC_POSTCONDITION_ASSUME(return >= x)
|
||||
JS_ALWAYS_INLINE size_t
|
||||
RoundUpPow2(size_t x)
|
||||
{
|
||||
size_t log2 = JS_CEILING_LOG2W(x);
|
||||
JS_ASSERT(log2 < tl::BitSize<size_t>::result);
|
||||
size_t result = size_t(1) << log2;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class AlignedPtrAndFlag
|
||||
{
|
||||
uintptr_t bits;
|
||||
|
||||
public:
|
||||
AlignedPtrAndFlag(T *t, bool flag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag);
|
||||
}
|
||||
|
||||
T *ptr() const {
|
||||
return (T *)(bits & ~uintptr_t(1));
|
||||
}
|
||||
|
||||
bool flag() const {
|
||||
return (bits & 1) != 0;
|
||||
}
|
||||
|
||||
void setPtr(T *t) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag());
|
||||
}
|
||||
|
||||
void setFlag() {
|
||||
bits |= 1;
|
||||
}
|
||||
|
||||
void unsetFlag() {
|
||||
bits &= ~uintptr_t(1);
|
||||
}
|
||||
|
||||
void set(T *t, bool flag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | flag;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static inline void
|
||||
Reverse(T *beg, T *end)
|
||||
{
|
||||
while (beg != end) {
|
||||
if (--end == beg)
|
||||
return;
|
||||
T tmp = *beg;
|
||||
*beg = *end;
|
||||
*end = tmp;
|
||||
++beg;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T *
|
||||
Find(T *beg, T *end, const T &v)
|
||||
{
|
||||
for (T *p = beg; p != end; ++p) {
|
||||
if (*p == v)
|
||||
return p;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
static inline typename Container::ElementType *
|
||||
Find(Container &c, const typename Container::ElementType &v)
|
||||
{
|
||||
return Find(c.begin(), c.end(), v);
|
||||
}
|
||||
|
||||
template <typename InputIterT, typename CallableT>
|
||||
void
|
||||
ForEach(InputIterT begin, InputIterT end, CallableT f)
|
||||
{
|
||||
for (; begin != end; ++begin)
|
||||
f(*begin);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Min(T t1, T t2)
|
||||
{
|
||||
return t1 < t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Max(T t1, T t2)
|
||||
{
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
/* Allows a const variable to be initialized after its declaration. */
|
||||
template <class T>
|
||||
static T&
|
||||
InitConst(const T &t)
|
||||
{
|
||||
return const_cast<T &>(t);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
JS_ALWAYS_INLINE T &
|
||||
ImplicitCast(U &u)
|
||||
{
|
||||
T &t = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class AutoScopedAssign
|
||||
{
|
||||
private:
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
T *addr;
|
||||
T old;
|
||||
|
||||
public:
|
||||
AutoScopedAssign(T *addr, const T &value JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: addr(addr), old(*addr)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
*addr = value;
|
||||
}
|
||||
|
||||
~AutoScopedAssign() { *addr = old; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class AlreadyIncRefed
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
RefCountable *obj;
|
||||
|
||||
public:
|
||||
explicit AlreadyIncRefed(RefCountable *obj) : obj(obj) {}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class NeedsIncRef
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
RefCountable *obj;
|
||||
|
||||
public:
|
||||
explicit NeedsIncRef(RefCountable *obj) : obj(obj) {}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class AutoRefCount
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
JSContext *const cx;
|
||||
RefCountable *obj;
|
||||
|
||||
AutoRefCount(const AutoRefCount &);
|
||||
void operator=(const AutoRefCount &);
|
||||
|
||||
public:
|
||||
explicit AutoRefCount(JSContext *cx)
|
||||
: cx(cx), obj(NULL)
|
||||
{}
|
||||
|
||||
AutoRefCount(JSContext *cx, NeedsIncRef<RefCountable> aobj)
|
||||
: cx(cx), obj(aobj.get())
|
||||
{
|
||||
if (obj)
|
||||
obj->incref(cx);
|
||||
}
|
||||
|
||||
AutoRefCount(JSContext *cx, AlreadyIncRefed<RefCountable> aobj)
|
||||
: cx(cx), obj(aobj.get())
|
||||
{}
|
||||
|
||||
~AutoRefCount() {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
}
|
||||
|
||||
void reset(NeedsIncRef<RefCountable> aobj) {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
obj = aobj.get();
|
||||
if (obj)
|
||||
obj->incref(cx);
|
||||
}
|
||||
|
||||
void reset(AlreadyIncRefed<RefCountable> aobj) {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
obj = aobj.get();
|
||||
}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jstl_h_ */
|
||||
#endif /* js_template_lib_h__ */
|
|
@ -0,0 +1,945 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** 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 Original Code is Mozilla SpiderMonkey JavaScript code.
|
||||
*
|
||||
* 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):
|
||||
*
|
||||
* 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 ***** */
|
||||
|
||||
#ifndef js_utility_h__
|
||||
#define js_utility_h__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/* The public JS engine namespace. */
|
||||
namespace JS {}
|
||||
|
||||
/* The mozilla-shared reusable template/utility namespace. */
|
||||
namespace mozilla {}
|
||||
|
||||
/* The private JS engine namespace. */
|
||||
namespace js {
|
||||
|
||||
/* The private namespace is a superset of the public/shared namespaces. */
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
|
||||
} /* namespace js */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Pattern used to overwrite freed memory. If you are accessing an object with
|
||||
* this pattern, you probably have a dangling pointer.
|
||||
*/
|
||||
#define JS_FREE_PATTERN 0xDA
|
||||
|
||||
/* JS_ASSERT */
|
||||
#ifdef DEBUG
|
||||
# define JS_ASSERT(expr) \
|
||||
((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
|
||||
# define JS_ASSERT_IF(cond, expr) \
|
||||
((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
|
||||
# define JS_NOT_REACHED(reason) \
|
||||
JS_Assert(reason, __FILE__, __LINE__)
|
||||
# define JS_ALWAYS_TRUE(expr) JS_ASSERT(expr)
|
||||
# define JS_ALWAYS_FALSE(expr) JS_ASSERT(!(expr))
|
||||
# ifdef JS_THREADSAFE
|
||||
# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr)
|
||||
# else
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
# endif
|
||||
#else
|
||||
# define JS_ASSERT(expr) ((void) 0)
|
||||
# define JS_ASSERT_IF(cond,expr) ((void) 0)
|
||||
# define JS_NOT_REACHED(reason)
|
||||
# define JS_ALWAYS_TRUE(expr) ((void) (expr))
|
||||
# define JS_ALWAYS_FALSE(expr) ((void) (expr))
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* JS_STATIC_ASSERT
|
||||
*
|
||||
* A compile-time assert. "cond" must be a constant expression. The macro can
|
||||
* be used only in places where an "extern" declaration is allowed.
|
||||
*/
|
||||
#ifdef __SUNPRO_CC
|
||||
/*
|
||||
* Sun Studio C++ compiler has a bug
|
||||
* "sizeof expression not accepted as size of array parameter"
|
||||
* It happens when js_static_assert() function is declared inside functions.
|
||||
* The bug number is 6688515. It is not public yet.
|
||||
* Therefore, for Sun Studio, declare js_static_assert as an array instead.
|
||||
*/
|
||||
# define JS_STATIC_ASSERT(cond) extern char js_static_assert[(cond) ? 1 : -1]
|
||||
#else
|
||||
# ifdef __COUNTER__
|
||||
# define JS_STATIC_ASSERT_GLUE1(x,y) x##y
|
||||
# define JS_STATIC_ASSERT_GLUE(x,y) JS_STATIC_ASSERT_GLUE1(x,y)
|
||||
# define JS_STATIC_ASSERT(cond) \
|
||||
typedef int JS_STATIC_ASSERT_GLUE(js_static_assert, __COUNTER__)[(cond) ? 1 : -1]
|
||||
# else
|
||||
# define JS_STATIC_ASSERT(cond) extern void js_static_assert(int arg[(cond) ? 1 : -1])
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define JS_STATIC_ASSERT_IF(cond, expr) JS_STATIC_ASSERT(!(cond) || (expr))
|
||||
|
||||
/*
|
||||
* Abort the process in a non-graceful manner. This will cause a core file,
|
||||
* call to the debugger or other moral equivalent as well as causing the
|
||||
* entire process to stop.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void) JS_Abort(void);
|
||||
|
||||
/*
|
||||
* Custom allocator support for SpiderMonkey
|
||||
*/
|
||||
#if defined JS_USE_CUSTOM_ALLOCATOR
|
||||
# include "jscustomallocator.h"
|
||||
#else
|
||||
# ifdef DEBUG
|
||||
/*
|
||||
* In order to test OOM conditions, when the shell command-line option
|
||||
* |-A NUM| is passed, we fail continuously after the NUM'th allocation.
|
||||
*/
|
||||
extern JS_PUBLIC_DATA(JSUint32) OOM_maxAllocations; /* set from shell/js.cpp */
|
||||
extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
|
||||
# define JS_OOM_POSSIBLY_FAIL() \
|
||||
do \
|
||||
{ \
|
||||
if (OOM_counter++ >= OOM_maxAllocations) { \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# else
|
||||
# define JS_OOM_POSSIBLY_FAIL() do {} while(0)
|
||||
# endif
|
||||
|
||||
/*
|
||||
* SpiderMonkey code should not be calling these allocation functions directly.
|
||||
* Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
|
||||
* However, js_free() can be called directly.
|
||||
*/
|
||||
static JS_INLINE void* js_malloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return malloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_calloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return calloc(bytes, 1);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_realloc(void* p, size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return realloc(p, bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void js_free(void* p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
#endif/* JS_USE_CUSTOM_ALLOCATOR */
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
*
|
||||
* With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129.
|
||||
*
|
||||
* SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856.
|
||||
*/
|
||||
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
|
||||
unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
|
||||
unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
|
||||
# pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward(&idx, (unsigned long)val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse(&idx, (unsigned long)val);
|
||||
return (int)(31-idx);
|
||||
}
|
||||
# define js_bitscan_ctz32(val) __BitScanForward32(val)
|
||||
# define js_bitscan_clz32(val) __BitScanReverse32(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_X64)
|
||||
unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask);
|
||||
# pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward64(&idx, val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse64(&idx, val);
|
||||
return (int)(63-idx);
|
||||
}
|
||||
# define js_bitscan_ctz64(val) __BitScanForward64(val)
|
||||
# define js_bitscan_clz64(val) __BitScanReverse64(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
#endif
|
||||
#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
|
||||
# define js_bitscan_ctz32(val) __builtin_ctz(val)
|
||||
# define js_bitscan_clz32(val) __builtin_clz(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
# if (JS_BYTES_PER_WORD == 8)
|
||||
# define js_bitscan_ctz64(val) __builtin_ctzll(val)
|
||||
# define js_bitscan_clz64(val) __builtin_clzll(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_CeilingLog2: Compute the log of the least power of
|
||||
** 2 greater than or equal to _n. The result is returned in _log2.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)).
|
||||
* The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is
|
||||
* undefined.
|
||||
*/
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
unsigned int j_ = (unsigned int)(_n); \
|
||||
(_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) & ((j_)-1)) \
|
||||
(_log2) += 1; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_FloorLog2: Compute the log of the greatest power of
|
||||
** 2 less than or equal to _n. The result is returned in _log2.
|
||||
**
|
||||
** This is equivalent to finding the highest set bit in the word.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)).
|
||||
* Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1
|
||||
* to ensure 0 result when _n == 0.
|
||||
*/
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
(_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
* a version of JS_CeilingLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size.
|
||||
*/
|
||||
#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the greatest power of 2 less than or equal to n.
|
||||
* This is a version of JS_FloorLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size and requires that n != 0.
|
||||
*/
|
||||
#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
|
||||
# else
|
||||
# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n))
|
||||
# endif
|
||||
#elif JS_BYTES_PER_WORD == 8
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN64
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
|
||||
# else
|
||||
extern size_t js_FloorLog2wImpl(size_t n);
|
||||
# endif
|
||||
#else
|
||||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
|
||||
/*
|
||||
* User guide to memory management within SpiderMonkey:
|
||||
*
|
||||
* Quick tips:
|
||||
*
|
||||
* Allocation:
|
||||
* - Prefer to allocate using JSContext:
|
||||
* cx->{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* - If no JSContext is available, use a JSRuntime:
|
||||
* rt->{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* - As a last resort, use unaccounted allocation ("OffTheBooks"):
|
||||
* js::OffTheBooks::{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* Deallocation:
|
||||
* - When the deallocation occurs on a slow path, use:
|
||||
* Foreground::{free_,delete_,array_delete}
|
||||
*
|
||||
* - Otherwise deallocate on a background thread using a JSContext:
|
||||
* cx->{free_,delete_,array_delete}
|
||||
*
|
||||
* - If no JSContext is available, use a JSRuntime:
|
||||
* rt->{free_,delete_,array_delete}
|
||||
*
|
||||
* - As a last resort, use UnwantedForeground deallocation:
|
||||
* js::UnwantedForeground::{free_,delete_,array_delete}
|
||||
*
|
||||
* General tips:
|
||||
*
|
||||
* - Mixing and matching these allocators is allowed (you may free memory
|
||||
* allocated by any allocator, with any deallocator).
|
||||
*
|
||||
* - Never, ever use normal C/C++ memory management:
|
||||
* malloc, free, new, new[], delete, operator new, etc.
|
||||
*
|
||||
* - Never, ever use low-level SpiderMonkey allocators:
|
||||
* js_malloc(), js_free(), js_calloc(), js_realloc()
|
||||
* Their use is reserved for the other memory managers.
|
||||
*
|
||||
* - Classes which have private constructors or destructors should have
|
||||
* JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR added to their
|
||||
* declaration.
|
||||
*
|
||||
* Details:
|
||||
*
|
||||
* Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on
|
||||
* failure instead of returning NULL, which is what SpiderMonkey expects.
|
||||
* (Even overriding them is unsafe, as the system's C++ runtime library may
|
||||
* throw, which we do not support. We also can't just use the 'nothrow'
|
||||
* variant of new/new[], because we want to mediate *all* allocations
|
||||
* within SpiderMonkey, to satisfy any embedders using
|
||||
* JS_USE_CUSTOM_ALLOCATOR.)
|
||||
*
|
||||
* JSContexts and JSRuntimes keep track of memory allocated, and use this
|
||||
* accounting to schedule GC. OffTheBooks does not. We'd like to remove
|
||||
* OffTheBooks allocations as much as possible (bug 636558).
|
||||
*
|
||||
* On allocation failure, a JSContext correctly reports an error, which a
|
||||
* JSRuntime and OffTheBooks does not.
|
||||
*
|
||||
* A JSContext deallocates in a background thread. A JSRuntime might
|
||||
* deallocate in the background in the future, but does not now. Foreground
|
||||
* deallocation is preferable on slow paths. UnwantedForeground deallocations
|
||||
* occur where we have no JSContext or JSRuntime, and the deallocation is not
|
||||
* on a slow path. We want to remove UnwantedForeground deallocations (bug
|
||||
* 636561).
|
||||
*
|
||||
* JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR makes the allocation
|
||||
* classes friends with your class, giving them access to private
|
||||
* constructors and destructors.
|
||||
*
|
||||
* |make check| does a source level check on the number of uses OffTheBooks,
|
||||
* UnwantedForeground, js_malloc, js_free etc, to prevent regressions. If you
|
||||
* really must add one, update Makefile.in, and run |make check|.
|
||||
*
|
||||
* |make check| also statically prevents the use of vanilla new/new[].
|
||||
*/
|
||||
|
||||
#define JS_NEW_BODY(allocator, t, parms) \
|
||||
void *memory = allocator(sizeof(t)); \
|
||||
return memory ? new(memory) t parms : NULL;
|
||||
|
||||
/*
|
||||
* Given a class which should provide new_() methods, add
|
||||
* JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
|
||||
* adds new_()s with up to 12 parameters. Add more versions of new_ below if
|
||||
* you need more than 12 parameters.
|
||||
*
|
||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
|
||||
* or the build will break.
|
||||
*/
|
||||
#define JS_DECLARE_NEW_METHODS(ALLOCATOR, QUALIFIERS)\
|
||||
template <class T>\
|
||||
QUALIFIERS T *new_() {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, ())\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1>\
|
||||
QUALIFIERS T *new_(P1 p1) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12))\
|
||||
}\
|
||||
static const int JSMinAlignment = 8;\
|
||||
template <class T>\
|
||||
QUALIFIERS T *array_new(size_t n) {\
|
||||
/* The length is stored just before the vector memory. */\
|
||||
uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);\
|
||||
size_t numBytes = size_t(numBytes64);\
|
||||
if (numBytes64 != numBytes) {\
|
||||
JS_ASSERT(0); /* we want to know if this happens in debug builds */\
|
||||
return NULL;\
|
||||
}\
|
||||
void *memory = ALLOCATOR(numBytes);\
|
||||
if (!memory)\
|
||||
return NULL;\
|
||||
*(size_t *)memory = n;\
|
||||
memory = (void*)(uintptr_t(memory) + JSMinAlignment);\
|
||||
return new(memory) T[n];\
|
||||
}\
|
||||
|
||||
|
||||
#define JS_DECLARE_DELETE_METHODS(DEALLOCATOR, QUALIFIERS)\
|
||||
template <class T>\
|
||||
QUALIFIERS void delete_(T *p) {\
|
||||
if (p) {\
|
||||
p->~T();\
|
||||
DEALLOCATOR(p);\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
template <class T>\
|
||||
QUALIFIERS void array_delete(T *p) {\
|
||||
if (p) {\
|
||||
void* p0 = (void *)(uintptr_t(p) - js::OffTheBooks::JSMinAlignment);\
|
||||
size_t n = *(size_t *)p0;\
|
||||
for (size_t i = 0; i < n; i++)\
|
||||
(p + i)->~T();\
|
||||
DEALLOCATOR(p0);\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In general, all allocations should go through a JSContext or JSRuntime, so
|
||||
* that the garbage collector knows how much memory has been allocated. In
|
||||
* cases where it is difficult to use a JSContext or JSRuntime, OffTheBooks can
|
||||
* be used, though this is undesirable.
|
||||
*/
|
||||
namespace js {
|
||||
|
||||
class OffTheBooks {
|
||||
public:
|
||||
JS_DECLARE_NEW_METHODS(::js_malloc, JS_ALWAYS_INLINE static)
|
||||
|
||||
static JS_INLINE void* malloc_(size_t bytes) {
|
||||
return ::js_malloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* calloc_(size_t bytes) {
|
||||
return ::js_calloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* realloc_(void* p, size_t bytes) {
|
||||
return ::js_realloc(p, bytes);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* We generally prefer deallocating using JSContext because it can happen in
|
||||
* the background. On slow paths, we may prefer foreground allocation.
|
||||
*/
|
||||
class Foreground {
|
||||
public:
|
||||
/* See parentheses comment above. */
|
||||
static JS_ALWAYS_INLINE void free_(void* p) {
|
||||
::js_free(p);
|
||||
}
|
||||
|
||||
JS_DECLARE_DELETE_METHODS(::js_free, JS_ALWAYS_INLINE static)
|
||||
};
|
||||
|
||||
class UnwantedForeground : public Foreground {
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Note lack of ; in JSRuntime below. This is intentional so "calling" this
|
||||
* looks "normal".
|
||||
*/
|
||||
#define JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR \
|
||||
friend class js::OffTheBooks;\
|
||||
friend class js::Foreground;\
|
||||
friend class js::UnwantedForeground;\
|
||||
friend struct ::JSContext;\
|
||||
friend struct ::JSRuntime
|
||||
|
||||
/*
|
||||
* The following classes are designed to cause assertions to detect
|
||||
* inadvertent use of guard objects as temporaries. In other words,
|
||||
* when we have a guard object whose only purpose is its constructor and
|
||||
* destructor (and is never otherwise referenced), the intended use
|
||||
* might be:
|
||||
* JSAutoTempValueRooter tvr(cx, 1, &val);
|
||||
* but is is easy to accidentally write:
|
||||
* JSAutoTempValueRooter(cx, 1, &val);
|
||||
* which compiles just fine, but runs the destructor well before the
|
||||
* intended time.
|
||||
*
|
||||
* They work by adding (#ifdef DEBUG) an additional parameter to the
|
||||
* guard object's constructor, with a default value, so that users of
|
||||
* the guard object's API do not need to do anything. The default value
|
||||
* of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
|
||||
* section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
|
||||
* guarantee that temporaries are destroyed in the reverse of their
|
||||
* construction order, but I actually can't find a statement that that
|
||||
* is true in the general case (beyond the two specific cases mentioned
|
||||
* there). However, it seems to be true.
|
||||
*
|
||||
* These classes are intended to be used only via the macros immediately
|
||||
* below them:
|
||||
* JS_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
|
||||
* variable, and should be put where a declaration of a private
|
||||
* member variable would be placed.
|
||||
* JS_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
|
||||
* parameters to each constructor of the guard object; it declares
|
||||
* (ifdef DEBUG) an additional parameter.
|
||||
* JS_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
|
||||
* constructor. It uses the parameter declared by
|
||||
* JS_GUARD_OBJECT_NOTIFIER_PARAM.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
class JS_FRIEND_API(JSGuardObjectNotifier)
|
||||
{
|
||||
private:
|
||||
bool* mStatementDone;
|
||||
public:
|
||||
JSGuardObjectNotifier() : mStatementDone(NULL) {}
|
||||
|
||||
~JSGuardObjectNotifier() {
|
||||
*mStatementDone = true;
|
||||
}
|
||||
|
||||
void setStatementDone(bool *aStatementDone) {
|
||||
mStatementDone = aStatementDone;
|
||||
}
|
||||
};
|
||||
|
||||
class JS_FRIEND_API(JSGuardObjectNotificationReceiver)
|
||||
{
|
||||
private:
|
||||
bool mStatementDone;
|
||||
public:
|
||||
JSGuardObjectNotificationReceiver() : mStatementDone(false) {}
|
||||
|
||||
~JSGuardObjectNotificationReceiver() {
|
||||
/*
|
||||
* Assert that the guard object was not used as a temporary.
|
||||
* (Note that this assert might also fire if Init is not called
|
||||
* because the guard object's implementation is not using the
|
||||
* above macros correctly.)
|
||||
*/
|
||||
JS_ASSERT(mStatementDone);
|
||||
}
|
||||
|
||||
void Init(const JSGuardObjectNotifier &aNotifier) {
|
||||
/*
|
||||
* aNotifier is passed as a const reference so that we can pass a
|
||||
* temporary, but we really intend it as non-const
|
||||
*/
|
||||
const_cast<JSGuardObjectNotifier&>(aNotifier).
|
||||
setStatementDone(&mStatementDone);
|
||||
}
|
||||
};
|
||||
|
||||
#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER \
|
||||
JSGuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM \
|
||||
, const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier()
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT \
|
||||
, const JSGuardObjectNotifier& _notifier
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 \
|
||||
const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier()
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_INIT \
|
||||
JS_BEGIN_MACRO _mCheckNotUsedAsTemporary.Init(_notifier); JS_END_MACRO
|
||||
|
||||
#else /* defined(DEBUG) */
|
||||
|
||||
#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM0
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_INIT JS_BEGIN_MACRO JS_END_MACRO
|
||||
|
||||
#endif /* !defined(DEBUG) */
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* "Move" References
|
||||
*
|
||||
* Some types can be copied much more efficiently if we know the original's
|
||||
* value need not be preserved --- that is, if we are doing a "move", not a
|
||||
* "copy". For example, if we have:
|
||||
*
|
||||
* Vector<T> u;
|
||||
* Vector<T> v(u);
|
||||
*
|
||||
* the constructor for v must apply a copy constructor to each element of u ---
|
||||
* taking time linear in the length of u. However, if we know we will not need u
|
||||
* any more once v has been initialized, then we could initialize v very
|
||||
* efficiently simply by stealing u's dynamically allocated buffer and giving it
|
||||
* to v --- a constant-time operation, regardless of the size of u.
|
||||
*
|
||||
* Moves often appear in container implementations. For example, when we append
|
||||
* to a vector, we may need to resize its buffer. This entails moving each of
|
||||
* its extant elements from the old, smaller buffer to the new, larger buffer.
|
||||
* But once the elements have been migrated, we're just going to throw away the
|
||||
* old buffer; we don't care if they still have their values. So if the vector's
|
||||
* element type can implement "move" more efficiently than "copy", the vector
|
||||
* resizing should by all means use a "move" operation. Hash tables also need to
|
||||
* be resized.
|
||||
*
|
||||
* The details of the optimization, and whether it's worth applying, vary from
|
||||
* one type to the next. And while some constructor calls are moves, many really
|
||||
* are copies, and can't be optimized this way. So we need:
|
||||
*
|
||||
* 1) a way for a particular invocation of a copy constructor to say that it's
|
||||
* really a move, and that the value of the original isn't important
|
||||
* afterwards (althought it must still be safe to destroy); and
|
||||
*
|
||||
* 2) a way for a type (like Vector) to announce that it can be moved more
|
||||
* efficiently than it can be copied, and provide an implementation of that
|
||||
* move operation.
|
||||
*
|
||||
* The Move(T &) function takes a reference to a T, and returns an MoveRef<T>
|
||||
* referring to the same value; that's 1). An MoveRef<T> is simply a reference
|
||||
* to a T, annotated to say that a copy constructor applied to it may move that
|
||||
* T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
|
||||
* should perform a more efficient move, instead of a copy, providing 2).
|
||||
*
|
||||
* So, where we might define a copy constructor for a class C like this:
|
||||
*
|
||||
* C(const C &rhs) { ... copy rhs to this ... }
|
||||
*
|
||||
* we would declare a move constructor like this:
|
||||
*
|
||||
* C(MoveRef<C> rhs) { ... move rhs to this ... }
|
||||
*
|
||||
* And where we might perform a copy like this:
|
||||
*
|
||||
* C c2(c1);
|
||||
*
|
||||
* we would perform a move like this:
|
||||
*
|
||||
* C c2(Move(c1))
|
||||
*
|
||||
* Note that MoveRef<T> implicitly converts to T &, so you can pass an
|
||||
* MoveRef<T> to an ordinary copy constructor for a type that doesn't support a
|
||||
* special move constructor, and you'll just get a copy. This means that
|
||||
* templates can use Move whenever they know they won't use the original value
|
||||
* any more, even if they're not sure whether the type at hand has a specialized
|
||||
* move constructor. If it doesn't, the MoveRef<T> will just convert to a T &,
|
||||
* and the ordinary copy constructor will apply.
|
||||
*
|
||||
* A class with a move constructor can also provide a move assignment operator,
|
||||
* which runs this's destructor, and then applies the move constructor to
|
||||
* *this's memory. A typical definition:
|
||||
*
|
||||
* C &operator=(MoveRef<C> rhs) {
|
||||
* this->~C();
|
||||
* new(this) C(rhs);
|
||||
* return *this;
|
||||
* }
|
||||
*
|
||||
* With that in place, one can write move assignments like this:
|
||||
*
|
||||
* c2 = Move(c1);
|
||||
*
|
||||
* This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
|
||||
* destructible state.
|
||||
*
|
||||
* This header file defines MoveRef and Move in the js namespace. It's up to
|
||||
* individual containers to annotate moves as such, by calling Move; and it's up
|
||||
* to individual types to define move constructors.
|
||||
*
|
||||
* One hint: if you're writing a move constructor where the type has members
|
||||
* that should be moved themselves, it's much nicer to write this:
|
||||
*
|
||||
* C(MoveRef<C> c) : x(c->x), y(c->y) { }
|
||||
*
|
||||
* than the equivalent:
|
||||
*
|
||||
* C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
|
||||
*
|
||||
* especially since GNU C++ fails to notice that this does indeed initialize x
|
||||
* and y, which may matter if they're const.
|
||||
*/
|
||||
template<typename T>
|
||||
class MoveRef {
|
||||
public:
|
||||
typedef T Referent;
|
||||
explicit MoveRef(T &t) : pointer(&t) { }
|
||||
T &operator*() const { return *pointer; }
|
||||
T *operator->() const { return pointer; }
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
/*
|
||||
* If MoveRef is used in a rvalue position (which is expected), we can
|
||||
* end up in a situation where, without this ifdef, we would try to pass
|
||||
* a T& to a move constructor, which fails. It is not clear if the compiler
|
||||
* should instead use the copy constructor, but for now this lets us build
|
||||
* with clang. See bug 689066 and llvm.org/pr11003 for the details.
|
||||
* Note: We can probably remove MoveRef completely once we are comfortable
|
||||
* using c++11.
|
||||
*/
|
||||
operator T&& () const { return static_cast<T&&>(*pointer); }
|
||||
#else
|
||||
operator T& () const { return *pointer; }
|
||||
#endif
|
||||
private:
|
||||
T *pointer;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
MoveRef<T> Move(T &t) { return MoveRef<T>(t); }
|
||||
|
||||
template<typename T>
|
||||
MoveRef<T> Move(const T &t) { return MoveRef<T>(const_cast<T &>(t)); }
|
||||
|
||||
/* Useful for implementing containers that assert non-reentrancy */
|
||||
class ReentrancyGuard
|
||||
{
|
||||
/* ReentrancyGuard is not copyable. */
|
||||
ReentrancyGuard(const ReentrancyGuard &);
|
||||
void operator=(const ReentrancyGuard &);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool &entered;
|
||||
#endif
|
||||
public:
|
||||
template <class T>
|
||||
#ifdef DEBUG
|
||||
ReentrancyGuard(T &obj)
|
||||
: entered(obj.entered)
|
||||
#else
|
||||
ReentrancyGuard(T &/*obj*/)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!entered);
|
||||
entered = true;
|
||||
#endif
|
||||
}
|
||||
~ReentrancyGuard()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
entered = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Round x up to the nearest power of 2. This function assumes that the most
|
||||
* significant bit of x is not set, which would lead to overflow.
|
||||
*/
|
||||
JS_ALWAYS_INLINE size_t
|
||||
RoundUpPow2(size_t x)
|
||||
{
|
||||
return size_t(1) << JS_CEILING_LOG2W(x);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
/*
|
||||
* This signature is for malloc_usable_size-like functions used to measure
|
||||
* memory usage. A return value of zero indicates that the size is unknown,
|
||||
* and so a fall-back computation should be done for the size.
|
||||
*/
|
||||
typedef size_t(*JSUsableSizeFun)(void *p);
|
||||
|
||||
/* sixgill annotation defines */
|
||||
#ifndef HAVE_STATIC_ANNOTATIONS
|
||||
# define HAVE_STATIC_ANNOTATIONS
|
||||
# ifdef XGILL_PLUGIN
|
||||
# define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
|
||||
# define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
|
||||
# define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
|
||||
# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
|
||||
# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
|
||||
# define STATIC_PASTE2(X,Y) X ## Y
|
||||
# define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
|
||||
# define STATIC_ASSERT(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assume_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assume_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static_runtime(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# else /* XGILL_PLUGIN */
|
||||
# define STATIC_PRECONDITION(COND) /* nothing */
|
||||
# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
|
||||
# define STATIC_POSTCONDITION(COND) /* nothing */
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
|
||||
# define STATIC_INVARIANT(COND) /* nothing */
|
||||
# define STATIC_INVARIANT_ASSUME(COND) /* nothing */
|
||||
# define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# endif /* XGILL_PLUGIN */
|
||||
# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
|
||||
#endif /* HAVE_STATIC_ANNOTATIONS */
|
||||
|
||||
#endif /* js_utility_h__ */
|
|
@ -41,10 +41,8 @@
|
|||
#ifndef jsvector_h_
|
||||
#define jsvector_h_
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsutil.h"
|
||||
#include "TemplateLib.h"
|
||||
#include "Utility.h"
|
||||
|
||||
/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
|
||||
#ifdef _MSC_VER
|
||||
|
@ -54,6 +52,9 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
template <class T, size_t N, class AllocPolicy>
|
||||
class Vector;
|
||||
|
||||
/*
|
||||
* This template class provides a default implementation for vector operations
|
||||
* when the element type is not known to be a POD, as judged by IsPodType.
|
|
@ -95,7 +95,14 @@ endif
|
|||
FORCE_STATIC_LIB = 1
|
||||
DIST_INSTALL = 1
|
||||
|
||||
VPATH = $(srcdir)
|
||||
VPATH = \
|
||||
$(srcdir) \
|
||||
$(srcdir)/builtin \
|
||||
$(srcdir)/ds \
|
||||
$(srcdir)/frontend \
|
||||
$(srcdir)/gc \
|
||||
$(srcdir)/vm \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
jsalloc.cpp \
|
||||
|
@ -163,6 +170,7 @@ CPPSRCS = \
|
|||
RegExpObject.cpp \
|
||||
RegExpStatics.cpp \
|
||||
RegExp.cpp \
|
||||
Statistics.cpp \
|
||||
Unicode.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -177,7 +185,6 @@ INSTALLED_HEADERS = \
|
|||
jsalloc.h \
|
||||
jsapi.h \
|
||||
jsatom.h \
|
||||
jsbit.h \
|
||||
jsclass.h \
|
||||
jsclist.h \
|
||||
jsclone.h \
|
||||
|
@ -202,7 +209,6 @@ INSTALLED_HEADERS = \
|
|||
jsotypes.h \
|
||||
jsproxy.h \
|
||||
jsprf.h \
|
||||
jsprobes.h \
|
||||
jspropertycache.h \
|
||||
jspropertytree.h \
|
||||
jsproto.tbl \
|
||||
|
@ -217,9 +223,6 @@ INSTALLED_HEADERS = \
|
|||
jstypedarray.h \
|
||||
jstypes.h \
|
||||
jsutil.h \
|
||||
jsvector.h \
|
||||
jstl.h \
|
||||
jshashtable.h \
|
||||
jsversion.h \
|
||||
jswrapper.h \
|
||||
jsxdrapi.h \
|
||||
|
@ -228,16 +231,10 @@ INSTALLED_HEADERS = \
|
|||
$(NULL)
|
||||
|
||||
######################################################
|
||||
# BEGIN include sources for the engine subdirectories
|
||||
# BEGIN exported headers that are only exported
|
||||
# because of inclusion by an INSTALLED_HEADER
|
||||
#
|
||||
VPATH += \
|
||||
$(srcdir)/builtin \
|
||||
$(srcdir)/ds \
|
||||
$(srcdir)/frontend \
|
||||
$(srcdir)/vm \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = vm ds
|
||||
EXPORTS_NAMESPACES += vm ds gc
|
||||
|
||||
EXPORTS_vm = \
|
||||
String.h \
|
||||
|
@ -246,7 +243,32 @@ EXPORTS_vm = \
|
|||
$(NULL)
|
||||
|
||||
EXPORTS_ds = \
|
||||
LifoAlloc.h
|
||||
LifoAlloc.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_gc = \
|
||||
Statistics.h \
|
||||
$(NULL)
|
||||
|
||||
######################################################
|
||||
# BEGIN include exported headers from the JS engine
|
||||
#
|
||||
# Ultimately, after cleansing INSTALLED_HEADERS,
|
||||
# these will be the ONLY headers exported by
|
||||
# the js engine
|
||||
#
|
||||
VPATH += \
|
||||
$(srcdir)/../public \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES += js
|
||||
|
||||
EXPORTS_js = \
|
||||
HashTable.h \
|
||||
TemplateLib.h \
|
||||
Utility.h \
|
||||
Vector.h \
|
||||
$(NULL)
|
||||
|
||||
###############################################
|
||||
# BEGIN include sources for low-level code shared with Gecko
|
||||
|
@ -259,9 +281,9 @@ EXPORTS_NAMESPACES += mozilla
|
|||
|
||||
EXPORTS_mozilla = \
|
||||
RangedPtr.h \
|
||||
RefPtr.h \
|
||||
Types.h \
|
||||
Util.h \
|
||||
RefPtr.h \
|
||||
Types.h \
|
||||
Util.h \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TRACEJIT
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "AssemblerBuffer.h"
|
||||
#include "jsstdint.h"
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include "methodjit/Logging.h"
|
||||
#define IPFX " %s"
|
||||
|
|
|
@ -28,13 +28,14 @@
|
|||
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
#include <limits>
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#if WTF_CPU_SPARC
|
||||
#ifdef linux // bugzilla 502369
|
||||
|
@ -165,10 +166,12 @@ private:
|
|||
};
|
||||
|
||||
class ExecutableAllocator {
|
||||
typedef void (*DestroyCallback)(void* addr, size_t size);
|
||||
enum ProtectionSetting { Writable, Executable };
|
||||
DestroyCallback destroyCallback;
|
||||
|
||||
public:
|
||||
ExecutableAllocator()
|
||||
ExecutableAllocator() : destroyCallback(NULL)
|
||||
{
|
||||
if (!pageSize) {
|
||||
pageSize = determinePageSize();
|
||||
|
@ -221,12 +224,18 @@ public:
|
|||
|
||||
void releasePoolPages(ExecutablePool *pool) {
|
||||
JS_ASSERT(pool->m_allocation.pages);
|
||||
if (destroyCallback)
|
||||
destroyCallback(pool->m_allocation.pages, pool->m_allocation.size);
|
||||
systemRelease(pool->m_allocation);
|
||||
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
|
||||
}
|
||||
|
||||
void getCodeStats(size_t& method, size_t& regexp, size_t& unused) const;
|
||||
|
||||
void setDestroyCallback(DestroyCallback destroyCallback) {
|
||||
this->destroyCallback = destroyCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t pageSize;
|
||||
static size_t largeAllocSize;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#define SegmentedVector_h
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace WTF {
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsinfer.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "builtin/RegExp.h"
|
||||
|
||||
|
|
|
@ -4420,28 +4420,6 @@ if test -n "$MOZ_TRACEVIS"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use GCTimer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(gctimer,
|
||||
[ --enable-gctimer Enable GC timer (default=no)],
|
||||
MOZ_GCTIMER=1,
|
||||
MOZ_GCTIMER= )
|
||||
if test -n "$MOZ_GCTIMER"; then
|
||||
AC_DEFINE(MOZ_GCTIMER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Don't enable GC-TestPilot plumbing
|
||||
dnl ========================================================
|
||||
JSGC_TESTPILOT=1
|
||||
MOZ_ARG_DISABLE_BOOL(gctestpilot,
|
||||
[ --disable-gctestpilot Disable GC TestPilot study hooks],
|
||||
JSGC_TESTPILOT= )
|
||||
if test -n "$JSGC_TESTPILOT"; then
|
||||
AC_DEFINE(JSGC_TESTPILOT)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use Valgrind
|
||||
dnl ========================================================
|
||||
|
@ -4658,6 +4636,23 @@ if test -z "$SKIP_LIBRARY_CHECKS"; then
|
|||
AC_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace))
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl JIT observers
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_WITH_STRING(jitreport-granularity,
|
||||
[ --jitreport-granularity=N
|
||||
Default granularity at which to report JIT code
|
||||
to external tools
|
||||
0 - no info
|
||||
1 - code ranges for whole functions only
|
||||
2 - per-line information
|
||||
3 - per-op information],
|
||||
JITREPORT_GRANULARITY=$withval,
|
||||
JITREPORT_GRANULARITY=3)
|
||||
|
||||
AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY)
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Misc. Options
|
||||
|
|
|
@ -41,10 +41,11 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "prlink.h"
|
||||
#include "ffi.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
namespace ctypes {
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#ifndef InlineMap_h__
|
||||
#define InlineMap_h__
|
||||
|
||||
#include "jshashtable.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
|
|
@ -65,6 +65,30 @@ BumpChunk::new_(size_t chunkSize)
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
BumpChunk::delete_(BumpChunk *chunk)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize);
|
||||
#endif
|
||||
js_free(chunk);
|
||||
}
|
||||
|
||||
bool
|
||||
BumpChunk::canAlloc(size_t n)
|
||||
{
|
||||
char *aligned = AlignPtr(bump);
|
||||
char *bumped = aligned + n;
|
||||
return bumped <= limit && bumped > headerBase();
|
||||
}
|
||||
|
||||
bool
|
||||
BumpChunk::canAllocUnaligned(size_t n)
|
||||
{
|
||||
char *bumped = bump + n;
|
||||
return bumped <= limit && bumped > headerBase();
|
||||
}
|
||||
|
||||
void *
|
||||
BumpChunk::tryAllocUnaligned(size_t n)
|
||||
{
|
||||
|
@ -73,6 +97,7 @@ BumpChunk::tryAllocUnaligned(size_t n)
|
|||
if (newBump > limit)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(canAllocUnaligned(n));
|
||||
setBump(newBump);
|
||||
return oldBump;
|
||||
}
|
||||
|
@ -136,9 +161,20 @@ LifoAlloc::getOrCreateChunk(size_t n)
|
|||
}
|
||||
|
||||
size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk);
|
||||
size_t chunkSize = n > defaultChunkFreeSpace
|
||||
? RoundUpPow2(n + sizeof(BumpChunk))
|
||||
: defaultChunkSize_;
|
||||
size_t chunkSize;
|
||||
if (n > defaultChunkFreeSpace) {
|
||||
size_t allocSizeWithHeader = n + sizeof(BumpChunk);
|
||||
|
||||
/* Guard for overflow. */
|
||||
if (allocSizeWithHeader < n ||
|
||||
(allocSizeWithHeader & (size_t(1) << (tl::BitSize<size_t>::result - 1)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunkSize = RoundUpPow2(allocSizeWithHeader);
|
||||
} else {
|
||||
chunkSize = defaultChunkSize_;
|
||||
}
|
||||
|
||||
/* If we get here, we couldn't find an existing BumpChunk to fill the request. */
|
||||
BumpChunk *newChunk = BumpChunk::new_(chunkSize);
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
*/
|
||||
|
||||
#include "jsutil.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "js/TemplateLib.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -78,7 +79,8 @@ class BumpChunk
|
|||
BumpChunk *next_;
|
||||
size_t bumpSpaceSize;
|
||||
|
||||
char *base() const { return limit - bumpSpaceSize; }
|
||||
char *headerBase() { return reinterpret_cast<char *>(this); }
|
||||
char *bumpBase() const { return limit - bumpSpaceSize; }
|
||||
|
||||
BumpChunk *thisDuringConstruction() { return this; }
|
||||
|
||||
|
@ -97,7 +99,7 @@ class BumpChunk
|
|||
}
|
||||
|
||||
void setBump(void *ptr) {
|
||||
JS_ASSERT(base() <= ptr);
|
||||
JS_ASSERT(bumpBase() <= ptr);
|
||||
JS_ASSERT(ptr <= limit);
|
||||
DebugOnly<char *> prevBump = bump;
|
||||
bump = static_cast<char *>(ptr);
|
||||
|
@ -109,10 +111,10 @@ class BumpChunk
|
|||
BumpChunk *next() const { return next_; }
|
||||
void setNext(BumpChunk *succ) { next_ = succ; }
|
||||
|
||||
size_t used() const { return bump - base(); }
|
||||
size_t used() const { return bump - bumpBase(); }
|
||||
|
||||
void resetBump() {
|
||||
setBump(reinterpret_cast<char *>(this) + sizeof(BumpChunk));
|
||||
setBump(headerBase() + sizeof(BumpChunk));
|
||||
}
|
||||
|
||||
void *mark() const { return bump; }
|
||||
|
@ -124,25 +126,26 @@ class BumpChunk
|
|||
}
|
||||
|
||||
bool contains(void *mark) const {
|
||||
return base() <= mark && mark <= limit;
|
||||
return bumpBase() <= mark && mark <= limit;
|
||||
}
|
||||
|
||||
bool canAlloc(size_t n) {
|
||||
return AlignPtr(bump) + n <= limit;
|
||||
}
|
||||
|
||||
bool canAllocUnaligned(size_t n) {
|
||||
return bump + n <= limit;
|
||||
}
|
||||
bool canAlloc(size_t n);
|
||||
bool canAllocUnaligned(size_t n);
|
||||
|
||||
/* Try to perform an allocation of size |n|, return null if not possible. */
|
||||
JS_ALWAYS_INLINE
|
||||
void *tryAlloc(size_t n) {
|
||||
char *aligned = AlignPtr(bump);
|
||||
char *newBump = aligned + n;
|
||||
|
||||
if (newBump > limit)
|
||||
return NULL;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (JS_UNLIKELY(newBump < bump))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(canAlloc(n)); /* Ensure consistency between "can" and "try". */
|
||||
setBump(newBump);
|
||||
return aligned;
|
||||
}
|
||||
|
@ -156,13 +159,7 @@ class BumpChunk
|
|||
}
|
||||
|
||||
static BumpChunk *new_(size_t chunkSize);
|
||||
|
||||
static void delete_(BumpChunk *chunk) {
|
||||
#ifdef DEBUG
|
||||
memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize);
|
||||
#endif
|
||||
js_free(chunk);
|
||||
}
|
||||
static void delete_(BumpChunk *chunk);
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
|
|
@ -41,9 +41,8 @@
|
|||
#ifndef ParseMaps_h__
|
||||
#define ParseMaps_h__
|
||||
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "mfbt/InlineMap.h"
|
||||
#include "ds/InlineMap.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** 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 Original Code is SpiderMonkey JavaScript engine.
|
||||
*
|
||||
* 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):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsprobes.h"
|
||||
#include "jsutil.h"
|
||||
#include "jscrashformat.h"
|
||||
#include "jscrashreport.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "gc/Statistics.h"
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
Statistics::Statistics(JSRuntime *rt)
|
||||
: runtime(rt)
|
||||
{
|
||||
char *env = getenv("MOZ_GCTIMER");
|
||||
if (!env || strcmp(env, "none") == 0) {
|
||||
fp = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(env, "stdout") == 0) {
|
||||
fullFormat = false;
|
||||
fp = stdout;
|
||||
} else if (strcmp(env, "stderr") == 0) {
|
||||
fullFormat = false;
|
||||
fp = stderr;
|
||||
} else {
|
||||
fullFormat = true;
|
||||
|
||||
fp = fopen(env, "a");
|
||||
JS_ASSERT(fp);
|
||||
|
||||
fprintf(fp, " AppTime, Total, Wait, Mark, Sweep, FinObj,"
|
||||
" FinStr, FinScr, FinShp, Destry, End, +Chu, -Chu, T, Reason\n");
|
||||
}
|
||||
|
||||
PodArrayZero(counts);
|
||||
|
||||
startupTime = PRMJ_Now();
|
||||
}
|
||||
|
||||
Statistics::~Statistics()
|
||||
{
|
||||
if (fp && fp != stdout && fp != stderr)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
struct GCCrashData
|
||||
{
|
||||
int isRegen;
|
||||
int isCompartment;
|
||||
};
|
||||
|
||||
void
|
||||
Statistics::beginGC(JSCompartment *comp, Reason reason)
|
||||
{
|
||||
compartment = comp;
|
||||
|
||||
PodArrayZero(phaseStarts);
|
||||
PodArrayZero(phaseEnds);
|
||||
PodArrayZero(phaseTimes);
|
||||
|
||||
triggerReason = reason;
|
||||
|
||||
beginPhase(PHASE_GC);
|
||||
Probes::GCStart(compartment);
|
||||
|
||||
GCCrashData crashData;
|
||||
crashData.isRegen = runtime->shapeGen & SHAPE_OVERFLOW_BIT;
|
||||
crashData.isCompartment = !!compartment;
|
||||
crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::t(Phase phase)
|
||||
{
|
||||
return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::beginDelay(Phase phase1, Phase phase2)
|
||||
{
|
||||
return double(phaseStarts[phase1] - phaseStarts[phase2]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::endDelay(Phase phase1, Phase phase2)
|
||||
{
|
||||
return double(phaseEnds[phase1] - phaseEnds[phase2]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::printStats()
|
||||
{
|
||||
if (fullFormat) {
|
||||
/* App , Total, Wait , Mark , Sweep, FinOb, FinSt, FinSc, FinSh, Destry, End */
|
||||
fprintf(fp,
|
||||
"%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, ",
|
||||
double(phaseStarts[PHASE_GC] - startupTime) / PRMJ_USEC_PER_MSEC,
|
||||
t(PHASE_GC),
|
||||
beginDelay(PHASE_MARK, PHASE_GC),
|
||||
t(PHASE_MARK), t(PHASE_SWEEP),
|
||||
t(PHASE_SWEEP_OBJECT), t(PHASE_SWEEP_STRING),
|
||||
t(PHASE_SWEEP_SCRIPT), t(PHASE_SWEEP_SHAPE),
|
||||
t(PHASE_DESTROY),
|
||||
endDelay(PHASE_GC, PHASE_DESTROY));
|
||||
|
||||
fprintf(fp, "%4d, %4d,", counts[STAT_NEW_CHUNK], counts[STAT_DESTROY_CHUNK]);
|
||||
fprintf(fp, " %s, %s\n", compartment ? "C" : "G", ExplainReason(triggerReason));
|
||||
} else {
|
||||
fprintf(fp, "%f %f %f\n",
|
||||
t(PHASE_GC), t(PHASE_MARK), t(PHASE_SWEEP));
|
||||
}
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endGC()
|
||||
{
|
||||
Probes::GCEnd(compartment);
|
||||
endPhase(PHASE_GC);
|
||||
crash::SnapshotGCStack();
|
||||
|
||||
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
|
||||
(*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
|
||||
(*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
|
||||
(*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN,
|
||||
runtime->shapeGen & SHAPE_OVERFLOW_BIT ? 1 : 0);
|
||||
(*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
|
||||
(*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
|
||||
(*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
|
||||
}
|
||||
|
||||
if (fp)
|
||||
printStats();
|
||||
|
||||
PodArrayZero(counts);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::beginPhase(Phase phase)
|
||||
{
|
||||
phaseStarts[phase] = PRMJ_Now();
|
||||
|
||||
if (phase == gcstats::PHASE_SWEEP) {
|
||||
Probes::GCStartSweepPhase(NULL);
|
||||
if (!compartment) {
|
||||
for (JSCompartment **c = runtime->compartments.begin();
|
||||
c != runtime->compartments.end(); ++c)
|
||||
{
|
||||
Probes::GCStartSweepPhase(*c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endPhase(Phase phase)
|
||||
{
|
||||
phaseEnds[phase] = PRMJ_Now();
|
||||
phaseTimes[phase] += phaseEnds[phase] - phaseStarts[phase];
|
||||
|
||||
if (phase == gcstats::PHASE_SWEEP) {
|
||||
if (!compartment) {
|
||||
for (JSCompartment **c = runtime->compartments.begin();
|
||||
c != runtime->compartments.end(); ++c)
|
||||
{
|
||||
Probes::GCEndSweepPhase(*c);
|
||||
}
|
||||
}
|
||||
Probes::GCEndSweepPhase(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** 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 Original Code is SpiderMonkey JavaScript engine.
|
||||
*
|
||||
* 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):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
#ifndef jsgc_statistics_h___
|
||||
#define jsgc_statistics_h___
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
enum Reason {
|
||||
PUBLIC_API,
|
||||
MAYBEGC,
|
||||
LASTCONTEXT,
|
||||
DESTROYCONTEXT,
|
||||
LASTDITCH,
|
||||
TOOMUCHMALLOC,
|
||||
ALLOCTRIGGER,
|
||||
CHUNK,
|
||||
SHAPE,
|
||||
REFILL
|
||||
};
|
||||
static const int NUM_REASONS = REFILL + 1;
|
||||
|
||||
static inline const char *
|
||||
ExplainReason(Reason r)
|
||||
{
|
||||
static const char *strs[] = {" API", "Maybe", "LastC", "DestC", "LastD",
|
||||
"Mallc", "Alloc", "Chunk", "Shape", "Refil"};
|
||||
|
||||
JS_ASSERT(strcmp(strs[SHAPE], "Shape") == 0 &&
|
||||
sizeof(strs) / sizeof(strs[0]) == NUM_REASONS);
|
||||
|
||||
return strs[r];
|
||||
}
|
||||
|
||||
enum Phase {
|
||||
PHASE_GC,
|
||||
PHASE_MARK,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_DESTROY,
|
||||
|
||||
PHASE_LIMIT
|
||||
};
|
||||
|
||||
enum Stat {
|
||||
STAT_NEW_CHUNK,
|
||||
STAT_DESTROY_CHUNK,
|
||||
|
||||
STAT_LIMIT
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
Statistics(JSRuntime *rt);
|
||||
~Statistics();
|
||||
|
||||
void beginGC(JSCompartment *comp, Reason reason);
|
||||
void endGC();
|
||||
|
||||
void beginPhase(Phase phase);
|
||||
void endPhase(Phase phase);
|
||||
|
||||
void count(Stat s) {
|
||||
JS_ASSERT(s < STAT_LIMIT);
|
||||
counts[s]++;
|
||||
}
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
|
||||
uint64 startupTime;
|
||||
|
||||
FILE *fp;
|
||||
bool fullFormat;
|
||||
|
||||
Reason triggerReason;
|
||||
JSCompartment *compartment;
|
||||
|
||||
uint64 phaseStarts[PHASE_LIMIT];
|
||||
uint64 phaseEnds[PHASE_LIMIT];
|
||||
uint64 phaseTimes[PHASE_LIMIT];
|
||||
unsigned int counts[STAT_LIMIT];
|
||||
|
||||
double t(Phase phase);
|
||||
double beginDelay(Phase phase1, Phase phase2);
|
||||
double endDelay(Phase phase1, Phase phase2);
|
||||
void printStats();
|
||||
};
|
||||
|
||||
struct AutoGC {
|
||||
AutoGC(Statistics &stats, JSCompartment *comp, Reason reason JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginGC(comp, reason); }
|
||||
~AutoGC() { stats.endGC(); }
|
||||
|
||||
Statistics &stats;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoPhase {
|
||||
AutoPhase(Statistics &stats, Phase phase JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), phase(phase) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginPhase(phase); }
|
||||
~AutoPhase() { stats.endPhase(phase); }
|
||||
|
||||
Statistics &stats;
|
||||
Phase phase;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_statistics_h___ */
|
|
@ -45,9 +45,9 @@
|
|||
#include "jscntxt.h"
|
||||
#include "jsinfer.h"
|
||||
#include "jsscript.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "js/TemplateLib.h"
|
||||
|
||||
struct JSScript;
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ BEGIN_TEST(testThreadGC_bug590533)
|
|||
* loop. Then run the GC with JSRuntime->gcIsNeeded flag set.
|
||||
*/
|
||||
js::AutoLockGC lock(rt);
|
||||
js::TriggerGC(rt);
|
||||
js::TriggerGC(rt, js::gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_GC(cx);
|
||||
|
|
|
@ -40,7 +40,10 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsalloc.h"
|
||||
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -83,7 +83,6 @@
|
|||
#include "jstracer.h"
|
||||
#include "prmjtime.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsweakmap.h"
|
||||
#include "jswrapper.h"
|
||||
#include "jstypedarray.h"
|
||||
|
@ -96,7 +95,6 @@
|
|||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
@ -664,6 +662,7 @@ JSRuntime::JSRuntime()
|
|||
gcMode(JSGC_MODE_GLOBAL),
|
||||
gcIsNeeded(0),
|
||||
gcWeakMapList(NULL),
|
||||
gcStats(thisFromCtor()),
|
||||
gcTriggerCompartment(NULL),
|
||||
gcCurrentCompartment(NULL),
|
||||
gcCheckCompartment(NULL),
|
||||
|
@ -696,7 +695,7 @@ JSRuntime::JSRuntime()
|
|||
requestDone(NULL),
|
||||
requestCount(0),
|
||||
gcThread(NULL),
|
||||
gcHelperThread(this),
|
||||
gcHelperThread(thisFromCtor()),
|
||||
rtLock(NULL),
|
||||
# ifdef DEBUG
|
||||
rtLockOwner(0),
|
||||
|
@ -706,6 +705,7 @@ JSRuntime::JSRuntime()
|
|||
debuggerMutations(0),
|
||||
securityCallbacks(NULL),
|
||||
structuredCloneCallbacks(NULL),
|
||||
telemetryCallback(NULL),
|
||||
propertyRemovals(0),
|
||||
scriptFilenameTable(NULL),
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -2706,14 +2706,12 @@ JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
|
|||
|
||||
LeaveTrace(cx);
|
||||
|
||||
GCREASON(PUBLIC_API);
|
||||
js_GC(cx, comp, GC_NORMAL);
|
||||
js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_GC(JSContext *cx)
|
||||
{
|
||||
GCREASON(PUBLIC_API);
|
||||
JS_CompartmentGC(cx, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,10 @@
|
|||
#include <stdio.h>
|
||||
#include "js-config.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsval.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* JS::Value can store a full int32. */
|
||||
|
@ -1696,6 +1697,17 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
|
|||
*/
|
||||
#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA
|
||||
|
||||
/*
|
||||
* The first call to JS_CallOnce by any thread in a process will call 'func'.
|
||||
* Later calls to JS_CallOnce with the same JSCallOnceType object will be
|
||||
* suppressed.
|
||||
*
|
||||
* Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce
|
||||
* to invoke its JSInitCallback.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallOnce(JSCallOnceType *once, JSInitCallback func);
|
||||
|
||||
/*
|
||||
* Microseconds since the epoch, midnight, January 1, 1970 UTC. See the
|
||||
* comment in jstypes.h regarding safe int64 usage.
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** 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 Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
/*
|
||||
* Lifetime-based fast allocation, inspired by much prior art, including
|
||||
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
|
||||
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jsalloc.h"
|
||||
#include "jstypes.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsarena.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
/* If JSArena's length is a multiple of 8, that ensures its payload is 8-aligned. */
|
||||
JS_STATIC_ASSERT(sizeof(JSArena) % 8 == 0);
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align)
|
||||
{
|
||||
/* Restricting ourselves to some simple alignments keeps things simple. */
|
||||
if (align == 1 || align == 2 || align == 4 || align == 8) {
|
||||
pool->mask = align - 1;
|
||||
} else {
|
||||
/* This shouldn't happen, but set pool->mask reasonably if it does. */
|
||||
JS_NOT_REACHED("JS_InitArenaPool: bad align");
|
||||
pool->mask = 7;
|
||||
}
|
||||
pool->first.next = NULL;
|
||||
/* pool->first is a zero-sized dummy arena that's never allocated from. */
|
||||
pool->first.base = pool->first.avail = pool->first.limit =
|
||||
JS_ARENA_ALIGN(pool, &pool->first + 1);
|
||||
pool->current = &pool->first;
|
||||
pool->arenasize = size;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
|
||||
{
|
||||
/*
|
||||
* Search pool from current forward till we find or make enough space.
|
||||
*
|
||||
* NB: subtract nb from a->limit in the loop condition, instead of adding
|
||||
* nb to a->avail, to avoid overflow (possible when running a 32-bit
|
||||
* program on a 64-bit system where the kernel maps the heap up against the
|
||||
* top of the 32-bit address space, see bug 279273). Note that this
|
||||
* necessitates a comparison between nb and a->limit that looks like a
|
||||
* (conceptual) type error but isn't.
|
||||
*/
|
||||
JS_ASSERT((nb & pool->mask) == 0);
|
||||
JSArena *a;
|
||||
/*
|
||||
* Comparing nb to a->limit looks like a (conceptual) type error, but it's
|
||||
* necessary to avoid wrap-around. Yuk.
|
||||
*/
|
||||
for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; pool->current = a) {
|
||||
JSArena **ap = &a->next;
|
||||
if (!*ap) {
|
||||
/* Not enough space in pool, so we must malloc. */
|
||||
size_t gross = sizeof(JSArena) + JS_MAX(nb, pool->arenasize);
|
||||
a = (JSArena *) OffTheBooks::malloc_(gross);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
a->next = NULL;
|
||||
a->base = a->avail = jsuword(a) + sizeof(JSArena);
|
||||
/*
|
||||
* Because malloc returns 8-aligned pointers and sizeof(JSArena) is
|
||||
* a multiple of 8, a->base will always be 8-aligned, which should
|
||||
* suffice for any valid pool.
|
||||
*/
|
||||
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
|
||||
a->limit = (jsuword)a + gross;
|
||||
|
||||
*ap = a;
|
||||
continue;
|
||||
}
|
||||
a = *ap; /* move to next arena */
|
||||
}
|
||||
|
||||
void* p = (void *)a->avail;
|
||||
a->avail += nb;
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
return p;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
{
|
||||
/* If we've called JS_ArenaRealloc, the new size must be bigger than pool->arenasize. */
|
||||
JS_ASSERT(size + incr > pool->arenasize);
|
||||
|
||||
/* Find the arena containing |p|. */
|
||||
JSArena *a;
|
||||
JSArena **ap = &pool->first.next;
|
||||
while (true) {
|
||||
a = *ap;
|
||||
if (JS_IS_IN_ARENA(a, p))
|
||||
break;
|
||||
JS_ASSERT(a != pool->current);
|
||||
ap = &a->next;
|
||||
}
|
||||
/* If we've called JS_ArenaRealloc, p must be at the start of an arena. */
|
||||
JS_ASSERT(a->base == jsuword(p));
|
||||
|
||||
size_t gross = sizeof(JSArena) + JS_ARENA_ALIGN(pool, size + incr);
|
||||
a = (JSArena *) OffTheBooks::realloc_(a, gross);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
a->base = jsuword(a) + sizeof(JSArena);
|
||||
a->avail = a->limit = jsuword(a) + gross;
|
||||
/*
|
||||
* Because realloc returns 8-aligned pointers and sizeof(JSArena) is a
|
||||
* multiple of 8, a->base will always be 8-aligned, which should suffice
|
||||
* for any valid pool.
|
||||
*/
|
||||
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
|
||||
|
||||
if (a != *ap) {
|
||||
/* realloc moved the allocation: update other pointers to a. */
|
||||
if (pool->current == *ap)
|
||||
pool->current = a;
|
||||
*ap = a;
|
||||
}
|
||||
|
||||
return (void *)a->base;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
/*
|
||||
* If p points to an oversized allocation, it owns an entire arena, so we
|
||||
* can simply realloc the arena.
|
||||
*/
|
||||
if (size > pool->arenasize)
|
||||
return JS_ArenaRealloc(pool, p, size, incr);
|
||||
|
||||
JS_ARENA_ALLOCATE(newp, pool, size + incr);
|
||||
if (newp)
|
||||
memcpy(newp, p, size);
|
||||
return newp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free tail arenas linked after head, which may not be the true list head.
|
||||
* Reset pool->current to point to head in case it pointed at a tail arena.
|
||||
*/
|
||||
static void
|
||||
FreeArenaList(JSArenaPool *pool, JSArena *head)
|
||||
{
|
||||
JSArena **ap, *a;
|
||||
|
||||
ap = &head->next;
|
||||
a = *ap;
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
do {
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
a->avail = a->base;
|
||||
JS_CLEAR_UNUSED(a);
|
||||
} while ((a = a->next) != NULL);
|
||||
a = *ap;
|
||||
#endif
|
||||
|
||||
do {
|
||||
*ap = a->next;
|
||||
JS_CLEAR_ARENA(a);
|
||||
UnwantedForeground::free_(a);
|
||||
} while ((a = *ap) != NULL);
|
||||
|
||||
pool->current = head;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaRelease(JSArenaPool *pool, char *mark)
|
||||
{
|
||||
JSArena *a;
|
||||
|
||||
for (a = &pool->first; a; a = a->next) {
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
|
||||
if (JS_IS_IN_ARENA(a, mark)) {
|
||||
a->avail = JS_ARENA_ALIGN(pool, mark);
|
||||
JS_ASSERT(a->avail <= a->limit);
|
||||
FreeArenaList(pool, a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FreeArenaPool(JSArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FinishArenaPool(JSArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaFinish()
|
||||
{
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaShutDown(void)
|
||||
{
|
||||
}
|
|
@ -109,7 +109,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsbool.h"
|
||||
#include "jsbuiltins.h"
|
||||
#include "jscntxt.h"
|
||||
|
@ -126,7 +125,6 @@
|
|||
#include "jsstr.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsvector.h"
|
||||
#include "jswrapper.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
#include "methodjit/StubCalls.h"
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include "jsprf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbit.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsgcmark.h"
|
||||
|
|
|
@ -42,13 +42,14 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include "jsversion.h"
|
||||
#include "jsalloc.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jshash.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
/* Engine-internal extensions of jsid */
|
||||
|
|
305
js/src/jsbit.h
305
js/src/jsbit.h
|
@ -1,305 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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 Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of 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 ***** */
|
||||
|
||||
#ifndef jsbit_h___
|
||||
#define jsbit_h___
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jscompat.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
** A jsbitmap_t is a long integer that can be used for bitmaps
|
||||
*/
|
||||
typedef jsuword jsbitmap_t; /* NSPR name, a la Unix system types */
|
||||
typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */
|
||||
|
||||
#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \
|
||||
sizeof(jsbitmap))
|
||||
|
||||
#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \
|
||||
~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
|
||||
/*
|
||||
** Compute the log of the least power of 2 greater than or equal to n
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i);
|
||||
|
||||
/*
|
||||
** Compute the log of the greatest power of 2 less than or equal to n
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i);
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
*
|
||||
* With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129.
|
||||
*
|
||||
* SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856.
|
||||
*/
|
||||
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
|
||||
unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
|
||||
unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
|
||||
# pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward(&idx, (unsigned long)val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse(&idx, (unsigned long)val);
|
||||
return (int)(31-idx);
|
||||
}
|
||||
# define js_bitscan_ctz32(val) __BitScanForward32(val)
|
||||
# define js_bitscan_clz32(val) __BitScanReverse32(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_X64)
|
||||
unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask);
|
||||
# pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward64(&idx, val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse64(&idx, val);
|
||||
return (int)(63-idx);
|
||||
}
|
||||
# define js_bitscan_ctz64(val) __BitScanForward64(val)
|
||||
# define js_bitscan_clz64(val) __BitScanReverse64(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
#endif
|
||||
#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
|
||||
# define js_bitscan_ctz32(val) __builtin_ctz(val)
|
||||
# define js_bitscan_clz32(val) __builtin_clz(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
# if (JS_BYTES_PER_WORD == 8)
|
||||
# define js_bitscan_ctz64(val) __builtin_ctzll(val)
|
||||
# define js_bitscan_clz64(val) __builtin_clzll(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_CeilingLog2: Compute the log of the least power of
|
||||
** 2 greater than or equal to _n. The result is returned in _log2.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)).
|
||||
* The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is
|
||||
* undefined.
|
||||
*/
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
unsigned int j_ = (unsigned int)(_n); \
|
||||
(_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) & ((j_)-1)) \
|
||||
(_log2) += 1; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_FloorLog2: Compute the log of the greatest power of
|
||||
** 2 less than or equal to _n. The result is returned in _log2.
|
||||
**
|
||||
** This is equivalent to finding the highest set bit in the word.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)).
|
||||
* Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1
|
||||
* to ensure 0 result when _n == 0.
|
||||
*/
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
(_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
* a version of JS_CeilingLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size.
|
||||
*/
|
||||
#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the greatest power of 2 less than or equal to n.
|
||||
* This is a version of JS_FloorLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size and requires that n != 0.
|
||||
*/
|
||||
#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
|
||||
# else
|
||||
# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n))
|
||||
#endif
|
||||
|
||||
#elif JS_BYTES_PER_WORD == 8
|
||||
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN64
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
|
||||
# else
|
||||
extern size_t js_FloorLog2wImpl(size_t n);
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# error "NOT SUPPORTED"
|
||||
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
inline size_t
|
||||
CountTrailingZeros(size_t n)
|
||||
{
|
||||
JS_ASSERT(n != 0);
|
||||
#if JS_BYTES_PER_WORD != 4 && JS_BYTES_PER_WORD != 8
|
||||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4 && defined JS_HAS_BUILTIN_BITSCAN32
|
||||
return js_bitscan_ctz32(n);
|
||||
#elif JS_BYTES_PER_WORD == 8 && defined JS_HAS_BUILTIN_BITSCAN64
|
||||
return js_bitscan_ctz64(n);
|
||||
#else
|
||||
size_t count = 0;
|
||||
# if JS_BYTES_PER_WORD == 8
|
||||
if (!(n & size_t(0xFFFFFFFFU))) { count += 32; n >>= 32; }
|
||||
# endif
|
||||
if (!(n & 0xFFFF)) { count += 16; n >>= 16; }
|
||||
if (!(n & 0xFF)) { count += 8; n >>= 8; }
|
||||
if (!(n & 0xF)) { count += 4; n >>= 4; }
|
||||
if (!(n & 0x3)) { count += 2; n >>= 2; }
|
||||
if (!(n & 0x1)) { count += 1; n >>= 1; }
|
||||
return count + 1 - (n & 0x1);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for rotate left. There is no rotate operation in the C Language so
|
||||
* the construct (a << 4) | (a >> 28) is used instead. Most compilers convert
|
||||
* this to a rotate instruction but some versions of MSVC don't without a
|
||||
* little help. To get MSVC to generate a rotate instruction, we have to use
|
||||
* the _rotl intrinsic and use a pragma to make _rotl inline.
|
||||
*
|
||||
* MSVC in VS2005 will do an inline rotate instruction on the above construct.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \
|
||||
defined(_M_X64))
|
||||
#include <stdlib.h>
|
||||
#pragma intrinsic(_rotl)
|
||||
#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits)
|
||||
#else
|
||||
#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits))))
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
#endif /* jsbit_h___ */
|
|
@ -53,7 +53,6 @@
|
|||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsstr.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include "jsstr.h"
|
||||
#include "jsbuiltins.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
|
|
|
@ -41,9 +41,10 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
JS_FRIEND_API(uint64_t)
|
||||
js_GetSCOffset(JSStructuredCloneWriter* writer);
|
||||
|
|
|
@ -533,21 +533,18 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
|||
#endif
|
||||
|
||||
if (last) {
|
||||
GCREASON(LASTCONTEXT);
|
||||
js_GC(cx, NULL, GC_LAST_CONTEXT);
|
||||
js_GC(cx, NULL, GC_LAST_CONTEXT, gcstats::LASTCONTEXT);
|
||||
|
||||
/* Take the runtime down, now that it has no contexts or atoms. */
|
||||
JS_LOCK_GC(rt);
|
||||
rt->state = JSRTS_DOWN;
|
||||
JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
|
||||
} else {
|
||||
if (mode == JSDCM_FORCE_GC) {
|
||||
GCREASON(DESTROYCONTEXT);
|
||||
js_GC(cx, NULL, GC_NORMAL);
|
||||
} else if (mode == JSDCM_MAYBE_GC) {
|
||||
GCREASON(DESTROYCONTEXT);
|
||||
if (mode == JSDCM_FORCE_GC)
|
||||
js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);
|
||||
else if (mode == JSDCM_MAYBE_GC)
|
||||
JS_MaybeGC(cx);
|
||||
}
|
||||
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
}
|
||||
|
@ -1165,7 +1162,7 @@ js_InvokeOperationCallback(JSContext *cx)
|
|||
JS_UNLOCK_GC(rt);
|
||||
|
||||
if (rt->gcIsNeeded) {
|
||||
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL);
|
||||
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, rt->gcTriggerReason);
|
||||
|
||||
/*
|
||||
* On trace we can exceed the GC quota, see comments in NewGCArena. So
|
||||
|
@ -1342,6 +1339,7 @@ JSContext::JSContext(JSRuntime *rt)
|
|||
throwing(false),
|
||||
exception(UndefinedValue()),
|
||||
runOptions(0),
|
||||
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
|
||||
localeCallbacks(NULL),
|
||||
resolvingList(NULL),
|
||||
generatingError(false),
|
||||
|
@ -1514,8 +1512,7 @@ JSRuntime::onTooMuchMalloc()
|
|||
*/
|
||||
js_WaitForGC(this);
|
||||
#endif
|
||||
GCREASON(TOOMUCHMALLOC);
|
||||
TriggerGC(this);
|
||||
TriggerGC(this, gcstats::TOOMUCHMALLOC);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
|
|
|
@ -45,21 +45,23 @@
|
|||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsclist.h"
|
||||
#include "jsdhash.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsgcchunk.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jspropertycache.h"
|
||||
#include "jspropertytree.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsvector.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "gc/Statistics.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/StackSpace.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -430,6 +432,10 @@ struct JSRuntime {
|
|||
JSGCMode gcMode;
|
||||
volatile jsuword gcIsNeeded;
|
||||
js::WeakMapBase *gcWeakMapList;
|
||||
js::gcstats::Statistics gcStats;
|
||||
|
||||
/* The reason that an interrupt-triggered GC should be called. */
|
||||
js::gcstats::Reason gcTriggerReason;
|
||||
|
||||
/* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
|
||||
void *gcMarkStackObjs[js::OBJECT_MARK_STACK_SIZE / sizeof(void *)];
|
||||
|
@ -599,6 +605,9 @@ struct JSRuntime {
|
|||
/* Structured data callbacks are runtime-wide. */
|
||||
const JSStructuredCloneCallbacks *structuredCloneCallbacks;
|
||||
|
||||
/* Call this to accumulate telemetry data. */
|
||||
JSAccumulateTelemetryDataCallback telemetryCallback;
|
||||
|
||||
/*
|
||||
* The propertyRemovals counter is incremented for every JSObject::clear,
|
||||
* and for each JSObject::remove method call that frees a slot in the given
|
||||
|
@ -673,59 +682,13 @@ struct JSRuntime {
|
|||
*/
|
||||
int32 inOOMReport;
|
||||
|
||||
#if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT)
|
||||
struct GCData {
|
||||
GCData()
|
||||
: firstEnter(0),
|
||||
firstEnterValid(false)
|
||||
#ifdef JSGC_TESTPILOT
|
||||
, infoEnabled(false),
|
||||
start(0),
|
||||
count(0)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
/*
|
||||
* Timestamp of the first GCTimer -- application runtime is determined
|
||||
* relative to this value.
|
||||
*/
|
||||
uint64 firstEnter;
|
||||
bool firstEnterValid;
|
||||
|
||||
void setFirstEnter(uint64 v) {
|
||||
JS_ASSERT(!firstEnterValid);
|
||||
firstEnter = v;
|
||||
firstEnterValid = true;
|
||||
}
|
||||
|
||||
#ifdef JSGC_TESTPILOT
|
||||
bool infoEnabled;
|
||||
|
||||
bool isTimerEnabled() {
|
||||
return infoEnabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular buffer with GC data.
|
||||
* count may grow >= INFO_LIMIT, which would indicate data loss.
|
||||
*/
|
||||
static const size_t INFO_LIMIT = 64;
|
||||
JSGCInfo info[INFO_LIMIT];
|
||||
size_t start;
|
||||
size_t count;
|
||||
#else /* defined(MOZ_GCTIMER) */
|
||||
bool isTimerEnabled() {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
} gcData;
|
||||
#endif
|
||||
|
||||
JSRuntime();
|
||||
~JSRuntime();
|
||||
|
||||
bool init(uint32 maxbytes);
|
||||
|
||||
JSRuntime *thisFromCtor() { return this; }
|
||||
|
||||
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||
void reduceGCTriggerBytes(uint32 amount);
|
||||
|
||||
|
@ -970,6 +933,8 @@ struct JSContext
|
|||
uintN runOptions; /* see jsapi.h for JSOPTION_* */
|
||||
|
||||
public:
|
||||
int32 reportGranularity; /* see jsprobes.h */
|
||||
|
||||
/* Locale specific callbacks for string conversion. */
|
||||
JSLocaleCallbacks *localeCallbacks;
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче