This commit is contained in:
Rob Campbell 2011-10-13 10:35:04 -03:00
Родитель e399f89604 513ec25690
Коммит 6035ebe12b
212 изменённых файлов: 3819 добавлений и 3136 удалений

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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

Просмотреть файл

@ -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()

Просмотреть файл

@ -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

Просмотреть файл

@ -1099,6 +1099,7 @@ public:
* @param aPrincipal Prinicpal of the document. Must not be null.
* @param aScriptObject The object from which the context for event handling
* can be got.
* @param aSVGDocument Force SVG Document creation.
* @param aResult [out] The document that was created.
*/
static nsresult CreateDocument(const nsAString& aNamespaceURI,
@ -1108,6 +1109,7 @@ public:
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal,
nsIScriptGlobalObject* aScriptObject,
bool aSVGDocument,
nsIDOMDocument** aResult);
/**

Просмотреть файл

@ -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;
@ -1878,7 +1880,8 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal,
bool aLoadedAsData,
nsIScriptGlobalObject* aEventObject);
nsIScriptGlobalObject* aEventObject,
bool aSVGDocument);
nsresult
NS_NewPluginDocument(nsIDocument** aInstancePtrResult);

Просмотреть файл

@ -3683,11 +3683,12 @@ nsContentUtils::CreateDocument(const nsAString& aNamespaceURI,
nsIURI* aDocumentURI, nsIURI* aBaseURI,
nsIPrincipal* aPrincipal,
nsIScriptGlobalObject* aEventObject,
bool aSVGDocument,
nsIDOMDocument** aResult)
{
nsresult rv = NS_NewDOMDocument(aResult, aNamespaceURI, aQualifiedName,
aDoctype, aDocumentURI, aBaseURI, aPrincipal,
PR_TRUE, aEventObject);
PR_TRUE, aEventObject, aSVGDocument);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> document = do_QueryInterface(*aResult);

Просмотреть файл

@ -141,10 +141,15 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream,
NS_ENSURE_ARG_POINTER(aResult);
*aResult = nsnull;
bool svg = nsCRT::strcmp(contentType, "image/svg+xml") == 0;
// For now, we can only create XML documents.
//XXXsmaug Should we create an HTMLDocument (in XHTML mode)
// for "application/xhtml+xml"?
if ((nsCRT::strcmp(contentType, "text/xml") != 0) &&
(nsCRT::strcmp(contentType, "application/xml") != 0) &&
(nsCRT::strcmp(contentType, "application/xhtml+xml") != 0))
(nsCRT::strcmp(contentType, "application/xhtml+xml") != 0) &&
!svg)
return NS_ERROR_NOT_IMPLEMENTED;
nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
@ -183,7 +188,7 @@ nsDOMParser::ParseFromStream(nsIInputStream *stream,
rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(), nsnull,
mDocumentURI, mBaseURI,
mOriginalPrincipal,
scriptHandlingObject,
scriptHandlingObject, svg,
getter_AddRefs(domDocument));
NS_ENSURE_SUCCESS(rv, rv);

Просмотреть файл

@ -1437,7 +1437,7 @@ nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
return nsContentUtils::CreateDocument(aNamespaceURI, aQualifiedName, aDoctype,
mDocumentURI, mBaseURI,
mOwner->NodePrincipal(),
scriptHandlingObject, aReturn);
scriptHandlingObject, false, aReturn);
}
NS_IMETHODIMP
@ -1469,7 +1469,7 @@ nsDOMImplementation::CreateHTMLDocument(const nsAString& aTitle,
rv = nsContentUtils::CreateDocument(EmptyString(), EmptyString(),
doctype, mDocumentURI, mBaseURI,
mOwner->NodePrincipal(),
scriptHandlingObject,
scriptHandlingObject, false,
getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> doc = do_QueryInterface(document);
@ -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;

Просмотреть файл

@ -1880,7 +1880,7 @@ nsXMLHttpRequest::OnStartRequest(nsIRequest *request, nsISupports *ctxt)
const nsAString& emptyStr = EmptyString();
nsCOMPtr<nsIScriptGlobalObject> global = do_QueryInterface(mOwner);
rv = nsContentUtils::CreateDocument(emptyStr, emptyStr, nsnull, docURI,
baseURI, mPrincipal, global,
baseURI, mPrincipal, global, false,
getter_AddRefs(mResponseXML));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIDocument> responseDoc = do_QueryInterface(mResponseXML);

Просмотреть файл

@ -516,8 +516,10 @@ _TEST_FILES2 = \
test_bug684671.html \
test_bug685798.html \
test_bug686449.xhtml \
test_bug690056.html \
test_bug692434.html \
file_bug692434.xml \
test_bug693875.html \
$(NULL)
_CHROME_FILES = \

Просмотреть файл

@ -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>

Просмотреть файл

@ -0,0 +1,39 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=693875
-->
<head>
<title>Test for Bug 693875</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=693875">Mozilla Bug 693875</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 693875 **/
var dp = new DOMParser();
var d = dp.parseFromString("<?xml version='1.0'?><svg xmlns='http://www.w3.org/2000/svg'></svg>",
"image/svg+xml");
ok(d instanceof SVGDocument, "Should have created an SVG document.");
ok("rootElement" in d, "Should have created an SVG document, which has .rootElement.");
is(d.documentElement.localName, "svg", "Root element should be svg.");
is(d.documentElement.namespaceURI, "http://www.w3.org/2000/svg",
"Root element should be in svg namespace.");
dp = new DOMParser();
d = dp.parseFromString("<?xml version='1.0'?><svg xmlns='http://www.w3.org/2000/svg'></svg>",
"text/xml");
ok(!(d instanceof SVGDocument), "Should not have created an SVG document!");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -104,7 +104,8 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
nsIURI* aBaseURI,
nsIPrincipal* aPrincipal,
bool aLoadedAsData,
nsIScriptGlobalObject* aEventObject)
nsIScriptGlobalObject* aEventObject,
bool aSVGDocument)
{
// Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
// since at least one caller (XMLHttpRequest) doesn't have decent args to
@ -117,7 +118,9 @@ NS_NewDOMDocument(nsIDOMDocument** aInstancePtrResult,
nsCOMPtr<nsIDocument> d;
bool isHTML = false;
bool isXHTML = false;
if (aDoctype) {
if (aSVGDocument) {
rv = NS_NewSVGDocument(getter_AddRefs(d));
} else if (aDoctype) {
nsAutoString publicId, name;
aDoctype->GetPublicId(publicId);
if (publicId.IsEmpty()) {

Просмотреть файл

@ -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">&notCached.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">&notCached.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>

Просмотреть файл

@ -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 &quot;Try Again&quot; 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>

Просмотреть файл

@ -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__ */

945
js/public/Utility.h Normal file
Просмотреть файл

@ -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 {

218
js/src/gc/Statistics.cpp Normal file
Просмотреть файл

@ -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 */

158
js/src/gc/Statistics.h Normal file
Просмотреть файл

@ -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 */

Просмотреть файл

@ -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;

Просмотреть файл

@ -847,7 +847,12 @@ date_parseISOString(JSLinearString *str, jsdouble *result, JSContext *cx)
tzMul = -1;
++i;
NEED_NDIGITS(2, tzHour);
NEED(':');
/*
* Non-standard extension to the ISO date format (permitted by ES5):
* allow "-0700" as a time zone offset, not just "-07:00".
*/
if (PEEK(':'))
++i;
NEED_NDIGITS(2, tzMin);
} else {
isLocalTime = JS_TRUE;

Просмотреть файл

@ -49,7 +49,6 @@
#include "jsstdint.h"
#include "jsutil.h"
#include "jsclist.h"
#include "jshashtable.h"
#include "jsapi.h"
#include "jscntxt.h"
#include "jsversion.h"
@ -69,6 +68,7 @@
#include "jsstr.h"
#include "jswatchpoint.h"
#include "jswrapper.h"
#include "vm/Debugger.h"
#include "jsatominlines.h"

Просмотреть файл

@ -45,7 +45,6 @@
#include <stdlib.h>
#include <string.h>
#include "jsstdint.h"
#include "jsbit.h"
#include "jsdhash.h"
#include "jsutil.h"

Просмотреть файл

@ -47,7 +47,6 @@
#include "jsapi.h"
#include "jsprvtd.h"
#include "jsnum.h"
#include "jsbit.h"
#include "jslibmath.h"
#include "jscntxt.h"

Просмотреть файл

@ -49,7 +49,6 @@
#include "jstypes.h"
#include "jsstdint.h"
#include "jsutil.h"
#include "jsbit.h"
#include "jsprf.h"
#include "jsapi.h"
#include "jsatom.h"
@ -7775,13 +7774,6 @@ js_FinishTakingSrcNotes(JSContext *cx, JSCodeGenerator *cg, jssrcnote *notes)
memcpy(notes + prologCount, cg->main.notes, SRCNOTE_SIZE(mainCount));
SN_MAKE_TERMINATOR(&notes[totalCount]);
#ifdef DEBUG_notme
{ int bin = JS_CeilingLog2(totalCount);
if (bin >= NBINS)
bin = NBINS - 1;
++hist[bin];
}
#endif
return JS_TRUE;
}

Просмотреть файл

@ -45,7 +45,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsbit.h"
#include "jsutil.h"
#include "jsprf.h"
#include "jsapi.h"
@ -618,8 +617,8 @@ StackTraceToString(JSContext *cx, JSExnPrivate *priv)
length_ >= STACK_LENGTH_LIMIT - stacklen) { \
goto done; \
} \
stackmax = JS_BIT(JS_CeilingLog2(stacklen + length_)); \
ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \
stackmax = RoundUpPow2(stacklen + length_); \
ptr_ = cx->realloc_(stackbuf, (stackmax+1) * sizeof(jschar)); \
if (!ptr_) \
goto bad; \
stackbuf = (jschar *) ptr_; \

Просмотреть файл

@ -222,3 +222,9 @@ JS_GetCustomIteratorCount(JSContext *cx)
{
return sCustomIteratorCount;
}
JS_FRIEND_API(void)
JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
{
rt->telemetryCallback = callback;
}

Просмотреть файл

@ -79,6 +79,21 @@ JS_SetProtoCalled(JSContext *cx);
extern JS_FRIEND_API(size_t)
JS_GetCustomIteratorCount(JSContext *cx);
enum {
JS_TELEMETRY_GC_REASON,
JS_TELEMETRY_GC_IS_COMPARTMENTAL,
JS_TELEMETRY_GC_IS_SHAPE_REGEN,
JS_TELEMETRY_GC_MS,
JS_TELEMETRY_GC_MARK_MS,
JS_TELEMETRY_GC_SWEEP_MS
};
typedef void
(* JSAccumulateTelemetryDataCallback)(int id, JSUint32 sample);
extern JS_FRIEND_API(void)
JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback);
/* Data for tracking analysis/inference memory usage. */
typedef struct TypeInferenceMemoryStats
{

Просмотреть файл

@ -44,7 +44,6 @@
#include <string.h>
#include "jstypes.h"
#include "jsstdint.h"
#include "jsbit.h"
#include "jsutil.h"
#include "jsapi.h"
#include "jsarray.h"

Просмотреть файл

@ -54,7 +54,6 @@
#include "jsstdint.h"
#include "jsutil.h"
#include "jshash.h"
#include "jsbit.h"
#include "jsclist.h"
#include "jsprf.h"
#include "jsapi.h"
@ -70,7 +69,6 @@
#include "jsgc.h"
#include "jsgcchunk.h"
#include "jsgcmark.h"
#include "jshashtable.h"
#include "jsinterp.h"
#include "jsiter.h"
#include "jslock.h"
@ -89,13 +87,13 @@
#endif
#include "methodjit/MethodJIT.h"
#include "vm/String.h"
#include "vm/Debugger.h"
#include "vm/String.h"
#include "jsobjinlines.h"
#include "vm/String-inl.h"
#include "vm/CallObject-inl.h"
#include "vm/String-inl.h"
#ifdef MOZ_VALGRIND
# define JS_VALGRIND
@ -442,7 +440,7 @@ ChunkPool::get(JSRuntime *rt)
--emptyCount;
} else {
JS_ASSERT(!emptyCount);
chunk = Chunk::allocate();
chunk = Chunk::allocate(rt);
if (!chunk)
return NULL;
}
@ -475,7 +473,7 @@ ChunkPool::put(JSRuntime *rt, Chunk *chunk)
*/
if (rt->gcHelperThread.sweeping()) {
if (rt->gcHelperThread.shouldShrink()) {
Chunk::release(chunk);
Chunk::release(rt, chunk);
return;
}
@ -514,7 +512,7 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll)
if (releaseAll || chunk->info.age == MAX_EMPTY_CHUNK_AGE) {
*chunkp = chunk->info.next;
--emptyCount;
Chunk::release(chunk);
Chunk::release(rt, chunk);
} else {
/* Keep the chunk but increase its age. */
++chunk->info.age;
@ -525,25 +523,21 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll)
}
/* static */ Chunk *
Chunk::allocate()
Chunk::allocate(JSRuntime *rt)
{
Chunk *chunk = static_cast<Chunk *>(AllocGCChunk());
if (!chunk)
return NULL;
chunk->init();
#ifdef MOZ_GCTIMER
JS_ATOMIC_INCREMENT(&newChunkCount);
#endif
rt->gcStats.count(gcstats::STAT_NEW_CHUNK);
return chunk;
}
/* static */ inline void
Chunk::release(Chunk *chunk)
Chunk::release(JSRuntime *rt, Chunk *chunk)
{
JS_ASSERT(chunk);
#ifdef MOZ_GCTIMER
JS_ATOMIC_INCREMENT(&destroyChunkCount);
#endif
rt->gcStats.count(gcstats::STAT_DESTROY_CHUNK);
FreeGCChunk(chunk);
}
@ -627,7 +621,7 @@ Chunk::allocateArena(JSCompartment *comp, AllocKind thingKind)
JS_ATOMIC_ADD(&rt->gcBytes, ArenaSize);
JS_ATOMIC_ADD(&comp->gcBytes, ArenaSize);
if (comp->gcBytes >= comp->gcTriggerBytes)
TriggerCompartmentGC(comp);
TriggerCompartmentGC(comp, gcstats::ALLOCTRIGGER);
return aheader;
}
@ -700,7 +694,7 @@ PickChunk(JSCompartment *comp)
GCChunkSet::AddPtr p = rt->gcChunkSet.lookupForAdd(chunk);
JS_ASSERT(!p);
if (!rt->gcChunkSet.add(p, chunk)) {
Chunk::release(chunk);
Chunk::release(rt, chunk);
return NULL;
}
@ -1059,7 +1053,7 @@ js_FinishGC(JSRuntime *rt)
rt->gcSystemAvailableChunkListHead = NULL;
rt->gcUserAvailableChunkListHead = NULL;
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
Chunk::release(r.front());
Chunk::release(rt, r.front());
rt->gcChunkSet.clear();
#ifdef JS_THREADSAFE
@ -1527,8 +1521,7 @@ RunLastDitchGC(JSContext *cx)
#endif
/* The last ditch GC preserves all atoms. */
AutoKeepAtoms keep(rt);
GCREASON(LASTDITCH);
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL);
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, gcstats::LASTDITCH);
#ifdef JS_THREADSAFE
if (rt->gcBytes >= rt->gcMaxBytes) {
@ -1581,8 +1574,7 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
*/
if (runGC || !IsGCAllowed(cx)) {
AutoLockGC lock(rt);
GCREASON(REFILL);
TriggerGC(rt);
TriggerGC(rt, gcstats::REFILL);
break;
}
runGC = true;
@ -1982,7 +1974,7 @@ MarkRuntime(JSTracer *trc)
}
void
TriggerGC(JSRuntime *rt)
TriggerGC(JSRuntime *rt, gcstats::Reason reason)
{
JS_ASSERT(!rt->gcRunning);
if (rt->gcIsNeeded)
@ -1994,24 +1986,24 @@ TriggerGC(JSRuntime *rt)
*/
rt->gcIsNeeded = true;
rt->gcTriggerCompartment = NULL;
rt->gcTriggerReason = reason;
TriggerAllOperationCallbacks(rt);
}
void
TriggerCompartmentGC(JSCompartment *comp)
TriggerCompartmentGC(JSCompartment *comp, gcstats::Reason reason)
{
JSRuntime *rt = comp->rt;
JS_ASSERT(!rt->gcRunning);
GCREASON(COMPARTMENT);
if (rt->gcZeal()) {
TriggerGC(rt);
TriggerGC(rt, reason);
return;
}
if (rt->gcMode != JSGC_MODE_COMPARTMENT || comp == rt->atomsCompartment) {
/* We can't do a compartmental GC of the default compartment. */
TriggerGC(rt);
TriggerGC(rt, reason);
return;
}
@ -2024,7 +2016,7 @@ TriggerCompartmentGC(JSCompartment *comp)
if (rt->gcBytes > 8192 && rt->gcBytes >= 3 * (rt->gcTriggerBytes / 2)) {
/* If we're using significantly more than our quota, do a full GC. */
TriggerGC(rt);
TriggerGC(rt, reason);
return;
}
@ -2034,6 +2026,7 @@ TriggerCompartmentGC(JSCompartment *comp)
*/
rt->gcIsNeeded = true;
rt->gcTriggerCompartment = comp;
rt->gcTriggerReason = reason;
TriggerAllOperationCallbacks(comp->rt);
}
@ -2043,21 +2036,18 @@ MaybeGC(JSContext *cx)
JSRuntime *rt = cx->runtime;
if (rt->gcZeal()) {
GCREASON(MAYBEGC);
js_GC(cx, NULL, GC_NORMAL);
js_GC(cx, NULL, GC_NORMAL, gcstats::MAYBEGC);
return;
}
JSCompartment *comp = cx->compartment;
if (rt->gcIsNeeded) {
GCREASON(MAYBEGC);
js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL);
js_GC(cx, (comp == rt->gcTriggerCompartment) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
return;
}
if (comp->gcBytes > 8192 && comp->gcBytes >= 3 * (comp->gcTriggerBytes / 4)) {
GCREASON(MAYBEGC);
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL);
js_GC(cx, (rt->gcMode == JSGC_MODE_COMPARTMENT) ? comp : NULL, GC_NORMAL, gcstats::MAYBEGC);
return;
}
@ -2067,12 +2057,10 @@ MaybeGC(JSContext *cx)
*/
int64 now = PRMJ_Now();
if (rt->gcNextFullGCTime && rt->gcNextFullGCTime <= now) {
if (rt->gcChunkAllocationSinceLastGC) {
GCREASON(MAYBEGC);
js_GC(cx, NULL, GC_SHRINK);
} else {
if (rt->gcChunkAllocationSinceLastGC)
js_GC(cx, NULL, GC_SHRINK, gcstats::MAYBEGC);
else
rt->gcNextFullGCTime = now + GC_IDLE_FULL_SPAN;
}
}
}
@ -2159,7 +2147,7 @@ GCHelperThread::threadLoop()
Chunk *chunk;
{
AutoUnlockGC unlock(rt);
chunk = Chunk::allocate();
chunk = Chunk::allocate(rt);
}
/* OOM stops the background allocation. */
@ -2286,7 +2274,7 @@ GCHelperThread::doSweep()
freeVector.resize(0);
}
}
} /* namespace js */
#endif /* JS_THREADSAFE */
@ -2346,7 +2334,7 @@ SweepCompartments(JSContext *cx, JSGCInvocationKind gckind)
}
static void
BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM)
BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
@ -2376,7 +2364,7 @@ BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTI
/*
* Mark phase.
*/
GCTIMESTAMP(startMark);
rt->gcStats.beginPhase(gcstats::PHASE_MARK);
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
r.front()->bitmap.clear();
@ -2391,7 +2379,7 @@ BeginMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTI
}
static void
EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM)
EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
@ -2413,6 +2401,8 @@ EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIME
rt->gcMarkingTracer = NULL;
rt->gcStats.endPhase(gcstats::PHASE_MARK);
if (rt->gcCallback)
(void) rt->gcCallback(cx, JSGC_MARK_END);
@ -2428,7 +2418,7 @@ EndMarkPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIME
}
static void
SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_PARAM)
SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
@ -2446,7 +2436,7 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_
* unique. This works since the atomization API must not be called during
* the GC.
*/
GCTIMESTAMP(startSweep);
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP);
/* Finalize unreachable (key,value) pairs in all weak maps. */
WeakMapBase::sweepAll(gcmarker);
@ -2456,10 +2446,6 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_
/* Collect watch points associated with unreachable objects. */
WatchpointMap::sweepAll(cx);
Probes::GCStartSweepPhase(NULL);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
Probes::GCStartSweepPhase(c);
if (!rt->gcCurrentCompartment)
Debugger::sweepAll(cx);
@ -2467,63 +2453,67 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->sweep(cx, releaseInterval);
/*
* We finalize objects before other GC things to ensure that the object's
* finalizer can access the other things even if they will be freed.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeObjects(cx);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_OBJECT);
GCTIMESTAMP(sweepObjectEnd);
/*
* We finalize objects before other GC things to ensure that the object's
* finalizer can access the other things even if they will be freed.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeObjects(cx);
}
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeStrings(cx);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_STRING);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeStrings(cx);
}
GCTIMESTAMP(sweepStringEnd);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_SCRIPT);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeScripts(cx);
}
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeScripts(cx);
GCTIMESTAMP(sweepScriptEnd);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeShapes(cx);
GCTIMESTAMP(sweepShapeEnd);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
Probes::GCEndSweepPhase(c);
Probes::GCEndSweepPhase(NULL);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_SWEEP_SHAPE);
for (GCCompartmentsIter c(rt); !c.done(); c.next())
c->arenas.finalizeShapes(cx);
}
#ifdef DEBUG
PropertyTree::dumpShapes(cx);
#endif
/*
* Sweep script filenames after sweeping functions in the generic loop
* above. In this way when a scripted function's finalizer destroys the
* script and calls rt->destroyScriptHook, the hook can still access the
* script's filename. See bug 323267.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next())
js_SweepScriptFilenames(c);
{
gcstats::AutoPhase ap(rt->gcStats, gcstats::PHASE_DESTROY);
/*
* This removes compartments from rt->compartment, so we do it last to make
* sure we don't miss sweeping any compartments.
*/
if (!rt->gcCurrentCompartment)
SweepCompartments(cx, gckind);
/*
* Sweep script filenames after sweeping functions in the generic loop
* above. In this way when a scripted function's finalizer destroys the
* script and calls rt->destroyScriptHook, the hook can still access the
* script's filename. See bug 323267.
*/
for (GCCompartmentsIter c(rt); !c.done(); c.next())
js_SweepScriptFilenames(c);
/*
* This removes compartments from rt->compartment, so we do it last to make
* sure we don't miss sweeping any compartments.
*/
if (!rt->gcCurrentCompartment)
SweepCompartments(cx, gckind);
#ifndef JS_THREADSAFE
/*
* Destroy arenas after we finished the sweeping so finalizers can safely
* use IsAboutToBeFinalized().
* This is done on the GCHelperThread if JS_THREADSAFE is defined.
*/
rt->gcChunkPool.expire(rt, gckind == GC_SHRINK);
/*
* Destroy arenas after we finished the sweeping so finalizers can safely
* use IsAboutToBeFinalized().
* This is done on the GCHelperThread if JS_THREADSAFE is defined.
*/
rt->gcChunkPool.expire(rt, gckind == GC_SHRINK);
#endif
GCTIMESTAMP(sweepDestroyEnd);
}
if (rt->gcCallback)
(void) rt->gcCallback(cx, JSGC_FINALIZE_END);
@ -2537,7 +2527,7 @@ SweepPhase(JSContext *cx, GCMarker *gcmarker, JSGCInvocationKind gckind GCTIMER_
* to finish. The caller must hold rt->gcLock.
*/
static void
MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
rt->gcNumber++;
@ -2556,10 +2546,10 @@ MarkAndSweep(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
JS_ASSERT(gcmarker.getMarkColor() == BLACK);
rt->gcMarkingTracer = &gcmarker;
BeginMarkPhase(cx, &gcmarker, gckind GCTIMER_ARG);
BeginMarkPhase(cx, &gcmarker, gckind);
gcmarker.drainMarkStack();
EndMarkPhase(cx, &gcmarker, gckind GCTIMER_ARG);
SweepPhase(cx, &gcmarker, gckind GCTIMER_ARG);
EndMarkPhase(cx, &gcmarker, gckind);
SweepPhase(cx, &gcmarker, gckind);
}
#ifdef JS_THREADSAFE
@ -2741,7 +2731,7 @@ AutoGCSession::~AutoGCSession()
* js_GC excludes any pointers we use during the marking implementation.
*/
static JS_NEVER_INLINE void
GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_PARAM)
GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
{
JSRuntime *rt = cx->runtime;
@ -2803,7 +2793,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
}
#endif
MarkAndSweep(cx, gckind GCTIMER_ARG);
MarkAndSweep(cx, gckind);
#ifdef JS_THREADSAFE
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
@ -2825,14 +2815,8 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind GCTIMER_P
(*c)->setGCLastBytes((*c)->gcBytes, gckind);
}
struct GCCrashData
{
int isRegen;
int isCompartment;
};
void
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Reason reason)
{
JSRuntime *rt = cx->runtime;
@ -2852,22 +2836,7 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
RecordNativeStackTopForGC(cx);
GCCrashData crashData;
crashData.isRegen = rt->shapeGen & SHAPE_OVERFLOW_BIT;
crashData.isCompartment = !!comp;
crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
GCTIMER_BEGIN(rt, comp);
struct AutoGCProbe {
JSCompartment *comp;
AutoGCProbe(JSCompartment *comp) : comp(comp) {
Probes::GCStart(comp);
}
~AutoGCProbe() {
Probes::GCEnd(comp); /* background thread may still be sweeping */
}
} autoGCProbe(comp);
gcstats::AutoGC agc(rt->gcStats, comp, reason);
do {
/*
@ -2885,7 +2854,7 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
/* Lock out other GC allocator and collector invocations. */
AutoLockGC lock(rt);
rt->gcPoke = false;
GCCycle(cx, comp, gckind GCTIMER_ARG);
GCCycle(cx, comp, gckind);
}
/* We re-sample the callback again as the finalizers can change it. */
@ -2901,9 +2870,6 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
rt->gcNextFullGCTime = PRMJ_Now() + GC_IDLE_FULL_SPAN;
rt->gcChunkAllocationSinceLastGC = false;
GCTIMER_END(gckind == GC_LAST_CONTEXT);
crash::SnapshotGCStack();
}
namespace js {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше