зеркало из https://github.com/mozilla/pjs.git
merge m-c to fx-team
This commit is contained in:
Коммит
6035ebe12b
|
@ -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()
|
||||
|
|
28
configure.in
28
configure.in
|
@ -7126,17 +7126,6 @@ if test -n "$MOZ_TRACEVIS"; then
|
|||
AC_DEFINE(MOZ_TRACEVIS)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use GCTimer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(gctimer,
|
||||
[ --enable-gctimer Enable GC timer (default=no)],
|
||||
MOZ_GCTIMER=1,
|
||||
MOZ_GCTIMER= )
|
||||
if test -n "$MOZ_GCTIMER"; then
|
||||
AC_DEFINE(MOZ_GCTIMER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl ETW - Event Tracing for Windows
|
||||
dnl ========================================================
|
||||
|
@ -7404,6 +7393,23 @@ if test -z "$SKIP_LIBRARY_CHECKS"; then
|
|||
MOZ_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace))
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl JIT observers
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_WITH_STRING(jitreport-granularity,
|
||||
[ --jitreport-granularity=N
|
||||
Default granularity at which to report JIT code
|
||||
to external tools
|
||||
0 - no info
|
||||
1 - code ranges for whole functions only
|
||||
2 - per-line information
|
||||
3 - per-op information],
|
||||
JITREPORT_GRANULARITY=$withval,
|
||||
JITREPORT_GRANULARITY=3)
|
||||
|
||||
AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY)
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Misc. Options
|
||||
|
|
|
@ -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">¬Cached.title;</h1>
|
||||
<h1 id="et_netOffline">&netOffline.title;</h1>
|
||||
<h1 id="et_netInterrupt">&netInterrupt.title;</h1>
|
||||
<h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
|
||||
|
@ -348,6 +349,7 @@
|
|||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
<div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
|
||||
<div id="ed_netReset">&netReset.longDesc;</div>
|
||||
<div id="ed_notCached">¬Cached.longDesc;</div>
|
||||
<div id="ed_netOffline">&netOffline.longDesc2;</div>
|
||||
<div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
|
||||
<div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
|
||||
|
|
|
@ -120,6 +120,8 @@ _TEST_FILES = \
|
|||
662200a.html \
|
||||
662200b.html \
|
||||
662200c.html \
|
||||
test_bug690056.xul \
|
||||
bug690056_window.xul \
|
||||
$(NULL)
|
||||
|
||||
_DOCSHELL_SUBHARNESS = \
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<window id="690056Test"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
width="600"
|
||||
height="600"
|
||||
onload="setTimeout(nextTest,0);"
|
||||
title="bug 6500056 test">
|
||||
|
||||
<script type="application/javascript" src= "chrome://mochikit/content/chrome-harness.js" />
|
||||
<script type="application/javascript" src="docshell_helpers.js" />
|
||||
<script type="application/javascript"><![CDATA[
|
||||
var tests = testIterator();
|
||||
|
||||
function nextTest() {
|
||||
tests.next();
|
||||
}
|
||||
|
||||
// Makes sure that we fire the visibilitychange events
|
||||
function testIterator() {
|
||||
// Enable bfcache
|
||||
enableBFCache(8);
|
||||
|
||||
// Load something for a start
|
||||
doPageNavigation({
|
||||
uri: 'data:text/html,<title>initial load</title>',
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Now load a new page
|
||||
doPageNavigation({
|
||||
uri: 'data:text/html,<title>new load</title>',
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
// No visibilitychange events fired for initial pageload
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: false }, // false on initial load
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Now go back
|
||||
doPageNavigation({
|
||||
back: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// And forward
|
||||
doPageNavigation({
|
||||
forward: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
function generateDetector(state, hidden, title, name) {
|
||||
var detector = function (event) {
|
||||
is(event.target.mozHidden, hidden,
|
||||
name + " hidden value does not match");
|
||||
is(event.target.mozVisibilityState, state,
|
||||
name + " state value does not match");
|
||||
is(event.target.title, title,
|
||||
name + " title value does not match");
|
||||
document.getElementById("content")
|
||||
.removeEventListener("mozvisibilitychange",
|
||||
detector,
|
||||
true);
|
||||
nextTest();
|
||||
}
|
||||
|
||||
document.getElementById("content")
|
||||
.addEventListener("mozvisibilitychange", detector, true);
|
||||
}
|
||||
|
||||
generateDetector("hidden", true, "new load", "Going hidden");
|
||||
|
||||
// Now flip our docshell to not active
|
||||
document.getElementById("content").docShellIsActive = false;
|
||||
yield;
|
||||
|
||||
// And navigate back; there should be no visibility state transitions
|
||||
doPageNavigation({
|
||||
back: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
{ type: "pageshow",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
],
|
||||
unexpectedEvents: [ "mozvisibilitychange" ],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
generateDetector("visible", false, "initial load", "Going visible");
|
||||
|
||||
// Now set the docshell active again
|
||||
document.getElementById("content").docShellIsActive = true;
|
||||
yield;
|
||||
|
||||
// And forward
|
||||
doPageNavigation({
|
||||
forward: true,
|
||||
eventsToListenFor: [ "pageshow", "pagehide", "mozvisibilitychange" ],
|
||||
expectedEvents: [ { type: "pagehide",
|
||||
title: "initial load",
|
||||
persisted: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "initial load",
|
||||
visibilityState: "hidden",
|
||||
hidden: true },
|
||||
{ type: "mozvisibilitychange",
|
||||
title: "new load",
|
||||
visibilityState: "visible",
|
||||
hidden: false },
|
||||
{ type: "pageshow",
|
||||
title: "new load",
|
||||
persisted: true },
|
||||
],
|
||||
onNavComplete: nextTest
|
||||
});
|
||||
yield;
|
||||
|
||||
// Tell the framework the test is finished. Include the final 'yield'
|
||||
// statement to prevent a StopIteration exception from being thrown.
|
||||
finish();
|
||||
yield;
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<browser type="content-primary" flex="1" id="content" src="about:blank"/>
|
||||
</window>
|
|
@ -18,6 +18,8 @@ const NAV_RELOAD = 4;
|
|||
|
||||
var gExpectedEvents; // an array of events which are expected to
|
||||
// be triggered by this navigation
|
||||
var gUnexpectedEvents; // an array of event names which are NOT expected
|
||||
// to be triggered by this navigation
|
||||
var gFinalEvent; // true if the last expected event has fired
|
||||
var gUrisNotInBFCache = []; // an array of uri's which shouldn't be stored
|
||||
// in the bfcache
|
||||
|
@ -95,6 +97,8 @@ function doPageNavigation(params) {
|
|||
params.eventsToListenFor : ["pageshow"];
|
||||
gExpectedEvents = typeof(params.eventsToListenFor) == "undefined" ||
|
||||
eventsToListenFor.length == 0 ? undefined : params.expectedEvents;
|
||||
gUnexpectedEvents = typeof(params.eventsToListenFor) == "undefined" ||
|
||||
eventsToListenFor.length == 0 ? undefined : params.unexpectedEvents;
|
||||
let preventBFCache = (typeof[params.preventBFCache] == "undefined") ?
|
||||
false : params.preventBFCache;
|
||||
let waitOnly = (typeof(params.waitForEventsOnly) == "boolean"
|
||||
|
@ -129,6 +133,10 @@ function doPageNavigation(params) {
|
|||
if (anExpectedEvent.type == anEventType)
|
||||
eventFound = true;
|
||||
}
|
||||
for each (let anExpectedEventType in gUnexpectedEvents) {
|
||||
if (anExpectedEventType == anEventType)
|
||||
eventFound = true;
|
||||
}
|
||||
if (!eventFound)
|
||||
throw "Event type " + anEventType + " is specified in " +
|
||||
"eventsToListenFor, but not in expectedEvents";
|
||||
|
@ -260,7 +268,12 @@ function pageEventListener(event) {
|
|||
"though it was loaded with .preventBFCache previously\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (typeof(gUnexpectedEvents) != "undefined") {
|
||||
is(gUnexpectedEvents.indexOf(event.type), -1,
|
||||
"Should not get unexpected event " + event.type);
|
||||
}
|
||||
|
||||
// If no expected events were specified, mark the final event as having been
|
||||
// triggered when a pageshow event is fired; this will allow
|
||||
// doPageNavigation() to return.
|
||||
|
@ -301,6 +314,18 @@ function pageEventListener(event) {
|
|||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
if ("visibilityState" in expected) {
|
||||
is(event.originalTarget.mozVisibilityState, expected.visibilityState,
|
||||
"The visibilityState property of the document on page " +
|
||||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
if ("hidden" in expected) {
|
||||
is(event.originalTarget.mozHidden, expected.hidden,
|
||||
"The hidden property of the document on page " +
|
||||
event.originalTarget.location + " had an unexpected value");
|
||||
}
|
||||
|
||||
// If we're out of expected events, let doPageNavigation() return.
|
||||
if (gExpectedEvents.length == 0)
|
||||
setTimeout(function() { gFinalEvent = true; }, 0);
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://global/skin"?>
|
||||
<?xml-stylesheet type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=690056
|
||||
-->
|
||||
<window title="Mozilla Bug 690056"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=690056"
|
||||
target="_blank">Mozilla Bug 690056</a>
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
/** Test for Bug 690056 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
window.open("bug690056_window.xul", "bug690056",
|
||||
"chrome,width=600,height=600");
|
||||
]]>
|
||||
</script>
|
||||
</window>
|
|
@ -97,21 +97,29 @@ public:
|
|||
|
||||
virtual void SetActive(bool aActive)
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"active state is only maintained on outer windows");
|
||||
mIsActive = aActive;
|
||||
}
|
||||
|
||||
bool IsActive()
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"active state is only maintained on outer windows");
|
||||
return mIsActive;
|
||||
}
|
||||
|
||||
virtual void SetIsBackground(bool aIsBackground)
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"background state is only maintained on outer windows");
|
||||
mIsBackground = aIsBackground;
|
||||
}
|
||||
|
||||
bool IsBackground()
|
||||
{
|
||||
NS_PRECONDITION(IsOuterWindow(),
|
||||
"background state is only maintained on outer windows");
|
||||
return mIsBackground;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ interface nsIDOMLocation;
|
|||
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
|
||||
*/
|
||||
|
||||
[scriptable, uuid(3f845f32-cb34-459c-8f79-2dfaa3088bbf)]
|
||||
[scriptable, uuid(CD4CD7C3-C688-4E50-9A72-4A00EABE66AB)]
|
||||
interface nsIDOMDocument : nsIDOMNode
|
||||
{
|
||||
readonly attribute nsIDOMDocumentType doctype;
|
||||
|
@ -411,4 +411,10 @@ interface nsIDOMDocument : nsIDOMNode
|
|||
|
||||
[implicit_jscontext] attribute jsval onmouseenter;
|
||||
[implicit_jscontext] attribute jsval onmouseleave;
|
||||
|
||||
/**
|
||||
* Visibility API implementation.
|
||||
*/
|
||||
readonly attribute boolean mozHidden;
|
||||
readonly attribute DOMString mozVisibilityState;
|
||||
};
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
|
||||
#include "nsIDOMDocument.idl"
|
||||
|
||||
[scriptable, uuid(9f566fd8-8bd7-49eb-be8b-16fb50d00d32)]
|
||||
[scriptable, uuid(BB4D4D76-3802-4191-88E2-933BA609C4E1)]
|
||||
interface nsIDOMXMLDocument : nsIDOMDocument
|
||||
{
|
||||
// DOM Level 3 Load & Save, DocumentLS
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
*/
|
||||
interface nsISelection;
|
||||
|
||||
[scriptable, uuid(280857b8-c52c-455e-8b47-c56ad96614f7)]
|
||||
[scriptable, uuid(C94A5F14-F79F-4054-A93C-E8FF35623460)]
|
||||
interface nsIDOMHTMLDocument : nsIDOMDocument
|
||||
{
|
||||
readonly attribute DOMString URL;
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
interface nsIDOMSVGSVGElement;
|
||||
|
||||
[scriptable, uuid(78ebe55f-631f-4b3b-9eba-c3689ff5ccbc)]
|
||||
[scriptable, uuid(B3806DF6-7ED4-4426-84E6-545EEFE5AA9A)]
|
||||
interface nsIDOMSVGDocument : nsIDOMDocument
|
||||
{
|
||||
readonly attribute DOMString domain;
|
||||
|
|
|
@ -46,6 +46,7 @@ confirmRepostPrompt=To display this page, the application must send information
|
|||
resendButton.label=Resend
|
||||
unknownSocketType=This document cannot be displayed unless you install the Personal Security Manager (PSM). Download and install PSM and try again, or contact your system administrator.
|
||||
netReset=The document contains no data.
|
||||
notCached=This document is no longer available.
|
||||
netOffline=This document cannot be displayed while offline. To go online, uncheck Work Offline from the File menu.
|
||||
isprinting=The document cannot change while Printing or in Print Preview.
|
||||
deniedPortAccess=Access to the port number given has been disabled for security reasons.
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
<!ENTITY netInterrupt.title "Data Transfer Interrupted">
|
||||
<!ENTITY netInterrupt.longDesc "<p>The browser connected successfully, but the connection was interrupted while transferring information. Please try again.</p><ul><li>Are you unable to browse other sites? Check the computer's network connection.</li><li>Still having trouble? Consult your network administrator or Internet provider for assistance.</li></ul>">
|
||||
|
||||
<!ENTITY notCached.title "Document Expired">
|
||||
<!ENTITY notCached.longDesc "<p>The requested document is not available in the browser's cache.</p><ul><li>As a security precuation, the browser does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
|
||||
|
||||
<!ENTITY netOffline.title "Offline Mode">
|
||||
<!ENTITY netOffline.longDesc2 "<p>The browser is operating in its offline mode and cannot connect to the requested item.</p><ul><li>Is the computer connected to an active network?</li><li>Press "Try Again" to switch to online mode and reload the page.</li></ul>">
|
||||
|
||||
|
|
|
@ -160,9 +160,6 @@ static JSBool
|
|||
NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
||||
JSObject **objp);
|
||||
|
||||
static JSBool
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp);
|
||||
|
||||
static void
|
||||
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj);
|
||||
|
||||
|
@ -183,7 +180,7 @@ static JSClass sNPObjectJSWrapperClass =
|
|||
NPObjWrapper_AddProperty, NPObjWrapper_DelProperty,
|
||||
NPObjWrapper_GetProperty, NPObjWrapper_SetProperty,
|
||||
(JSEnumerateOp)NPObjWrapper_newEnumerate,
|
||||
(JSResolveOp)NPObjWrapper_NewResolve, NPObjWrapper_Convert,
|
||||
(JSResolveOp)NPObjWrapper_NewResolve, JS_ConvertStub,
|
||||
NPObjWrapper_Finalize, nsnull, nsnull, NPObjWrapper_Call,
|
||||
NPObjWrapper_Construct, nsnull, nsnull
|
||||
};
|
||||
|
@ -1683,18 +1680,6 @@ NPObjWrapper_NewResolve(JSContext *cx, JSObject *obj, jsid id, uintN flags,
|
|||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
NPObjWrapper_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
||||
{
|
||||
// The sole reason we implement this hook is to prevent the JS
|
||||
// engine from calling valueOf() on NPObject's. Some NPObject's may
|
||||
// actually implement a method named valueOf, but it's unlikely to
|
||||
// behave as the JS engine expects it to. IOW, this is an empty hook
|
||||
// that overrides what the default hook does.
|
||||
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
NPObjWrapper_Finalize(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
|
@ -2195,6 +2180,9 @@ NPObjectMember_Convert(JSContext *cx, JSObject *obj, JSType type, jsval *vp)
|
|||
case JSTYPE_BOOLEAN:
|
||||
case JSTYPE_OBJECT:
|
||||
*vp = memberPrivate->fieldValue;
|
||||
if (!JSVAL_IS_PRIMITIVE(*vp)) {
|
||||
return JS_ConvertStub(cx, JSVAL_TO_OBJECT(*vp), type, vp);
|
||||
}
|
||||
return JS_TRUE;
|
||||
case JSTYPE_FUNCTION:
|
||||
// Leave this to NPObjectMember_Call.
|
||||
|
|
|
@ -46,6 +46,7 @@ include $(topsrcdir)/config/rules.mk
|
|||
|
||||
_MOCHITEST_FILES = \
|
||||
utils.js \
|
||||
test_defaultValue.html \
|
||||
test_getauthenticationinfo.html \
|
||||
test_npobject_getters.html \
|
||||
test_npruntime_npnevaluate.html \
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>NPObject [[DefaultValue]] implementation</title>
|
||||
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
|
||||
<body onload="run()">
|
||||
|
||||
<embed id="plugin" type="application/x-test" wmode="window"></embed>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function run() {
|
||||
var plugin = document.getElementById("plugin");
|
||||
var pluginProto = Object.getPrototypeOf(plugin);
|
||||
|
||||
plugin.propertyAndMethod = {};
|
||||
plugin.propertyAndMethod + "baz";
|
||||
ok(true, "|plugin.propertyAndMethod + \"baz\"| shouldn't assert");
|
||||
pluginProto.propertyAndMethod = {};
|
||||
pluginProto.propertyAndMethod + "quux";
|
||||
ok(true, "|pluginProto.propertyAndMethod + \"quux\"| shouldn't assert");
|
||||
|
||||
plugin + "foo";
|
||||
ok(true, "|plugin + \"foo\"| shouldn't assert");
|
||||
pluginProto + "bar";
|
||||
ok(true, "|pluginProto + \"bar\"| shouldn't assert");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -9,8 +9,6 @@
|
|||
<body>
|
||||
<p id="display"></p>
|
||||
|
||||
<iframe id="subframe" src="npruntime_identifiers_subpage.html"></iframe>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
////
|
||||
// This test exercises NP identifiers by querying the reflector to make sure
|
||||
|
@ -20,8 +18,6 @@
|
|||
|
||||
var testsRun = 0;
|
||||
|
||||
document.getElementById('subframe').addEventListener('load', doTest, false);
|
||||
|
||||
function doTest() {
|
||||
SpecialPowers.gc();
|
||||
|
||||
|
@ -56,5 +52,8 @@
|
|||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<iframe id="subframe" src="npruntime_identifiers_subpage.html" onload="doTest()"></iframe>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include "Events.h"
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ abstract public class GeckoApp
|
|||
|
||||
public static AbsoluteLayout mainLayout;
|
||||
public static GeckoSurfaceView surfaceView;
|
||||
public static SurfaceView cameraView;
|
||||
public static GeckoApp mAppContext;
|
||||
public static boolean mFullscreen = false;
|
||||
public static File sGREDir = null;
|
||||
|
@ -377,6 +378,11 @@ abstract public class GeckoApp
|
|||
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
|
||||
WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
|
||||
if (cameraView == null) {
|
||||
cameraView = new SurfaceView(this);
|
||||
cameraView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
|
||||
}
|
||||
|
||||
if (surfaceView == null)
|
||||
surfaceView = new GeckoSurfaceView(this);
|
||||
else
|
||||
|
@ -388,6 +394,10 @@ abstract public class GeckoApp
|
|||
AbsoluteLayout.LayoutParams.MATCH_PARENT,
|
||||
0,
|
||||
0));
|
||||
|
||||
// Some phones (eg. nexus S) need at least a 8x16 preview size
|
||||
mainLayout.addView(cameraView, new AbsoluteLayout.LayoutParams(8, 16, 0, 0));
|
||||
|
||||
setContentView(mainLayout,
|
||||
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
|
||||
ViewGroup.LayoutParams.FILL_PARENT));
|
||||
|
|
|
@ -1531,7 +1531,7 @@ public class GeckoAppShell
|
|||
|
||||
static int kPreferedFps = 25;
|
||||
static byte[] sCameraBuffer = null;
|
||||
|
||||
|
||||
static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) {
|
||||
Log.i("GeckoAppJava", "initCamera(" + aContentType + ", " + aWidth + "x" + aHeight + ") on thread " + Thread.currentThread().getId());
|
||||
|
||||
|
@ -1585,6 +1585,14 @@ public class GeckoAppShell
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
sCamera.setPreviewDisplay(GeckoApp.cameraView.getHolder());
|
||||
} catch(IOException e) {
|
||||
Log.e("GeckoAppJava", "Error setPreviewDisplay:", e);
|
||||
} catch(RuntimeException e) {
|
||||
Log.e("GeckoAppJava", "Error setPreviewDisplay:", e);
|
||||
}
|
||||
|
||||
sCamera.setParameters(params);
|
||||
sCameraBuffer = new byte[(bufferSize * 12) / 8];
|
||||
sCamera.addCallbackBuffer(sCameraBuffer);
|
||||
|
|
|
@ -46,9 +46,7 @@ MODULE = embedcomponents
|
|||
LIBRARY_NAME = windowwatcher_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
|
||||
|
||||
CPPSRCS = \
|
||||
nsWWJSUtils.cpp \
|
||||
nsWindowWatcher.cpp \
|
||||
nsAutoWindowStateHelper.cpp \
|
||||
$(NULL)
|
||||
|
@ -62,5 +60,7 @@ endif
|
|||
# static lib.
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
# For nsJSUtils
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/base
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* This file is a small subset of nsJSUtils utility functions,
|
||||
from the dom directory.
|
||||
*/
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsWWJSUtils.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
||||
nsIScriptGlobalObject *
|
||||
nsWWJSUtils::GetStaticScriptGlobal(JSContext* aContext, JSObject* aObj)
|
||||
{
|
||||
nsISupports* supports;
|
||||
JSClass* clazz;
|
||||
JSObject* parent;
|
||||
JSObject* glob = aObj; // starting point for search
|
||||
|
||||
if (!glob)
|
||||
return nsnull;
|
||||
|
||||
while (nsnull != (parent = JS_GetParent(aContext, glob)))
|
||||
glob = parent;
|
||||
|
||||
clazz = JS_GET_CLASS(aContext, glob);
|
||||
|
||||
if (!clazz ||
|
||||
!(clazz->flags & JSCLASS_HAS_PRIVATE) ||
|
||||
!(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
|
||||
!(supports = (nsISupports*) JS_GetPrivate(aContext, glob))) {
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(supports));
|
||||
NS_ENSURE_TRUE(wrapper, nsnull);
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryWrappedNative(wrapper));
|
||||
|
||||
// This will return a pointer to something we're about to release,
|
||||
// but that's ok here.
|
||||
return sgo;
|
||||
}
|
||||
|
||||
nsIScriptContext *
|
||||
nsWWJSUtils::GetDynamicScriptContext(JSContext *aContext)
|
||||
{
|
||||
return GetScriptContextFromJSContext(aContext);
|
||||
}
|
||||
|
||||
nsIScriptGlobalObject *
|
||||
nsWWJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
|
||||
{
|
||||
nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
|
||||
if (!scriptCX)
|
||||
return nsnull;
|
||||
return scriptCX->GetGlobalObject();
|
||||
}
|
||||
|
||||
nsIScriptContext *
|
||||
nsWWJSUtils::GetStaticScriptContext(JSContext* aContext,
|
||||
JSObject* aObj)
|
||||
{
|
||||
nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aContext, aObj);
|
||||
if (!nativeGlobal)
|
||||
return nsnull;
|
||||
return nativeGlobal->GetContext();
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include "nsCRT.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsWWJSUtils.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "plstr.h"
|
||||
|
||||
#include "nsIBaseWindow.h"
|
||||
|
@ -316,7 +316,7 @@ nsresult JSContextAutoPopper::Push(JSContext *cx)
|
|||
// Save cx in mContext to indicate need to pop.
|
||||
if (cx && NS_SUCCEEDED(mService->Push(cx))) {
|
||||
mContext = cx;
|
||||
mContextKungFuDeathGrip = nsWWJSUtils::GetDynamicScriptContext(cx);
|
||||
mContextKungFuDeathGrip = nsJSUtils::GetDynamicScriptContext(cx);
|
||||
}
|
||||
}
|
||||
return mContext ? NS_OK : NS_ERROR_FAILURE;
|
||||
|
@ -925,7 +925,7 @@ nsWindowWatcher::OpenWindowJSInternal(nsIDOMWindow *aParent,
|
|||
|
||||
// get its document, if any
|
||||
if (stack && NS_SUCCEEDED(stack->Peek(&ccx)) && ccx) {
|
||||
nsIScriptGlobalObject *sgo = nsWWJSUtils::GetDynamicScriptGlobal(ccx);
|
||||
nsIScriptGlobalObject *sgo = nsJSUtils::GetDynamicScriptGlobal(ccx);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> w(do_QueryInterface(sgo));
|
||||
if (w) {
|
||||
|
@ -1374,7 +1374,7 @@ nsWindowWatcher::URIfromURL(const char *aURL,
|
|||
in nsGlobalWindow.cpp.) */
|
||||
JSContext *cx = GetJSContextFromCallStack();
|
||||
if (cx) {
|
||||
nsIScriptContext *scriptcx = nsWWJSUtils::GetDynamicScriptContext(cx);
|
||||
nsIScriptContext *scriptcx = nsJSUtils::GetDynamicScriptContext(cx);
|
||||
if (scriptcx) {
|
||||
baseWindow = do_QueryInterface(scriptcx->GetGlobalObject());
|
||||
}
|
||||
|
@ -1717,7 +1717,7 @@ nsWindowWatcher::GetCallerTreeItem(nsIDocShellTreeItem* aParentItem)
|
|||
|
||||
if (cx) {
|
||||
nsCOMPtr<nsIWebNavigation> callerWebNav =
|
||||
do_GetInterface(nsWWJSUtils::GetDynamicScriptGlobal(cx));
|
||||
do_GetInterface(nsJSUtils::GetDynamicScriptGlobal(cx));
|
||||
|
||||
if (callerWebNav) {
|
||||
CallQueryInterface(callerWebNav, &callerItem);
|
||||
|
|
|
@ -147,8 +147,6 @@ ThebesLayerBufferOGL::RenderTo(const nsIntPoint& aOffset,
|
|||
|
||||
if (passes == 2) {
|
||||
ComponentAlphaTextureLayerProgram *alphaProgram;
|
||||
NS_ASSERTION(!mTexImage->IsRGB() && !mTexImageOnWhite->IsRGB(),
|
||||
"Only BGR image surported with component alpha (currently!)");
|
||||
if (pass == 1) {
|
||||
alphaProgram = aManager->GetComponentAlphaPass1LayerProgram();
|
||||
gl()->fBlendFuncSeparate(LOCAL_GL_ZERO, LOCAL_GL_ONE_MINUS_SRC_COLOR,
|
||||
|
|
|
@ -775,7 +775,6 @@ TiledTextureImage::DirectUpdate(gfxASurface* aSurf, const nsIntRegion& aRegion,
|
|||
aFrom + nsIntPoint(xPos, yPos));
|
||||
}
|
||||
mShaderType = mImages[0]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[0]->IsRGB();
|
||||
mTextureState = Valid;
|
||||
return result;
|
||||
}
|
||||
|
@ -888,7 +887,6 @@ TiledTextureImage::EndUpdate()
|
|||
mInUpdate = PR_FALSE;
|
||||
mTextureState = Valid;
|
||||
mShaderType = mImages[mCurrentImage]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[mCurrentImage]->IsRGB();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -916,7 +914,6 @@ TiledTextureImage::EndUpdate()
|
|||
mUpdateSurface = nsnull;
|
||||
mInUpdate = PR_FALSE;
|
||||
mShaderType = mImages[0]->GetShaderProgramType();
|
||||
mIsRGBFormat = mImages[0]->IsRGB();
|
||||
mTextureState = Valid;
|
||||
}
|
||||
|
||||
|
|
|
@ -321,8 +321,6 @@ public:
|
|||
virtual bool InUpdate() const = 0;
|
||||
GLenum GetWrapMode() const { return mWrapMode; }
|
||||
|
||||
bool IsRGB() const { return mIsRGBFormat; }
|
||||
|
||||
void SetFilter(gfxPattern::GraphicsFilter aFilter) { mFilter = aFilter; }
|
||||
|
||||
protected:
|
||||
|
@ -340,7 +338,6 @@ protected:
|
|||
: mSize(aSize)
|
||||
, mWrapMode(aWrapMode)
|
||||
, mContentType(aContentType)
|
||||
, mIsRGBFormat(aIsRGB)
|
||||
{}
|
||||
|
||||
/**
|
||||
|
@ -352,7 +349,6 @@ protected:
|
|||
nsIntSize mSize;
|
||||
GLenum mWrapMode;
|
||||
ContentType mContentType;
|
||||
bool mIsRGBFormat;
|
||||
ShaderProgramType mShaderType;
|
||||
gfxPattern::GraphicsFilter mFilter;
|
||||
};
|
||||
|
|
|
@ -1207,7 +1207,7 @@ public:
|
|||
// for RGB24. No easy way to upload that to GL.
|
||||
//
|
||||
// Note that if we start using RGB565 here, we'll need to
|
||||
// watch for a) setting mIsRGBFormat to TRUE; and b) getting
|
||||
// watch for a) setting the correct format; and b) getting
|
||||
// the stride right.
|
||||
if (mUpdateFormat == gfxASurface::ImageFormatRGB24) {
|
||||
mUpdateFormat = gfxASurface::ImageFormatARGB32;
|
||||
|
@ -1275,9 +1275,6 @@ public:
|
|||
return mUpdateSurface;
|
||||
}
|
||||
|
||||
// if we get this far, then we're using Cairo's byte order
|
||||
mIsRGBFormat = PR_FALSE;
|
||||
|
||||
//printf_stderr("creating image surface %dx%d format %d\n", mUpdateRect.width, mUpdateRect.height, mUpdateFormat);
|
||||
|
||||
mUpdateSurface =
|
||||
|
@ -1646,7 +1643,6 @@ public:
|
|||
}
|
||||
|
||||
mBackingSurface = xsurface;
|
||||
mIsRGBFormat = PR_TRUE;
|
||||
#endif
|
||||
|
||||
return mBackingSurface != nsnull;
|
||||
|
|
|
@ -801,15 +801,26 @@ gfxRect gfx3DMatrix::ProjectRectBounds(const gfxRect& aRect) const
|
|||
|
||||
gfxPoint3D gfx3DMatrix::GetNormalVector() const
|
||||
{
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0));
|
||||
gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0));
|
||||
gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0));
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0));
|
||||
gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0));
|
||||
gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0));
|
||||
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
gfxPoint3D ab = b - a;
|
||||
gfxPoint3D ac = c - a;
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
gfxPoint3D ab = b - a;
|
||||
gfxPoint3D ac = c - a;
|
||||
|
||||
return ac.CrossProduct(ab);
|
||||
return ac.CrossProduct(ab);
|
||||
}
|
||||
|
||||
bool gfx3DMatrix::IsBackfaceVisible() const
|
||||
{
|
||||
// Inverse()._33 < 0;
|
||||
gfxFloat det = Determinant();
|
||||
float _33 = _12*_24*_41 - _14*_22*_41 +
|
||||
_14*_21*_42 - _11*_24*_42 -
|
||||
_12*_21*_44 + _11*_22*_44;
|
||||
return (_33 * det) < 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -306,6 +306,12 @@ public:
|
|||
*/
|
||||
gfxPoint3D GetNormalVector() const;
|
||||
|
||||
/**
|
||||
* Returns true if a plane transformed by this matrix will
|
||||
* have it's back face visible.
|
||||
*/
|
||||
bool IsBackfaceVisible() const;
|
||||
|
||||
/**
|
||||
* Check if matrix is singular (no inverse exists).
|
||||
*/
|
||||
|
|
|
@ -101,6 +101,10 @@ using namespace mozilla::ipc::windows;
|
|||
|
||||
// pulled from widget's nsAppShell
|
||||
extern const PRUnichar* kAppShellEventId;
|
||||
#if defined(ACCESSIBILITY)
|
||||
// pulled from accessibility's win utils
|
||||
extern const PRUnichar* kPropNameTabContent;
|
||||
#endif
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -379,6 +383,14 @@ WindowIsDeferredWindow(HWND hWnd)
|
|||
return false;
|
||||
}
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
// Tab content creates a window that responds to accessible WM_GETOBJECT
|
||||
// calls. This window can safely be ignored.
|
||||
if (::GetPropW(hWnd, kPropNameTabContent)) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Common mozilla windows we must defer messages to.
|
||||
nsDependentString className(buffer, length);
|
||||
if (StringBeginsWith(className, NS_LITERAL_STRING("Mozilla")) ||
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "jscntxt.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jscntxt.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
#include "mozilla/jetpack/JetpackActorCommon.h"
|
||||
#include "mozilla/jetpack/PJetpack.h"
|
||||
|
|
|
@ -43,9 +43,8 @@
|
|||
#ifndef jshashtable_h_
|
||||
#define jshashtable_h_
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsutil.h"
|
||||
#include "TemplateLib.h"
|
||||
#include "Utility.h"
|
||||
|
||||
namespace js {
|
||||
|
|
@ -14,18 +14,19 @@
|
|||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* July 16, 2009.
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Corporation.
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Luke Wagner <lw@mozilla.com>
|
||||
* Luke Wagner <luke@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
|
@ -37,20 +38,20 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jstl_h_
|
||||
#define jstl_h_
|
||||
#ifndef js_template_lib_h__
|
||||
#define js_template_lib_h__
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "mozilla/Types.h"
|
||||
#include "jsstdint.h"
|
||||
|
||||
#include <new>
|
||||
#include <string.h>
|
||||
/*
|
||||
* Library of reusable template meta-functions (that is, functions on types and
|
||||
* compile-time values). Meta-functions are placed inside the 'tl' namespace to
|
||||
* avoid conflict with non-meta functions that logically have the same name
|
||||
* (e.g., js::tl::Min vs. js::Min).
|
||||
*/
|
||||
|
||||
namespace js {
|
||||
|
||||
/* JavaScript Template Library. */
|
||||
namespace tl {
|
||||
|
||||
/* Compute min/max/clamp. */
|
||||
|
@ -178,270 +179,6 @@ template <bool cond, typename T, T v1, T v2> struct If { static const T r
|
|||
template <typename T, T v1, T v2> struct If<false, T, v1, v2> { static const T result = v2; };
|
||||
|
||||
} /* namespace tl */
|
||||
|
||||
/* Useful for implementing containers that assert non-reentrancy */
|
||||
class ReentrancyGuard
|
||||
{
|
||||
/* ReentrancyGuard is not copyable. */
|
||||
ReentrancyGuard(const ReentrancyGuard &);
|
||||
void operator=(const ReentrancyGuard &);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool &entered;
|
||||
#endif
|
||||
public:
|
||||
template <class T>
|
||||
#ifdef DEBUG
|
||||
ReentrancyGuard(T &obj)
|
||||
: entered(obj.entered)
|
||||
#else
|
||||
ReentrancyGuard(T &/*obj*/)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!entered);
|
||||
entered = true;
|
||||
#endif
|
||||
}
|
||||
~ReentrancyGuard()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
entered = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Round x up to the nearest power of 2. This function assumes that the most
|
||||
* significant bit of x is not set, which would lead to overflow.
|
||||
*/
|
||||
STATIC_POSTCONDITION_ASSUME(return >= x)
|
||||
JS_ALWAYS_INLINE size_t
|
||||
RoundUpPow2(size_t x)
|
||||
{
|
||||
size_t log2 = JS_CEILING_LOG2W(x);
|
||||
JS_ASSERT(log2 < tl::BitSize<size_t>::result);
|
||||
size_t result = size_t(1) << log2;
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class AlignedPtrAndFlag
|
||||
{
|
||||
uintptr_t bits;
|
||||
|
||||
public:
|
||||
AlignedPtrAndFlag(T *t, bool flag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag);
|
||||
}
|
||||
|
||||
T *ptr() const {
|
||||
return (T *)(bits & ~uintptr_t(1));
|
||||
}
|
||||
|
||||
bool flag() const {
|
||||
return (bits & 1) != 0;
|
||||
}
|
||||
|
||||
void setPtr(T *t) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | uintptr_t(flag());
|
||||
}
|
||||
|
||||
void setFlag() {
|
||||
bits |= 1;
|
||||
}
|
||||
|
||||
void unsetFlag() {
|
||||
bits &= ~uintptr_t(1);
|
||||
}
|
||||
|
||||
void set(T *t, bool flag) {
|
||||
JS_ASSERT((uintptr_t(t) & 1) == 0);
|
||||
bits = uintptr_t(t) | flag;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
static inline void
|
||||
Reverse(T *beg, T *end)
|
||||
{
|
||||
while (beg != end) {
|
||||
if (--end == beg)
|
||||
return;
|
||||
T tmp = *beg;
|
||||
*beg = *end;
|
||||
*end = tmp;
|
||||
++beg;
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T *
|
||||
Find(T *beg, T *end, const T &v)
|
||||
{
|
||||
for (T *p = beg; p != end; ++p) {
|
||||
if (*p == v)
|
||||
return p;
|
||||
}
|
||||
return end;
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
static inline typename Container::ElementType *
|
||||
Find(Container &c, const typename Container::ElementType &v)
|
||||
{
|
||||
return Find(c.begin(), c.end(), v);
|
||||
}
|
||||
|
||||
template <typename InputIterT, typename CallableT>
|
||||
void
|
||||
ForEach(InputIterT begin, InputIterT end, CallableT f)
|
||||
{
|
||||
for (; begin != end; ++begin)
|
||||
f(*begin);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Min(T t1, T t2)
|
||||
{
|
||||
return t1 < t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static inline T
|
||||
Max(T t1, T t2)
|
||||
{
|
||||
return t1 > t2 ? t1 : t2;
|
||||
}
|
||||
|
||||
/* Allows a const variable to be initialized after its declaration. */
|
||||
template <class T>
|
||||
static T&
|
||||
InitConst(const T &t)
|
||||
{
|
||||
return const_cast<T &>(t);
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
JS_ALWAYS_INLINE T &
|
||||
ImplicitCast(U &u)
|
||||
{
|
||||
T &t = u;
|
||||
return t;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class AutoScopedAssign
|
||||
{
|
||||
private:
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
T *addr;
|
||||
T old;
|
||||
|
||||
public:
|
||||
AutoScopedAssign(T *addr, const T &value JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: addr(addr), old(*addr)
|
||||
{
|
||||
JS_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
*addr = value;
|
||||
}
|
||||
|
||||
~AutoScopedAssign() { *addr = old; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class AlreadyIncRefed
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
RefCountable *obj;
|
||||
|
||||
public:
|
||||
explicit AlreadyIncRefed(RefCountable *obj) : obj(obj) {}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class NeedsIncRef
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
RefCountable *obj;
|
||||
|
||||
public:
|
||||
explicit NeedsIncRef(RefCountable *obj) : obj(obj) {}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
template <class RefCountable>
|
||||
class AutoRefCount
|
||||
{
|
||||
typedef RefCountable *****ConvertibleToBool;
|
||||
|
||||
JSContext *const cx;
|
||||
RefCountable *obj;
|
||||
|
||||
AutoRefCount(const AutoRefCount &);
|
||||
void operator=(const AutoRefCount &);
|
||||
|
||||
public:
|
||||
explicit AutoRefCount(JSContext *cx)
|
||||
: cx(cx), obj(NULL)
|
||||
{}
|
||||
|
||||
AutoRefCount(JSContext *cx, NeedsIncRef<RefCountable> aobj)
|
||||
: cx(cx), obj(aobj.get())
|
||||
{
|
||||
if (obj)
|
||||
obj->incref(cx);
|
||||
}
|
||||
|
||||
AutoRefCount(JSContext *cx, AlreadyIncRefed<RefCountable> aobj)
|
||||
: cx(cx), obj(aobj.get())
|
||||
{}
|
||||
|
||||
~AutoRefCount() {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
}
|
||||
|
||||
void reset(NeedsIncRef<RefCountable> aobj) {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
obj = aobj.get();
|
||||
if (obj)
|
||||
obj->incref(cx);
|
||||
}
|
||||
|
||||
void reset(AlreadyIncRefed<RefCountable> aobj) {
|
||||
if (obj)
|
||||
obj->decref(cx);
|
||||
obj = aobj.get();
|
||||
}
|
||||
|
||||
bool null() const { return obj == NULL; }
|
||||
operator ConvertibleToBool() const { return (ConvertibleToBool)obj; }
|
||||
|
||||
RefCountable *operator->() const { JS_ASSERT(!null()); return obj; }
|
||||
RefCountable &operator*() const { JS_ASSERT(!null()); return *obj; }
|
||||
RefCountable *get() const { return obj; }
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jstl_h_ */
|
||||
#endif /* js_template_lib_h__ */
|
|
@ -0,0 +1,945 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef js_utility_h__
|
||||
#define js_utility_h__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
/* The public JS engine namespace. */
|
||||
namespace JS {}
|
||||
|
||||
/* The mozilla-shared reusable template/utility namespace. */
|
||||
namespace mozilla {}
|
||||
|
||||
/* The private JS engine namespace. */
|
||||
namespace js {
|
||||
|
||||
/* The private namespace is a superset of the public/shared namespaces. */
|
||||
using namespace JS;
|
||||
using namespace mozilla;
|
||||
|
||||
} /* namespace js */
|
||||
#endif /* __cplusplus */
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
* Pattern used to overwrite freed memory. If you are accessing an object with
|
||||
* this pattern, you probably have a dangling pointer.
|
||||
*/
|
||||
#define JS_FREE_PATTERN 0xDA
|
||||
|
||||
/* JS_ASSERT */
|
||||
#ifdef DEBUG
|
||||
# define JS_ASSERT(expr) \
|
||||
((expr) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
|
||||
# define JS_ASSERT_IF(cond, expr) \
|
||||
((!(cond) || (expr)) ? (void)0 : JS_Assert(#expr, __FILE__, __LINE__))
|
||||
# define JS_NOT_REACHED(reason) \
|
||||
JS_Assert(reason, __FILE__, __LINE__)
|
||||
# define JS_ALWAYS_TRUE(expr) JS_ASSERT(expr)
|
||||
# define JS_ALWAYS_FALSE(expr) JS_ASSERT(!(expr))
|
||||
# ifdef JS_THREADSAFE
|
||||
# define JS_THREADSAFE_ASSERT(expr) JS_ASSERT(expr)
|
||||
# else
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
# endif
|
||||
#else
|
||||
# define JS_ASSERT(expr) ((void) 0)
|
||||
# define JS_ASSERT_IF(cond,expr) ((void) 0)
|
||||
# define JS_NOT_REACHED(reason)
|
||||
# define JS_ALWAYS_TRUE(expr) ((void) (expr))
|
||||
# define JS_ALWAYS_FALSE(expr) ((void) (expr))
|
||||
# define JS_THREADSAFE_ASSERT(expr) ((void) 0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* JS_STATIC_ASSERT
|
||||
*
|
||||
* A compile-time assert. "cond" must be a constant expression. The macro can
|
||||
* be used only in places where an "extern" declaration is allowed.
|
||||
*/
|
||||
#ifdef __SUNPRO_CC
|
||||
/*
|
||||
* Sun Studio C++ compiler has a bug
|
||||
* "sizeof expression not accepted as size of array parameter"
|
||||
* It happens when js_static_assert() function is declared inside functions.
|
||||
* The bug number is 6688515. It is not public yet.
|
||||
* Therefore, for Sun Studio, declare js_static_assert as an array instead.
|
||||
*/
|
||||
# define JS_STATIC_ASSERT(cond) extern char js_static_assert[(cond) ? 1 : -1]
|
||||
#else
|
||||
# ifdef __COUNTER__
|
||||
# define JS_STATIC_ASSERT_GLUE1(x,y) x##y
|
||||
# define JS_STATIC_ASSERT_GLUE(x,y) JS_STATIC_ASSERT_GLUE1(x,y)
|
||||
# define JS_STATIC_ASSERT(cond) \
|
||||
typedef int JS_STATIC_ASSERT_GLUE(js_static_assert, __COUNTER__)[(cond) ? 1 : -1]
|
||||
# else
|
||||
# define JS_STATIC_ASSERT(cond) extern void js_static_assert(int arg[(cond) ? 1 : -1])
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define JS_STATIC_ASSERT_IF(cond, expr) JS_STATIC_ASSERT(!(cond) || (expr))
|
||||
|
||||
/*
|
||||
* Abort the process in a non-graceful manner. This will cause a core file,
|
||||
* call to the debugger or other moral equivalent as well as causing the
|
||||
* entire process to stop.
|
||||
*/
|
||||
extern JS_PUBLIC_API(void) JS_Abort(void);
|
||||
|
||||
/*
|
||||
* Custom allocator support for SpiderMonkey
|
||||
*/
|
||||
#if defined JS_USE_CUSTOM_ALLOCATOR
|
||||
# include "jscustomallocator.h"
|
||||
#else
|
||||
# ifdef DEBUG
|
||||
/*
|
||||
* In order to test OOM conditions, when the shell command-line option
|
||||
* |-A NUM| is passed, we fail continuously after the NUM'th allocation.
|
||||
*/
|
||||
extern JS_PUBLIC_DATA(JSUint32) OOM_maxAllocations; /* set from shell/js.cpp */
|
||||
extern JS_PUBLIC_DATA(JSUint32) OOM_counter; /* data race, who cares. */
|
||||
# define JS_OOM_POSSIBLY_FAIL() \
|
||||
do \
|
||||
{ \
|
||||
if (OOM_counter++ >= OOM_maxAllocations) { \
|
||||
return NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# else
|
||||
# define JS_OOM_POSSIBLY_FAIL() do {} while(0)
|
||||
# endif
|
||||
|
||||
/*
|
||||
* SpiderMonkey code should not be calling these allocation functions directly.
|
||||
* Instead, all calls should go through JSRuntime, JSContext or OffTheBooks.
|
||||
* However, js_free() can be called directly.
|
||||
*/
|
||||
static JS_INLINE void* js_malloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return malloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_calloc(size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return calloc(bytes, 1);
|
||||
}
|
||||
|
||||
static JS_INLINE void* js_realloc(void* p, size_t bytes)
|
||||
{
|
||||
JS_OOM_POSSIBLY_FAIL();
|
||||
return realloc(p, bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void js_free(void* p)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
#endif/* JS_USE_CUSTOM_ALLOCATOR */
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
*
|
||||
* With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129.
|
||||
*
|
||||
* SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856.
|
||||
*/
|
||||
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
|
||||
unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
|
||||
unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
|
||||
# pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward(&idx, (unsigned long)val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse(&idx, (unsigned long)val);
|
||||
return (int)(31-idx);
|
||||
}
|
||||
# define js_bitscan_ctz32(val) __BitScanForward32(val)
|
||||
# define js_bitscan_clz32(val) __BitScanReverse32(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_X64)
|
||||
unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask);
|
||||
# pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward64(&idx, val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse64(&idx, val);
|
||||
return (int)(63-idx);
|
||||
}
|
||||
# define js_bitscan_ctz64(val) __BitScanForward64(val)
|
||||
# define js_bitscan_clz64(val) __BitScanReverse64(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
#endif
|
||||
#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
|
||||
# define js_bitscan_ctz32(val) __builtin_ctz(val)
|
||||
# define js_bitscan_clz32(val) __builtin_clz(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
# if (JS_BYTES_PER_WORD == 8)
|
||||
# define js_bitscan_ctz64(val) __builtin_ctzll(val)
|
||||
# define js_bitscan_clz64(val) __builtin_clzll(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_CeilingLog2: Compute the log of the least power of
|
||||
** 2 greater than or equal to _n. The result is returned in _log2.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)).
|
||||
* The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is
|
||||
* undefined.
|
||||
*/
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
unsigned int j_ = (unsigned int)(_n); \
|
||||
(_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) & ((j_)-1)) \
|
||||
(_log2) += 1; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_FloorLog2: Compute the log of the greatest power of
|
||||
** 2 less than or equal to _n. The result is returned in _log2.
|
||||
**
|
||||
** This is equivalent to finding the highest set bit in the word.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)).
|
||||
* Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1
|
||||
* to ensure 0 result when _n == 0.
|
||||
*/
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
(_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
* a version of JS_CeilingLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size.
|
||||
*/
|
||||
#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the greatest power of 2 less than or equal to n.
|
||||
* This is a version of JS_FloorLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size and requires that n != 0.
|
||||
*/
|
||||
#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
|
||||
# else
|
||||
# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n))
|
||||
# endif
|
||||
#elif JS_BYTES_PER_WORD == 8
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN64
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
|
||||
# else
|
||||
extern size_t js_FloorLog2wImpl(size_t n);
|
||||
# endif
|
||||
#else
|
||||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <new>
|
||||
|
||||
/*
|
||||
* User guide to memory management within SpiderMonkey:
|
||||
*
|
||||
* Quick tips:
|
||||
*
|
||||
* Allocation:
|
||||
* - Prefer to allocate using JSContext:
|
||||
* cx->{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* - If no JSContext is available, use a JSRuntime:
|
||||
* rt->{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* - As a last resort, use unaccounted allocation ("OffTheBooks"):
|
||||
* js::OffTheBooks::{malloc_,realloc_,calloc_,new_,array_new}
|
||||
*
|
||||
* Deallocation:
|
||||
* - When the deallocation occurs on a slow path, use:
|
||||
* Foreground::{free_,delete_,array_delete}
|
||||
*
|
||||
* - Otherwise deallocate on a background thread using a JSContext:
|
||||
* cx->{free_,delete_,array_delete}
|
||||
*
|
||||
* - If no JSContext is available, use a JSRuntime:
|
||||
* rt->{free_,delete_,array_delete}
|
||||
*
|
||||
* - As a last resort, use UnwantedForeground deallocation:
|
||||
* js::UnwantedForeground::{free_,delete_,array_delete}
|
||||
*
|
||||
* General tips:
|
||||
*
|
||||
* - Mixing and matching these allocators is allowed (you may free memory
|
||||
* allocated by any allocator, with any deallocator).
|
||||
*
|
||||
* - Never, ever use normal C/C++ memory management:
|
||||
* malloc, free, new, new[], delete, operator new, etc.
|
||||
*
|
||||
* - Never, ever use low-level SpiderMonkey allocators:
|
||||
* js_malloc(), js_free(), js_calloc(), js_realloc()
|
||||
* Their use is reserved for the other memory managers.
|
||||
*
|
||||
* - Classes which have private constructors or destructors should have
|
||||
* JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR added to their
|
||||
* declaration.
|
||||
*
|
||||
* Details:
|
||||
*
|
||||
* Using vanilla new/new[] is unsafe in SpiderMonkey because they throw on
|
||||
* failure instead of returning NULL, which is what SpiderMonkey expects.
|
||||
* (Even overriding them is unsafe, as the system's C++ runtime library may
|
||||
* throw, which we do not support. We also can't just use the 'nothrow'
|
||||
* variant of new/new[], because we want to mediate *all* allocations
|
||||
* within SpiderMonkey, to satisfy any embedders using
|
||||
* JS_USE_CUSTOM_ALLOCATOR.)
|
||||
*
|
||||
* JSContexts and JSRuntimes keep track of memory allocated, and use this
|
||||
* accounting to schedule GC. OffTheBooks does not. We'd like to remove
|
||||
* OffTheBooks allocations as much as possible (bug 636558).
|
||||
*
|
||||
* On allocation failure, a JSContext correctly reports an error, which a
|
||||
* JSRuntime and OffTheBooks does not.
|
||||
*
|
||||
* A JSContext deallocates in a background thread. A JSRuntime might
|
||||
* deallocate in the background in the future, but does not now. Foreground
|
||||
* deallocation is preferable on slow paths. UnwantedForeground deallocations
|
||||
* occur where we have no JSContext or JSRuntime, and the deallocation is not
|
||||
* on a slow path. We want to remove UnwantedForeground deallocations (bug
|
||||
* 636561).
|
||||
*
|
||||
* JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR makes the allocation
|
||||
* classes friends with your class, giving them access to private
|
||||
* constructors and destructors.
|
||||
*
|
||||
* |make check| does a source level check on the number of uses OffTheBooks,
|
||||
* UnwantedForeground, js_malloc, js_free etc, to prevent regressions. If you
|
||||
* really must add one, update Makefile.in, and run |make check|.
|
||||
*
|
||||
* |make check| also statically prevents the use of vanilla new/new[].
|
||||
*/
|
||||
|
||||
#define JS_NEW_BODY(allocator, t, parms) \
|
||||
void *memory = allocator(sizeof(t)); \
|
||||
return memory ? new(memory) t parms : NULL;
|
||||
|
||||
/*
|
||||
* Given a class which should provide new_() methods, add
|
||||
* JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This
|
||||
* adds new_()s with up to 12 parameters. Add more versions of new_ below if
|
||||
* you need more than 12 parameters.
|
||||
*
|
||||
* Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
|
||||
* or the build will break.
|
||||
*/
|
||||
#define JS_DECLARE_NEW_METHODS(ALLOCATOR, QUALIFIERS)\
|
||||
template <class T>\
|
||||
QUALIFIERS T *new_() {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, ())\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1>\
|
||||
QUALIFIERS T *new_(P1 p1) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))\
|
||||
}\
|
||||
\
|
||||
template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\
|
||||
QUALIFIERS T *new_(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8, P9 p9, P10 p10, P11 p11, P12 p12) {\
|
||||
JS_NEW_BODY(ALLOCATOR, T, (p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12))\
|
||||
}\
|
||||
static const int JSMinAlignment = 8;\
|
||||
template <class T>\
|
||||
QUALIFIERS T *array_new(size_t n) {\
|
||||
/* The length is stored just before the vector memory. */\
|
||||
uint64 numBytes64 = uint64(JSMinAlignment) + uint64(sizeof(T)) * uint64(n);\
|
||||
size_t numBytes = size_t(numBytes64);\
|
||||
if (numBytes64 != numBytes) {\
|
||||
JS_ASSERT(0); /* we want to know if this happens in debug builds */\
|
||||
return NULL;\
|
||||
}\
|
||||
void *memory = ALLOCATOR(numBytes);\
|
||||
if (!memory)\
|
||||
return NULL;\
|
||||
*(size_t *)memory = n;\
|
||||
memory = (void*)(uintptr_t(memory) + JSMinAlignment);\
|
||||
return new(memory) T[n];\
|
||||
}\
|
||||
|
||||
|
||||
#define JS_DECLARE_DELETE_METHODS(DEALLOCATOR, QUALIFIERS)\
|
||||
template <class T>\
|
||||
QUALIFIERS void delete_(T *p) {\
|
||||
if (p) {\
|
||||
p->~T();\
|
||||
DEALLOCATOR(p);\
|
||||
}\
|
||||
}\
|
||||
\
|
||||
template <class T>\
|
||||
QUALIFIERS void array_delete(T *p) {\
|
||||
if (p) {\
|
||||
void* p0 = (void *)(uintptr_t(p) - js::OffTheBooks::JSMinAlignment);\
|
||||
size_t n = *(size_t *)p0;\
|
||||
for (size_t i = 0; i < n; i++)\
|
||||
(p + i)->~T();\
|
||||
DEALLOCATOR(p0);\
|
||||
}\
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* In general, all allocations should go through a JSContext or JSRuntime, so
|
||||
* that the garbage collector knows how much memory has been allocated. In
|
||||
* cases where it is difficult to use a JSContext or JSRuntime, OffTheBooks can
|
||||
* be used, though this is undesirable.
|
||||
*/
|
||||
namespace js {
|
||||
|
||||
class OffTheBooks {
|
||||
public:
|
||||
JS_DECLARE_NEW_METHODS(::js_malloc, JS_ALWAYS_INLINE static)
|
||||
|
||||
static JS_INLINE void* malloc_(size_t bytes) {
|
||||
return ::js_malloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* calloc_(size_t bytes) {
|
||||
return ::js_calloc(bytes);
|
||||
}
|
||||
|
||||
static JS_INLINE void* realloc_(void* p, size_t bytes) {
|
||||
return ::js_realloc(p, bytes);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* We generally prefer deallocating using JSContext because it can happen in
|
||||
* the background. On slow paths, we may prefer foreground allocation.
|
||||
*/
|
||||
class Foreground {
|
||||
public:
|
||||
/* See parentheses comment above. */
|
||||
static JS_ALWAYS_INLINE void free_(void* p) {
|
||||
::js_free(p);
|
||||
}
|
||||
|
||||
JS_DECLARE_DELETE_METHODS(::js_free, JS_ALWAYS_INLINE static)
|
||||
};
|
||||
|
||||
class UnwantedForeground : public Foreground {
|
||||
};
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Note lack of ; in JSRuntime below. This is intentional so "calling" this
|
||||
* looks "normal".
|
||||
*/
|
||||
#define JS_DECLARE_ALLOCATION_FRIENDS_FOR_PRIVATE_CONSTRUCTOR \
|
||||
friend class js::OffTheBooks;\
|
||||
friend class js::Foreground;\
|
||||
friend class js::UnwantedForeground;\
|
||||
friend struct ::JSContext;\
|
||||
friend struct ::JSRuntime
|
||||
|
||||
/*
|
||||
* The following classes are designed to cause assertions to detect
|
||||
* inadvertent use of guard objects as temporaries. In other words,
|
||||
* when we have a guard object whose only purpose is its constructor and
|
||||
* destructor (and is never otherwise referenced), the intended use
|
||||
* might be:
|
||||
* JSAutoTempValueRooter tvr(cx, 1, &val);
|
||||
* but is is easy to accidentally write:
|
||||
* JSAutoTempValueRooter(cx, 1, &val);
|
||||
* which compiles just fine, but runs the destructor well before the
|
||||
* intended time.
|
||||
*
|
||||
* They work by adding (#ifdef DEBUG) an additional parameter to the
|
||||
* guard object's constructor, with a default value, so that users of
|
||||
* the guard object's API do not need to do anything. The default value
|
||||
* of this parameter is a temporary object. C++ (ISO/IEC 14882:1998),
|
||||
* section 12.2 [class.temporary], clauses 4 and 5 seem to assume a
|
||||
* guarantee that temporaries are destroyed in the reverse of their
|
||||
* construction order, but I actually can't find a statement that that
|
||||
* is true in the general case (beyond the two specific cases mentioned
|
||||
* there). However, it seems to be true.
|
||||
*
|
||||
* These classes are intended to be used only via the macros immediately
|
||||
* below them:
|
||||
* JS_DECL_USE_GUARD_OBJECT_NOTIFIER declares (ifdef DEBUG) a member
|
||||
* variable, and should be put where a declaration of a private
|
||||
* member variable would be placed.
|
||||
* JS_GUARD_OBJECT_NOTIFIER_PARAM should be placed at the end of the
|
||||
* parameters to each constructor of the guard object; it declares
|
||||
* (ifdef DEBUG) an additional parameter.
|
||||
* JS_GUARD_OBJECT_NOTIFIER_INIT is a statement that belongs in each
|
||||
* constructor. It uses the parameter declared by
|
||||
* JS_GUARD_OBJECT_NOTIFIER_PARAM.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
class JS_FRIEND_API(JSGuardObjectNotifier)
|
||||
{
|
||||
private:
|
||||
bool* mStatementDone;
|
||||
public:
|
||||
JSGuardObjectNotifier() : mStatementDone(NULL) {}
|
||||
|
||||
~JSGuardObjectNotifier() {
|
||||
*mStatementDone = true;
|
||||
}
|
||||
|
||||
void setStatementDone(bool *aStatementDone) {
|
||||
mStatementDone = aStatementDone;
|
||||
}
|
||||
};
|
||||
|
||||
class JS_FRIEND_API(JSGuardObjectNotificationReceiver)
|
||||
{
|
||||
private:
|
||||
bool mStatementDone;
|
||||
public:
|
||||
JSGuardObjectNotificationReceiver() : mStatementDone(false) {}
|
||||
|
||||
~JSGuardObjectNotificationReceiver() {
|
||||
/*
|
||||
* Assert that the guard object was not used as a temporary.
|
||||
* (Note that this assert might also fire if Init is not called
|
||||
* because the guard object's implementation is not using the
|
||||
* above macros correctly.)
|
||||
*/
|
||||
JS_ASSERT(mStatementDone);
|
||||
}
|
||||
|
||||
void Init(const JSGuardObjectNotifier &aNotifier) {
|
||||
/*
|
||||
* aNotifier is passed as a const reference so that we can pass a
|
||||
* temporary, but we really intend it as non-const
|
||||
*/
|
||||
const_cast<JSGuardObjectNotifier&>(aNotifier).
|
||||
setStatementDone(&mStatementDone);
|
||||
}
|
||||
};
|
||||
|
||||
#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER \
|
||||
JSGuardObjectNotificationReceiver _mCheckNotUsedAsTemporary;
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM \
|
||||
, const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier()
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT \
|
||||
, const JSGuardObjectNotifier& _notifier
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM0 \
|
||||
const JSGuardObjectNotifier& _notifier = JSGuardObjectNotifier()
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_INIT \
|
||||
JS_BEGIN_MACRO _mCheckNotUsedAsTemporary.Init(_notifier); JS_END_MACRO
|
||||
|
||||
#else /* defined(DEBUG) */
|
||||
|
||||
#define JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM_NO_INIT
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_PARAM0
|
||||
#define JS_GUARD_OBJECT_NOTIFIER_INIT JS_BEGIN_MACRO JS_END_MACRO
|
||||
|
||||
#endif /* !defined(DEBUG) */
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* "Move" References
|
||||
*
|
||||
* Some types can be copied much more efficiently if we know the original's
|
||||
* value need not be preserved --- that is, if we are doing a "move", not a
|
||||
* "copy". For example, if we have:
|
||||
*
|
||||
* Vector<T> u;
|
||||
* Vector<T> v(u);
|
||||
*
|
||||
* the constructor for v must apply a copy constructor to each element of u ---
|
||||
* taking time linear in the length of u. However, if we know we will not need u
|
||||
* any more once v has been initialized, then we could initialize v very
|
||||
* efficiently simply by stealing u's dynamically allocated buffer and giving it
|
||||
* to v --- a constant-time operation, regardless of the size of u.
|
||||
*
|
||||
* Moves often appear in container implementations. For example, when we append
|
||||
* to a vector, we may need to resize its buffer. This entails moving each of
|
||||
* its extant elements from the old, smaller buffer to the new, larger buffer.
|
||||
* But once the elements have been migrated, we're just going to throw away the
|
||||
* old buffer; we don't care if they still have their values. So if the vector's
|
||||
* element type can implement "move" more efficiently than "copy", the vector
|
||||
* resizing should by all means use a "move" operation. Hash tables also need to
|
||||
* be resized.
|
||||
*
|
||||
* The details of the optimization, and whether it's worth applying, vary from
|
||||
* one type to the next. And while some constructor calls are moves, many really
|
||||
* are copies, and can't be optimized this way. So we need:
|
||||
*
|
||||
* 1) a way for a particular invocation of a copy constructor to say that it's
|
||||
* really a move, and that the value of the original isn't important
|
||||
* afterwards (althought it must still be safe to destroy); and
|
||||
*
|
||||
* 2) a way for a type (like Vector) to announce that it can be moved more
|
||||
* efficiently than it can be copied, and provide an implementation of that
|
||||
* move operation.
|
||||
*
|
||||
* The Move(T &) function takes a reference to a T, and returns an MoveRef<T>
|
||||
* referring to the same value; that's 1). An MoveRef<T> is simply a reference
|
||||
* to a T, annotated to say that a copy constructor applied to it may move that
|
||||
* T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
|
||||
* should perform a more efficient move, instead of a copy, providing 2).
|
||||
*
|
||||
* So, where we might define a copy constructor for a class C like this:
|
||||
*
|
||||
* C(const C &rhs) { ... copy rhs to this ... }
|
||||
*
|
||||
* we would declare a move constructor like this:
|
||||
*
|
||||
* C(MoveRef<C> rhs) { ... move rhs to this ... }
|
||||
*
|
||||
* And where we might perform a copy like this:
|
||||
*
|
||||
* C c2(c1);
|
||||
*
|
||||
* we would perform a move like this:
|
||||
*
|
||||
* C c2(Move(c1))
|
||||
*
|
||||
* Note that MoveRef<T> implicitly converts to T &, so you can pass an
|
||||
* MoveRef<T> to an ordinary copy constructor for a type that doesn't support a
|
||||
* special move constructor, and you'll just get a copy. This means that
|
||||
* templates can use Move whenever they know they won't use the original value
|
||||
* any more, even if they're not sure whether the type at hand has a specialized
|
||||
* move constructor. If it doesn't, the MoveRef<T> will just convert to a T &,
|
||||
* and the ordinary copy constructor will apply.
|
||||
*
|
||||
* A class with a move constructor can also provide a move assignment operator,
|
||||
* which runs this's destructor, and then applies the move constructor to
|
||||
* *this's memory. A typical definition:
|
||||
*
|
||||
* C &operator=(MoveRef<C> rhs) {
|
||||
* this->~C();
|
||||
* new(this) C(rhs);
|
||||
* return *this;
|
||||
* }
|
||||
*
|
||||
* With that in place, one can write move assignments like this:
|
||||
*
|
||||
* c2 = Move(c1);
|
||||
*
|
||||
* This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
|
||||
* destructible state.
|
||||
*
|
||||
* This header file defines MoveRef and Move in the js namespace. It's up to
|
||||
* individual containers to annotate moves as such, by calling Move; and it's up
|
||||
* to individual types to define move constructors.
|
||||
*
|
||||
* One hint: if you're writing a move constructor where the type has members
|
||||
* that should be moved themselves, it's much nicer to write this:
|
||||
*
|
||||
* C(MoveRef<C> c) : x(c->x), y(c->y) { }
|
||||
*
|
||||
* than the equivalent:
|
||||
*
|
||||
* C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
|
||||
*
|
||||
* especially since GNU C++ fails to notice that this does indeed initialize x
|
||||
* and y, which may matter if they're const.
|
||||
*/
|
||||
template<typename T>
|
||||
class MoveRef {
|
||||
public:
|
||||
typedef T Referent;
|
||||
explicit MoveRef(T &t) : pointer(&t) { }
|
||||
T &operator*() const { return *pointer; }
|
||||
T *operator->() const { return pointer; }
|
||||
#ifdef __GXX_EXPERIMENTAL_CXX0X__
|
||||
/*
|
||||
* If MoveRef is used in a rvalue position (which is expected), we can
|
||||
* end up in a situation where, without this ifdef, we would try to pass
|
||||
* a T& to a move constructor, which fails. It is not clear if the compiler
|
||||
* should instead use the copy constructor, but for now this lets us build
|
||||
* with clang. See bug 689066 and llvm.org/pr11003 for the details.
|
||||
* Note: We can probably remove MoveRef completely once we are comfortable
|
||||
* using c++11.
|
||||
*/
|
||||
operator T&& () const { return static_cast<T&&>(*pointer); }
|
||||
#else
|
||||
operator T& () const { return *pointer; }
|
||||
#endif
|
||||
private:
|
||||
T *pointer;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
MoveRef<T> Move(T &t) { return MoveRef<T>(t); }
|
||||
|
||||
template<typename T>
|
||||
MoveRef<T> Move(const T &t) { return MoveRef<T>(const_cast<T &>(t)); }
|
||||
|
||||
/* Useful for implementing containers that assert non-reentrancy */
|
||||
class ReentrancyGuard
|
||||
{
|
||||
/* ReentrancyGuard is not copyable. */
|
||||
ReentrancyGuard(const ReentrancyGuard &);
|
||||
void operator=(const ReentrancyGuard &);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool &entered;
|
||||
#endif
|
||||
public:
|
||||
template <class T>
|
||||
#ifdef DEBUG
|
||||
ReentrancyGuard(T &obj)
|
||||
: entered(obj.entered)
|
||||
#else
|
||||
ReentrancyGuard(T &/*obj*/)
|
||||
#endif
|
||||
{
|
||||
#ifdef DEBUG
|
||||
JS_ASSERT(!entered);
|
||||
entered = true;
|
||||
#endif
|
||||
}
|
||||
~ReentrancyGuard()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
entered = false;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Round x up to the nearest power of 2. This function assumes that the most
|
||||
* significant bit of x is not set, which would lead to overflow.
|
||||
*/
|
||||
JS_ALWAYS_INLINE size_t
|
||||
RoundUpPow2(size_t x)
|
||||
{
|
||||
return size_t(1) << JS_CEILING_LOG2W(x);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
||||
/*
|
||||
* This signature is for malloc_usable_size-like functions used to measure
|
||||
* memory usage. A return value of zero indicates that the size is unknown,
|
||||
* and so a fall-back computation should be done for the size.
|
||||
*/
|
||||
typedef size_t(*JSUsableSizeFun)(void *p);
|
||||
|
||||
/* sixgill annotation defines */
|
||||
#ifndef HAVE_STATIC_ANNOTATIONS
|
||||
# define HAVE_STATIC_ANNOTATIONS
|
||||
# ifdef XGILL_PLUGIN
|
||||
# define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
|
||||
# define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
|
||||
# define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
|
||||
# define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
|
||||
# define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
|
||||
# define STATIC_PASTE2(X,Y) X ## Y
|
||||
# define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y)
|
||||
# define STATIC_ASSERT(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assume_static(#COND), unused)) \
|
||||
int STATIC_PASTE1(assume_static_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) \
|
||||
JS_BEGIN_MACRO \
|
||||
__attribute__((assert_static_runtime(#COND), unused)) \
|
||||
int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \
|
||||
JS_END_MACRO
|
||||
# else /* XGILL_PLUGIN */
|
||||
# define STATIC_PRECONDITION(COND) /* nothing */
|
||||
# define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
|
||||
# define STATIC_POSTCONDITION(COND) /* nothing */
|
||||
# define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
|
||||
# define STATIC_INVARIANT(COND) /* nothing */
|
||||
# define STATIC_INVARIANT_ASSUME(COND) /* nothing */
|
||||
# define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
|
||||
# endif /* XGILL_PLUGIN */
|
||||
# define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
|
||||
#endif /* HAVE_STATIC_ANNOTATIONS */
|
||||
|
||||
#endif /* js_utility_h__ */
|
|
@ -41,10 +41,8 @@
|
|||
#ifndef jsvector_h_
|
||||
#define jsvector_h_
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsutil.h"
|
||||
#include "TemplateLib.h"
|
||||
#include "Utility.h"
|
||||
|
||||
/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
|
||||
#ifdef _MSC_VER
|
||||
|
@ -54,6 +52,9 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
template <class T, size_t N, class AllocPolicy>
|
||||
class Vector;
|
||||
|
||||
/*
|
||||
* This template class provides a default implementation for vector operations
|
||||
* when the element type is not known to be a POD, as judged by IsPodType.
|
|
@ -95,7 +95,14 @@ endif
|
|||
FORCE_STATIC_LIB = 1
|
||||
DIST_INSTALL = 1
|
||||
|
||||
VPATH = $(srcdir)
|
||||
VPATH = \
|
||||
$(srcdir) \
|
||||
$(srcdir)/builtin \
|
||||
$(srcdir)/ds \
|
||||
$(srcdir)/frontend \
|
||||
$(srcdir)/gc \
|
||||
$(srcdir)/vm \
|
||||
$(NULL)
|
||||
|
||||
CPPSRCS = \
|
||||
jsalloc.cpp \
|
||||
|
@ -163,6 +170,7 @@ CPPSRCS = \
|
|||
RegExpObject.cpp \
|
||||
RegExpStatics.cpp \
|
||||
RegExp.cpp \
|
||||
Statistics.cpp \
|
||||
Unicode.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -177,7 +185,6 @@ INSTALLED_HEADERS = \
|
|||
jsalloc.h \
|
||||
jsapi.h \
|
||||
jsatom.h \
|
||||
jsbit.h \
|
||||
jsclass.h \
|
||||
jsclist.h \
|
||||
jsclone.h \
|
||||
|
@ -202,7 +209,6 @@ INSTALLED_HEADERS = \
|
|||
jsotypes.h \
|
||||
jsproxy.h \
|
||||
jsprf.h \
|
||||
jsprobes.h \
|
||||
jspropertycache.h \
|
||||
jspropertytree.h \
|
||||
jsproto.tbl \
|
||||
|
@ -217,9 +223,6 @@ INSTALLED_HEADERS = \
|
|||
jstypedarray.h \
|
||||
jstypes.h \
|
||||
jsutil.h \
|
||||
jsvector.h \
|
||||
jstl.h \
|
||||
jshashtable.h \
|
||||
jsversion.h \
|
||||
jswrapper.h \
|
||||
jsxdrapi.h \
|
||||
|
@ -228,16 +231,10 @@ INSTALLED_HEADERS = \
|
|||
$(NULL)
|
||||
|
||||
######################################################
|
||||
# BEGIN include sources for the engine subdirectories
|
||||
# BEGIN exported headers that are only exported
|
||||
# because of inclusion by an INSTALLED_HEADER
|
||||
#
|
||||
VPATH += \
|
||||
$(srcdir)/builtin \
|
||||
$(srcdir)/ds \
|
||||
$(srcdir)/frontend \
|
||||
$(srcdir)/vm \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES = vm ds
|
||||
EXPORTS_NAMESPACES += vm ds gc
|
||||
|
||||
EXPORTS_vm = \
|
||||
String.h \
|
||||
|
@ -246,7 +243,32 @@ EXPORTS_vm = \
|
|||
$(NULL)
|
||||
|
||||
EXPORTS_ds = \
|
||||
LifoAlloc.h
|
||||
LifoAlloc.h \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_gc = \
|
||||
Statistics.h \
|
||||
$(NULL)
|
||||
|
||||
######################################################
|
||||
# BEGIN include exported headers from the JS engine
|
||||
#
|
||||
# Ultimately, after cleansing INSTALLED_HEADERS,
|
||||
# these will be the ONLY headers exported by
|
||||
# the js engine
|
||||
#
|
||||
VPATH += \
|
||||
$(srcdir)/../public \
|
||||
$(NULL)
|
||||
|
||||
EXPORTS_NAMESPACES += js
|
||||
|
||||
EXPORTS_js = \
|
||||
HashTable.h \
|
||||
TemplateLib.h \
|
||||
Utility.h \
|
||||
Vector.h \
|
||||
$(NULL)
|
||||
|
||||
###############################################
|
||||
# BEGIN include sources for low-level code shared with Gecko
|
||||
|
@ -259,9 +281,9 @@ EXPORTS_NAMESPACES += mozilla
|
|||
|
||||
EXPORTS_mozilla = \
|
||||
RangedPtr.h \
|
||||
RefPtr.h \
|
||||
Types.h \
|
||||
Util.h \
|
||||
RefPtr.h \
|
||||
Types.h \
|
||||
Util.h \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TRACEJIT
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
#include "AssemblerBuffer.h"
|
||||
#include "jsstdint.h"
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include "methodjit/Logging.h"
|
||||
#define IPFX " %s"
|
||||
|
|
|
@ -28,13 +28,14 @@
|
|||
|
||||
#include <stddef.h> // for ptrdiff_t
|
||||
#include <limits>
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
|
||||
#include "jsalloc.h"
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#include "assembler/wtf/Assertions.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
#if WTF_CPU_SPARC
|
||||
#ifdef linux // bugzilla 502369
|
||||
|
@ -165,10 +166,12 @@ private:
|
|||
};
|
||||
|
||||
class ExecutableAllocator {
|
||||
typedef void (*DestroyCallback)(void* addr, size_t size);
|
||||
enum ProtectionSetting { Writable, Executable };
|
||||
DestroyCallback destroyCallback;
|
||||
|
||||
public:
|
||||
ExecutableAllocator()
|
||||
ExecutableAllocator() : destroyCallback(NULL)
|
||||
{
|
||||
if (!pageSize) {
|
||||
pageSize = determinePageSize();
|
||||
|
@ -221,12 +224,18 @@ public:
|
|||
|
||||
void releasePoolPages(ExecutablePool *pool) {
|
||||
JS_ASSERT(pool->m_allocation.pages);
|
||||
if (destroyCallback)
|
||||
destroyCallback(pool->m_allocation.pages, pool->m_allocation.size);
|
||||
systemRelease(pool->m_allocation);
|
||||
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
|
||||
}
|
||||
|
||||
void getCodeStats(size_t& method, size_t& regexp, size_t& unused) const;
|
||||
|
||||
void setDestroyCallback(DestroyCallback destroyCallback) {
|
||||
this->destroyCallback = destroyCallback;
|
||||
}
|
||||
|
||||
private:
|
||||
static size_t pageSize;
|
||||
static size_t largeAllocSize;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#define SegmentedVector_h
|
||||
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
namespace WTF {
|
||||
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsinfer.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "builtin/RegExp.h"
|
||||
|
||||
|
|
|
@ -4420,28 +4420,6 @@ if test -n "$MOZ_TRACEVIS"; then
|
|||
fi
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use GCTimer
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(gctimer,
|
||||
[ --enable-gctimer Enable GC timer (default=no)],
|
||||
MOZ_GCTIMER=1,
|
||||
MOZ_GCTIMER= )
|
||||
if test -n "$MOZ_GCTIMER"; then
|
||||
AC_DEFINE(MOZ_GCTIMER)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Don't enable GC-TestPilot plumbing
|
||||
dnl ========================================================
|
||||
JSGC_TESTPILOT=1
|
||||
MOZ_ARG_DISABLE_BOOL(gctestpilot,
|
||||
[ --disable-gctestpilot Disable GC TestPilot study hooks],
|
||||
JSGC_TESTPILOT= )
|
||||
if test -n "$JSGC_TESTPILOT"; then
|
||||
AC_DEFINE(JSGC_TESTPILOT)
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl = Use Valgrind
|
||||
dnl ========================================================
|
||||
|
@ -4658,6 +4636,23 @@ if test -z "$SKIP_LIBRARY_CHECKS"; then
|
|||
AC_CHECK_HEADER(unwind.h, AC_CHECK_FUNCS(_Unwind_Backtrace))
|
||||
fi
|
||||
|
||||
dnl ========================================================
|
||||
dnl JIT observers
|
||||
dnl ========================================================
|
||||
|
||||
MOZ_ARG_WITH_STRING(jitreport-granularity,
|
||||
[ --jitreport-granularity=N
|
||||
Default granularity at which to report JIT code
|
||||
to external tools
|
||||
0 - no info
|
||||
1 - code ranges for whole functions only
|
||||
2 - per-line information
|
||||
3 - per-op information],
|
||||
JITREPORT_GRANULARITY=$withval,
|
||||
JITREPORT_GRANULARITY=3)
|
||||
|
||||
AC_DEFINE_UNQUOTED(JS_DEFAULT_JITREPORT_GRANULARITY, $JITREPORT_GRANULARITY)
|
||||
|
||||
dnl ========================================================
|
||||
dnl =
|
||||
dnl = Misc. Options
|
||||
|
|
|
@ -41,10 +41,11 @@
|
|||
|
||||
#include "jscntxt.h"
|
||||
#include "jsapi.h"
|
||||
#include "jshashtable.h"
|
||||
#include "prlink.h"
|
||||
#include "ffi.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
namespace ctypes {
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
#ifndef InlineMap_h__
|
||||
#define InlineMap_h__
|
||||
|
||||
#include "jshashtable.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
|
|
@ -65,6 +65,30 @@ BumpChunk::new_(size_t chunkSize)
|
|||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
BumpChunk::delete_(BumpChunk *chunk)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize);
|
||||
#endif
|
||||
js_free(chunk);
|
||||
}
|
||||
|
||||
bool
|
||||
BumpChunk::canAlloc(size_t n)
|
||||
{
|
||||
char *aligned = AlignPtr(bump);
|
||||
char *bumped = aligned + n;
|
||||
return bumped <= limit && bumped > headerBase();
|
||||
}
|
||||
|
||||
bool
|
||||
BumpChunk::canAllocUnaligned(size_t n)
|
||||
{
|
||||
char *bumped = bump + n;
|
||||
return bumped <= limit && bumped > headerBase();
|
||||
}
|
||||
|
||||
void *
|
||||
BumpChunk::tryAllocUnaligned(size_t n)
|
||||
{
|
||||
|
@ -73,6 +97,7 @@ BumpChunk::tryAllocUnaligned(size_t n)
|
|||
if (newBump > limit)
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(canAllocUnaligned(n));
|
||||
setBump(newBump);
|
||||
return oldBump;
|
||||
}
|
||||
|
@ -136,9 +161,20 @@ LifoAlloc::getOrCreateChunk(size_t n)
|
|||
}
|
||||
|
||||
size_t defaultChunkFreeSpace = defaultChunkSize_ - sizeof(BumpChunk);
|
||||
size_t chunkSize = n > defaultChunkFreeSpace
|
||||
? RoundUpPow2(n + sizeof(BumpChunk))
|
||||
: defaultChunkSize_;
|
||||
size_t chunkSize;
|
||||
if (n > defaultChunkFreeSpace) {
|
||||
size_t allocSizeWithHeader = n + sizeof(BumpChunk);
|
||||
|
||||
/* Guard for overflow. */
|
||||
if (allocSizeWithHeader < n ||
|
||||
(allocSizeWithHeader & (size_t(1) << (tl::BitSize<size_t>::result - 1)))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chunkSize = RoundUpPow2(allocSizeWithHeader);
|
||||
} else {
|
||||
chunkSize = defaultChunkSize_;
|
||||
}
|
||||
|
||||
/* If we get here, we couldn't find an existing BumpChunk to fill the request. */
|
||||
BumpChunk *newChunk = BumpChunk::new_(chunkSize);
|
||||
|
|
|
@ -49,7 +49,8 @@
|
|||
*/
|
||||
|
||||
#include "jsutil.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "js/TemplateLib.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -78,7 +79,8 @@ class BumpChunk
|
|||
BumpChunk *next_;
|
||||
size_t bumpSpaceSize;
|
||||
|
||||
char *base() const { return limit - bumpSpaceSize; }
|
||||
char *headerBase() { return reinterpret_cast<char *>(this); }
|
||||
char *bumpBase() const { return limit - bumpSpaceSize; }
|
||||
|
||||
BumpChunk *thisDuringConstruction() { return this; }
|
||||
|
||||
|
@ -97,7 +99,7 @@ class BumpChunk
|
|||
}
|
||||
|
||||
void setBump(void *ptr) {
|
||||
JS_ASSERT(base() <= ptr);
|
||||
JS_ASSERT(bumpBase() <= ptr);
|
||||
JS_ASSERT(ptr <= limit);
|
||||
DebugOnly<char *> prevBump = bump;
|
||||
bump = static_cast<char *>(ptr);
|
||||
|
@ -109,10 +111,10 @@ class BumpChunk
|
|||
BumpChunk *next() const { return next_; }
|
||||
void setNext(BumpChunk *succ) { next_ = succ; }
|
||||
|
||||
size_t used() const { return bump - base(); }
|
||||
size_t used() const { return bump - bumpBase(); }
|
||||
|
||||
void resetBump() {
|
||||
setBump(reinterpret_cast<char *>(this) + sizeof(BumpChunk));
|
||||
setBump(headerBase() + sizeof(BumpChunk));
|
||||
}
|
||||
|
||||
void *mark() const { return bump; }
|
||||
|
@ -124,25 +126,26 @@ class BumpChunk
|
|||
}
|
||||
|
||||
bool contains(void *mark) const {
|
||||
return base() <= mark && mark <= limit;
|
||||
return bumpBase() <= mark && mark <= limit;
|
||||
}
|
||||
|
||||
bool canAlloc(size_t n) {
|
||||
return AlignPtr(bump) + n <= limit;
|
||||
}
|
||||
|
||||
bool canAllocUnaligned(size_t n) {
|
||||
return bump + n <= limit;
|
||||
}
|
||||
bool canAlloc(size_t n);
|
||||
bool canAllocUnaligned(size_t n);
|
||||
|
||||
/* Try to perform an allocation of size |n|, return null if not possible. */
|
||||
JS_ALWAYS_INLINE
|
||||
void *tryAlloc(size_t n) {
|
||||
char *aligned = AlignPtr(bump);
|
||||
char *newBump = aligned + n;
|
||||
|
||||
if (newBump > limit)
|
||||
return NULL;
|
||||
|
||||
/* Check for overflow. */
|
||||
if (JS_UNLIKELY(newBump < bump))
|
||||
return NULL;
|
||||
|
||||
JS_ASSERT(canAlloc(n)); /* Ensure consistency between "can" and "try". */
|
||||
setBump(newBump);
|
||||
return aligned;
|
||||
}
|
||||
|
@ -156,13 +159,7 @@ class BumpChunk
|
|||
}
|
||||
|
||||
static BumpChunk *new_(size_t chunkSize);
|
||||
|
||||
static void delete_(BumpChunk *chunk) {
|
||||
#ifdef DEBUG
|
||||
memset(chunk, 0xcd, sizeof(*chunk) + chunk->bumpSpaceSize);
|
||||
#endif
|
||||
js_free(chunk);
|
||||
}
|
||||
static void delete_(BumpChunk *chunk);
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
|
|
|
@ -41,9 +41,8 @@
|
|||
#ifndef ParseMaps_h__
|
||||
#define ParseMaps_h__
|
||||
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "mfbt/InlineMap.h"
|
||||
#include "ds/InlineMap.h"
|
||||
#include "js/HashTable.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
|
|
@ -0,0 +1,218 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "jscntxt.h"
|
||||
#include "jsprobes.h"
|
||||
#include "jsutil.h"
|
||||
#include "jscrashformat.h"
|
||||
#include "jscrashreport.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "gc/Statistics.h"
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
Statistics::Statistics(JSRuntime *rt)
|
||||
: runtime(rt)
|
||||
{
|
||||
char *env = getenv("MOZ_GCTIMER");
|
||||
if (!env || strcmp(env, "none") == 0) {
|
||||
fp = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (strcmp(env, "stdout") == 0) {
|
||||
fullFormat = false;
|
||||
fp = stdout;
|
||||
} else if (strcmp(env, "stderr") == 0) {
|
||||
fullFormat = false;
|
||||
fp = stderr;
|
||||
} else {
|
||||
fullFormat = true;
|
||||
|
||||
fp = fopen(env, "a");
|
||||
JS_ASSERT(fp);
|
||||
|
||||
fprintf(fp, " AppTime, Total, Wait, Mark, Sweep, FinObj,"
|
||||
" FinStr, FinScr, FinShp, Destry, End, +Chu, -Chu, T, Reason\n");
|
||||
}
|
||||
|
||||
PodArrayZero(counts);
|
||||
|
||||
startupTime = PRMJ_Now();
|
||||
}
|
||||
|
||||
Statistics::~Statistics()
|
||||
{
|
||||
if (fp && fp != stdout && fp != stderr)
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
struct GCCrashData
|
||||
{
|
||||
int isRegen;
|
||||
int isCompartment;
|
||||
};
|
||||
|
||||
void
|
||||
Statistics::beginGC(JSCompartment *comp, Reason reason)
|
||||
{
|
||||
compartment = comp;
|
||||
|
||||
PodArrayZero(phaseStarts);
|
||||
PodArrayZero(phaseEnds);
|
||||
PodArrayZero(phaseTimes);
|
||||
|
||||
triggerReason = reason;
|
||||
|
||||
beginPhase(PHASE_GC);
|
||||
Probes::GCStart(compartment);
|
||||
|
||||
GCCrashData crashData;
|
||||
crashData.isRegen = runtime->shapeGen & SHAPE_OVERFLOW_BIT;
|
||||
crashData.isCompartment = !!compartment;
|
||||
crash::SaveCrashData(crash::JS_CRASH_TAG_GC, &crashData, sizeof(crashData));
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::t(Phase phase)
|
||||
{
|
||||
return double(phaseTimes[phase]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::beginDelay(Phase phase1, Phase phase2)
|
||||
{
|
||||
return double(phaseStarts[phase1] - phaseStarts[phase2]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
double
|
||||
Statistics::endDelay(Phase phase1, Phase phase2)
|
||||
{
|
||||
return double(phaseEnds[phase1] - phaseEnds[phase2]) / PRMJ_USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::printStats()
|
||||
{
|
||||
if (fullFormat) {
|
||||
/* App , Total, Wait , Mark , Sweep, FinOb, FinSt, FinSc, FinSh, Destry, End */
|
||||
fprintf(fp,
|
||||
"%12.0f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, %6.1f, ",
|
||||
double(phaseStarts[PHASE_GC] - startupTime) / PRMJ_USEC_PER_MSEC,
|
||||
t(PHASE_GC),
|
||||
beginDelay(PHASE_MARK, PHASE_GC),
|
||||
t(PHASE_MARK), t(PHASE_SWEEP),
|
||||
t(PHASE_SWEEP_OBJECT), t(PHASE_SWEEP_STRING),
|
||||
t(PHASE_SWEEP_SCRIPT), t(PHASE_SWEEP_SHAPE),
|
||||
t(PHASE_DESTROY),
|
||||
endDelay(PHASE_GC, PHASE_DESTROY));
|
||||
|
||||
fprintf(fp, "%4d, %4d,", counts[STAT_NEW_CHUNK], counts[STAT_DESTROY_CHUNK]);
|
||||
fprintf(fp, " %s, %s\n", compartment ? "C" : "G", ExplainReason(triggerReason));
|
||||
} else {
|
||||
fprintf(fp, "%f %f %f\n",
|
||||
t(PHASE_GC), t(PHASE_MARK), t(PHASE_SWEEP));
|
||||
}
|
||||
fflush(fp);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endGC()
|
||||
{
|
||||
Probes::GCEnd(compartment);
|
||||
endPhase(PHASE_GC);
|
||||
crash::SnapshotGCStack();
|
||||
|
||||
if (JSAccumulateTelemetryDataCallback cb = runtime->telemetryCallback) {
|
||||
(*cb)(JS_TELEMETRY_GC_REASON, triggerReason);
|
||||
(*cb)(JS_TELEMETRY_GC_IS_COMPARTMENTAL, compartment ? 1 : 0);
|
||||
(*cb)(JS_TELEMETRY_GC_IS_SHAPE_REGEN,
|
||||
runtime->shapeGen & SHAPE_OVERFLOW_BIT ? 1 : 0);
|
||||
(*cb)(JS_TELEMETRY_GC_MS, t(PHASE_GC));
|
||||
(*cb)(JS_TELEMETRY_GC_MARK_MS, t(PHASE_MARK));
|
||||
(*cb)(JS_TELEMETRY_GC_SWEEP_MS, t(PHASE_SWEEP));
|
||||
}
|
||||
|
||||
if (fp)
|
||||
printStats();
|
||||
|
||||
PodArrayZero(counts);
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::beginPhase(Phase phase)
|
||||
{
|
||||
phaseStarts[phase] = PRMJ_Now();
|
||||
|
||||
if (phase == gcstats::PHASE_SWEEP) {
|
||||
Probes::GCStartSweepPhase(NULL);
|
||||
if (!compartment) {
|
||||
for (JSCompartment **c = runtime->compartments.begin();
|
||||
c != runtime->compartments.end(); ++c)
|
||||
{
|
||||
Probes::GCStartSweepPhase(*c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Statistics::endPhase(Phase phase)
|
||||
{
|
||||
phaseEnds[phase] = PRMJ_Now();
|
||||
phaseTimes[phase] += phaseEnds[phase] - phaseStarts[phase];
|
||||
|
||||
if (phase == gcstats::PHASE_SWEEP) {
|
||||
if (!compartment) {
|
||||
for (JSCompartment **c = runtime->compartments.begin();
|
||||
c != runtime->compartments.end(); ++c)
|
||||
{
|
||||
Probes::GCEndSweepPhase(*c);
|
||||
}
|
||||
}
|
||||
Probes::GCEndSweepPhase(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
|
@ -0,0 +1,158 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is SpiderMonkey JavaScript engine.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2011
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsgc_statistics_h___
|
||||
#define jsgc_statistics_h___
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
struct JSCompartment;
|
||||
|
||||
namespace js {
|
||||
namespace gcstats {
|
||||
|
||||
enum Reason {
|
||||
PUBLIC_API,
|
||||
MAYBEGC,
|
||||
LASTCONTEXT,
|
||||
DESTROYCONTEXT,
|
||||
LASTDITCH,
|
||||
TOOMUCHMALLOC,
|
||||
ALLOCTRIGGER,
|
||||
CHUNK,
|
||||
SHAPE,
|
||||
REFILL
|
||||
};
|
||||
static const int NUM_REASONS = REFILL + 1;
|
||||
|
||||
static inline const char *
|
||||
ExplainReason(Reason r)
|
||||
{
|
||||
static const char *strs[] = {" API", "Maybe", "LastC", "DestC", "LastD",
|
||||
"Mallc", "Alloc", "Chunk", "Shape", "Refil"};
|
||||
|
||||
JS_ASSERT(strcmp(strs[SHAPE], "Shape") == 0 &&
|
||||
sizeof(strs) / sizeof(strs[0]) == NUM_REASONS);
|
||||
|
||||
return strs[r];
|
||||
}
|
||||
|
||||
enum Phase {
|
||||
PHASE_GC,
|
||||
PHASE_MARK,
|
||||
PHASE_SWEEP,
|
||||
PHASE_SWEEP_OBJECT,
|
||||
PHASE_SWEEP_STRING,
|
||||
PHASE_SWEEP_SCRIPT,
|
||||
PHASE_SWEEP_SHAPE,
|
||||
PHASE_DESTROY,
|
||||
|
||||
PHASE_LIMIT
|
||||
};
|
||||
|
||||
enum Stat {
|
||||
STAT_NEW_CHUNK,
|
||||
STAT_DESTROY_CHUNK,
|
||||
|
||||
STAT_LIMIT
|
||||
};
|
||||
|
||||
struct Statistics {
|
||||
Statistics(JSRuntime *rt);
|
||||
~Statistics();
|
||||
|
||||
void beginGC(JSCompartment *comp, Reason reason);
|
||||
void endGC();
|
||||
|
||||
void beginPhase(Phase phase);
|
||||
void endPhase(Phase phase);
|
||||
|
||||
void count(Stat s) {
|
||||
JS_ASSERT(s < STAT_LIMIT);
|
||||
counts[s]++;
|
||||
}
|
||||
|
||||
private:
|
||||
JSRuntime *runtime;
|
||||
|
||||
uint64 startupTime;
|
||||
|
||||
FILE *fp;
|
||||
bool fullFormat;
|
||||
|
||||
Reason triggerReason;
|
||||
JSCompartment *compartment;
|
||||
|
||||
uint64 phaseStarts[PHASE_LIMIT];
|
||||
uint64 phaseEnds[PHASE_LIMIT];
|
||||
uint64 phaseTimes[PHASE_LIMIT];
|
||||
unsigned int counts[STAT_LIMIT];
|
||||
|
||||
double t(Phase phase);
|
||||
double beginDelay(Phase phase1, Phase phase2);
|
||||
double endDelay(Phase phase1, Phase phase2);
|
||||
void printStats();
|
||||
};
|
||||
|
||||
struct AutoGC {
|
||||
AutoGC(Statistics &stats, JSCompartment *comp, Reason reason JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginGC(comp, reason); }
|
||||
~AutoGC() { stats.endGC(); }
|
||||
|
||||
Statistics &stats;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
struct AutoPhase {
|
||||
AutoPhase(Statistics &stats, Phase phase JS_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
: stats(stats), phase(phase) { JS_GUARD_OBJECT_NOTIFIER_INIT; stats.beginPhase(phase); }
|
||||
~AutoPhase() { stats.endPhase(phase); }
|
||||
|
||||
Statistics &stats;
|
||||
Phase phase;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
|
||||
} /* namespace gcstats */
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* jsgc_statistics_h___ */
|
|
@ -45,9 +45,9 @@
|
|||
#include "jscntxt.h"
|
||||
#include "jsinfer.h"
|
||||
#include "jsscript.h"
|
||||
#include "jstl.h"
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "js/TemplateLib.h"
|
||||
|
||||
struct JSScript;
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ BEGIN_TEST(testThreadGC_bug590533)
|
|||
* loop. Then run the GC with JSRuntime->gcIsNeeded flag set.
|
||||
*/
|
||||
js::AutoLockGC lock(rt);
|
||||
js::TriggerGC(rt);
|
||||
js::TriggerGC(rt, js::gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_GC(cx);
|
||||
|
|
|
@ -40,7 +40,10 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsalloc.h"
|
||||
|
||||
#include "js/Vector.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -83,7 +83,6 @@
|
|||
#include "jstracer.h"
|
||||
#include "prmjtime.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsweakmap.h"
|
||||
#include "jswrapper.h"
|
||||
#include "jstypedarray.h"
|
||||
|
@ -96,7 +95,6 @@
|
|||
#include "jsobjinlines.h"
|
||||
#include "jsscopeinlines.h"
|
||||
#include "jsscriptinlines.h"
|
||||
#include "assembler/wtf/Platform.h"
|
||||
|
||||
#include "vm/RegExpObject-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
@ -664,6 +662,7 @@ JSRuntime::JSRuntime()
|
|||
gcMode(JSGC_MODE_GLOBAL),
|
||||
gcIsNeeded(0),
|
||||
gcWeakMapList(NULL),
|
||||
gcStats(thisFromCtor()),
|
||||
gcTriggerCompartment(NULL),
|
||||
gcCurrentCompartment(NULL),
|
||||
gcCheckCompartment(NULL),
|
||||
|
@ -696,7 +695,7 @@ JSRuntime::JSRuntime()
|
|||
requestDone(NULL),
|
||||
requestCount(0),
|
||||
gcThread(NULL),
|
||||
gcHelperThread(this),
|
||||
gcHelperThread(thisFromCtor()),
|
||||
rtLock(NULL),
|
||||
# ifdef DEBUG
|
||||
rtLockOwner(0),
|
||||
|
@ -706,6 +705,7 @@ JSRuntime::JSRuntime()
|
|||
debuggerMutations(0),
|
||||
securityCallbacks(NULL),
|
||||
structuredCloneCallbacks(NULL),
|
||||
telemetryCallback(NULL),
|
||||
propertyRemovals(0),
|
||||
scriptFilenameTable(NULL),
|
||||
#ifdef JS_THREADSAFE
|
||||
|
@ -2706,14 +2706,12 @@ JS_CompartmentGC(JSContext *cx, JSCompartment *comp)
|
|||
|
||||
LeaveTrace(cx);
|
||||
|
||||
GCREASON(PUBLIC_API);
|
||||
js_GC(cx, comp, GC_NORMAL);
|
||||
js_GC(cx, comp, GC_NORMAL, gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_GC(JSContext *cx)
|
||||
{
|
||||
GCREASON(PUBLIC_API);
|
||||
JS_CompartmentGC(cx, NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,9 +47,10 @@
|
|||
#include <stdio.h>
|
||||
#include "js-config.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsval.h"
|
||||
|
||||
#include "js/Utility.h"
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/* JS::Value can store a full int32. */
|
||||
|
@ -1696,6 +1697,17 @@ extern JS_PUBLIC_DATA(jsid) JSID_EMPTY;
|
|||
*/
|
||||
#define JSFUN_GENERIC_NATIVE JSFUN_LAMBDA
|
||||
|
||||
/*
|
||||
* The first call to JS_CallOnce by any thread in a process will call 'func'.
|
||||
* Later calls to JS_CallOnce with the same JSCallOnceType object will be
|
||||
* suppressed.
|
||||
*
|
||||
* Equivalently: each distinct JSCallOnceType object will allow one JS_CallOnce
|
||||
* to invoke its JSInitCallback.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_CallOnce(JSCallOnceType *once, JSInitCallback func);
|
||||
|
||||
/*
|
||||
* Microseconds since the epoch, midnight, January 1, 1970 UTC. See the
|
||||
* comment in jstypes.h regarding safe int64 usage.
|
||||
|
|
|
@ -1,258 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Lifetime-based fast allocation, inspired by much prior art, including
|
||||
* "Fast Allocation and Deallocation of Memory Based on Object Lifetimes"
|
||||
* David R. Hanson, Software -- Practice and Experience, Vol. 20(1).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "jsalloc.h"
|
||||
#include "jstypes.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsarena.h"
|
||||
#include "jsprvtd.h"
|
||||
|
||||
using namespace js;
|
||||
|
||||
/* If JSArena's length is a multiple of 8, that ensures its payload is 8-aligned. */
|
||||
JS_STATIC_ASSERT(sizeof(JSArena) % 8 == 0);
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_InitArenaPool(JSArenaPool *pool, const char *name, size_t size, size_t align)
|
||||
{
|
||||
/* Restricting ourselves to some simple alignments keeps things simple. */
|
||||
if (align == 1 || align == 2 || align == 4 || align == 8) {
|
||||
pool->mask = align - 1;
|
||||
} else {
|
||||
/* This shouldn't happen, but set pool->mask reasonably if it does. */
|
||||
JS_NOT_REACHED("JS_InitArenaPool: bad align");
|
||||
pool->mask = 7;
|
||||
}
|
||||
pool->first.next = NULL;
|
||||
/* pool->first is a zero-sized dummy arena that's never allocated from. */
|
||||
pool->first.base = pool->first.avail = pool->first.limit =
|
||||
JS_ARENA_ALIGN(pool, &pool->first + 1);
|
||||
pool->current = &pool->first;
|
||||
pool->arenasize = size;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaAllocate(JSArenaPool *pool, size_t nb)
|
||||
{
|
||||
/*
|
||||
* Search pool from current forward till we find or make enough space.
|
||||
*
|
||||
* NB: subtract nb from a->limit in the loop condition, instead of adding
|
||||
* nb to a->avail, to avoid overflow (possible when running a 32-bit
|
||||
* program on a 64-bit system where the kernel maps the heap up against the
|
||||
* top of the 32-bit address space, see bug 279273). Note that this
|
||||
* necessitates a comparison between nb and a->limit that looks like a
|
||||
* (conceptual) type error but isn't.
|
||||
*/
|
||||
JS_ASSERT((nb & pool->mask) == 0);
|
||||
JSArena *a;
|
||||
/*
|
||||
* Comparing nb to a->limit looks like a (conceptual) type error, but it's
|
||||
* necessary to avoid wrap-around. Yuk.
|
||||
*/
|
||||
for (a = pool->current; nb > a->limit || a->avail > a->limit - nb; pool->current = a) {
|
||||
JSArena **ap = &a->next;
|
||||
if (!*ap) {
|
||||
/* Not enough space in pool, so we must malloc. */
|
||||
size_t gross = sizeof(JSArena) + JS_MAX(nb, pool->arenasize);
|
||||
a = (JSArena *) OffTheBooks::malloc_(gross);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
a->next = NULL;
|
||||
a->base = a->avail = jsuword(a) + sizeof(JSArena);
|
||||
/*
|
||||
* Because malloc returns 8-aligned pointers and sizeof(JSArena) is
|
||||
* a multiple of 8, a->base will always be 8-aligned, which should
|
||||
* suffice for any valid pool.
|
||||
*/
|
||||
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
|
||||
a->limit = (jsuword)a + gross;
|
||||
|
||||
*ap = a;
|
||||
continue;
|
||||
}
|
||||
a = *ap; /* move to next arena */
|
||||
}
|
||||
|
||||
void* p = (void *)a->avail;
|
||||
a->avail += nb;
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
return p;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaRealloc(JSArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
{
|
||||
/* If we've called JS_ArenaRealloc, the new size must be bigger than pool->arenasize. */
|
||||
JS_ASSERT(size + incr > pool->arenasize);
|
||||
|
||||
/* Find the arena containing |p|. */
|
||||
JSArena *a;
|
||||
JSArena **ap = &pool->first.next;
|
||||
while (true) {
|
||||
a = *ap;
|
||||
if (JS_IS_IN_ARENA(a, p))
|
||||
break;
|
||||
JS_ASSERT(a != pool->current);
|
||||
ap = &a->next;
|
||||
}
|
||||
/* If we've called JS_ArenaRealloc, p must be at the start of an arena. */
|
||||
JS_ASSERT(a->base == jsuword(p));
|
||||
|
||||
size_t gross = sizeof(JSArena) + JS_ARENA_ALIGN(pool, size + incr);
|
||||
a = (JSArena *) OffTheBooks::realloc_(a, gross);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
a->base = jsuword(a) + sizeof(JSArena);
|
||||
a->avail = a->limit = jsuword(a) + gross;
|
||||
/*
|
||||
* Because realloc returns 8-aligned pointers and sizeof(JSArena) is a
|
||||
* multiple of 8, a->base will always be 8-aligned, which should suffice
|
||||
* for any valid pool.
|
||||
*/
|
||||
JS_ASSERT(a->base == JS_ARENA_ALIGN(pool, a->base));
|
||||
|
||||
if (a != *ap) {
|
||||
/* realloc moved the allocation: update other pointers to a. */
|
||||
if (pool->current == *ap)
|
||||
pool->current = a;
|
||||
*ap = a;
|
||||
}
|
||||
|
||||
return (void *)a->base;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
JS_ArenaGrow(JSArenaPool *pool, void *p, size_t size, size_t incr)
|
||||
{
|
||||
void *newp;
|
||||
|
||||
/*
|
||||
* If p points to an oversized allocation, it owns an entire arena, so we
|
||||
* can simply realloc the arena.
|
||||
*/
|
||||
if (size > pool->arenasize)
|
||||
return JS_ArenaRealloc(pool, p, size, incr);
|
||||
|
||||
JS_ARENA_ALLOCATE(newp, pool, size + incr);
|
||||
if (newp)
|
||||
memcpy(newp, p, size);
|
||||
return newp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Free tail arenas linked after head, which may not be the true list head.
|
||||
* Reset pool->current to point to head in case it pointed at a tail arena.
|
||||
*/
|
||||
static void
|
||||
FreeArenaList(JSArenaPool *pool, JSArena *head)
|
||||
{
|
||||
JSArena **ap, *a;
|
||||
|
||||
ap = &head->next;
|
||||
a = *ap;
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
#ifdef DEBUG
|
||||
do {
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
a->avail = a->base;
|
||||
JS_CLEAR_UNUSED(a);
|
||||
} while ((a = a->next) != NULL);
|
||||
a = *ap;
|
||||
#endif
|
||||
|
||||
do {
|
||||
*ap = a->next;
|
||||
JS_CLEAR_ARENA(a);
|
||||
UnwantedForeground::free_(a);
|
||||
} while ((a = *ap) != NULL);
|
||||
|
||||
pool->current = head;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaRelease(JSArenaPool *pool, char *mark)
|
||||
{
|
||||
JSArena *a;
|
||||
|
||||
for (a = &pool->first; a; a = a->next) {
|
||||
JS_ASSERT(a->base <= a->avail && a->avail <= a->limit);
|
||||
|
||||
if (JS_IS_IN_ARENA(a, mark)) {
|
||||
a->avail = JS_ARENA_ALIGN(pool, mark);
|
||||
JS_ASSERT(a->avail <= a->limit);
|
||||
FreeArenaList(pool, a);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FreeArenaPool(JSArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FinishArenaPool(JSArenaPool *pool)
|
||||
{
|
||||
FreeArenaList(pool, &pool->first);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaFinish()
|
||||
{
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ArenaShutDown(void)
|
||||
{
|
||||
}
|
|
@ -109,7 +109,6 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsarray.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbit.h"
|
||||
#include "jsbool.h"
|
||||
#include "jsbuiltins.h"
|
||||
#include "jscntxt.h"
|
||||
|
@ -126,7 +125,6 @@
|
|||
#include "jsstr.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsvector.h"
|
||||
#include "jswrapper.h"
|
||||
#include "methodjit/MethodJIT.h"
|
||||
#include "methodjit/StubCalls.h"
|
||||
|
|
|
@ -52,7 +52,6 @@
|
|||
#include "jsprf.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsbit.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsgcmark.h"
|
||||
|
|
|
@ -42,13 +42,14 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include "jsversion.h"
|
||||
#include "jsalloc.h"
|
||||
#include "jsapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jshash.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jspubtd.h"
|
||||
#include "jslock.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "vm/String.h"
|
||||
|
||||
/* Engine-internal extensions of jsid */
|
||||
|
|
305
js/src/jsbit.h
305
js/src/jsbit.h
|
@ -1,305 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsbit_h___
|
||||
#define jsbit_h___
|
||||
|
||||
#include "jstypes.h"
|
||||
#include "jscompat.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
|
||||
/*
|
||||
** A jsbitmap_t is a long integer that can be used for bitmaps
|
||||
*/
|
||||
typedef jsuword jsbitmap_t; /* NSPR name, a la Unix system types */
|
||||
typedef jsbitmap_t jsbitmap; /* JS-style scalar typedef name */
|
||||
|
||||
#define JS_BITMAP_SIZE(bits) (JS_HOWMANY(bits, JS_BITS_PER_WORD) * \
|
||||
sizeof(jsbitmap))
|
||||
|
||||
#define JS_TEST_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] & \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_SET_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] |= \
|
||||
((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
#define JS_CLEAR_BIT(_map,_bit) ((_map)[(_bit)>>JS_BITS_PER_WORD_LOG2] &= \
|
||||
~((jsbitmap)1<<((_bit)&(JS_BITS_PER_WORD-1))))
|
||||
|
||||
/*
|
||||
** Compute the log of the least power of 2 greater than or equal to n
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSIntn) JS_CeilingLog2(JSUint32 i);
|
||||
|
||||
/*
|
||||
** Compute the log of the greatest power of 2 less than or equal to n
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSIntn) JS_FloorLog2(JSUint32 i);
|
||||
|
||||
/*
|
||||
* Replace bit-scanning code sequences with CPU-specific instructions to
|
||||
* speedup calculations of ceiling/floor log2.
|
||||
*
|
||||
* With GCC 3.4 or later we can use __builtin_clz for that, see bug 327129.
|
||||
*
|
||||
* SWS: Added MSVC intrinsic bitscan support. See bugs 349364 and 356856.
|
||||
*/
|
||||
#if defined(_WIN32) && (_MSC_VER >= 1300) && (defined(_M_IX86) || defined(_M_AMD64) || defined(_M_X64))
|
||||
|
||||
unsigned char _BitScanForward(unsigned long * Index, unsigned long Mask);
|
||||
unsigned char _BitScanReverse(unsigned long * Index, unsigned long Mask);
|
||||
# pragma intrinsic(_BitScanForward,_BitScanReverse)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward(&idx, (unsigned long)val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse32(unsigned int val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse(&idx, (unsigned long)val);
|
||||
return (int)(31-idx);
|
||||
}
|
||||
# define js_bitscan_ctz32(val) __BitScanForward32(val)
|
||||
# define js_bitscan_clz32(val) __BitScanReverse32(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
|
||||
#if defined(_M_AMD64) || defined(_M_X64)
|
||||
unsigned char _BitScanForward64(unsigned long * Index, unsigned __int64 Mask);
|
||||
unsigned char _BitScanReverse64(unsigned long * Index, unsigned __int64 Mask);
|
||||
# pragma intrinsic(_BitScanForward64,_BitScanReverse64)
|
||||
|
||||
__forceinline static int
|
||||
__BitScanForward64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanForward64(&idx, val);
|
||||
return (int)idx;
|
||||
}
|
||||
__forceinline static int
|
||||
__BitScanReverse64(unsigned __int64 val)
|
||||
{
|
||||
unsigned long idx;
|
||||
|
||||
_BitScanReverse64(&idx, val);
|
||||
return (int)(63-idx);
|
||||
}
|
||||
# define js_bitscan_ctz64(val) __BitScanForward64(val)
|
||||
# define js_bitscan_clz64(val) __BitScanReverse64(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
#endif
|
||||
#elif (__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||
|
||||
# define js_bitscan_ctz32(val) __builtin_ctz(val)
|
||||
# define js_bitscan_clz32(val) __builtin_clz(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN32
|
||||
# if (JS_BYTES_PER_WORD == 8)
|
||||
# define js_bitscan_ctz64(val) __builtin_ctzll(val)
|
||||
# define js_bitscan_clz64(val) __builtin_clzll(val)
|
||||
# define JS_HAS_BUILTIN_BITSCAN64
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_CeilingLog2: Compute the log of the least power of
|
||||
** 2 greater than or equal to _n. The result is returned in _log2.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use intrinsic function or count-leading-zeros to calculate ceil(log2(_n)).
|
||||
* The macro checks for "n <= 1" and not "n != 0" as js_bitscan_clz32(0) is
|
||||
* undefined.
|
||||
*/
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
unsigned int j_ = (unsigned int)(_n); \
|
||||
(_log2) = (j_ <= 1 ? 0 : 32 - js_bitscan_clz32(j_ - 1)); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_CEILING_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) & ((j_)-1)) \
|
||||
(_log2) += 1; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
** Macro version of JS_FloorLog2: Compute the log of the greatest power of
|
||||
** 2 less than or equal to _n. The result is returned in _log2.
|
||||
**
|
||||
** This is equivalent to finding the highest set bit in the word.
|
||||
*/
|
||||
#ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
/*
|
||||
* Use js_bitscan_clz32 or count-leading-zeros to calculate floor(log2(_n)).
|
||||
* Since js_bitscan_clz32(0) is undefined, the macro set the loweset bit to 1
|
||||
* to ensure 0 result when _n == 0.
|
||||
*/
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
(_log2) = 31 - js_bitscan_clz32(((unsigned int)(_n)) | 1); \
|
||||
JS_END_MACRO
|
||||
#else
|
||||
# define JS_FLOOR_LOG2(_log2,_n) \
|
||||
JS_BEGIN_MACRO \
|
||||
JSUint32 j_ = (JSUint32)(_n); \
|
||||
(_log2) = 0; \
|
||||
if ((j_) >> 16) \
|
||||
(_log2) += 16, (j_) >>= 16; \
|
||||
if ((j_) >> 8) \
|
||||
(_log2) += 8, (j_) >>= 8; \
|
||||
if ((j_) >> 4) \
|
||||
(_log2) += 4, (j_) >>= 4; \
|
||||
if ((j_) >> 2) \
|
||||
(_log2) += 2, (j_) >>= 2; \
|
||||
if ((j_) >> 1) \
|
||||
(_log2) += 1; \
|
||||
JS_END_MACRO
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the least power of 2 greater than or equal to n. This is
|
||||
* a version of JS_CeilingLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size.
|
||||
*/
|
||||
#define JS_CEILING_LOG2W(n) ((n) <= 1 ? 0 : 1 + JS_FLOOR_LOG2W((n) - 1))
|
||||
|
||||
/*
|
||||
* Internal function.
|
||||
* Compute the log of the greatest power of 2 less than or equal to n.
|
||||
* This is a version of JS_FloorLog2 that operates on unsigned integers with
|
||||
* CPU-dependant size and requires that n != 0.
|
||||
*/
|
||||
#define JS_FLOOR_LOG2W(n) (JS_ASSERT((n) != 0), js_FloorLog2wImpl(n))
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4
|
||||
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN32
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz32(n)))
|
||||
# else
|
||||
# define js_FloorLog2wImpl(n) ((size_t)JS_FloorLog2(n))
|
||||
#endif
|
||||
|
||||
#elif JS_BYTES_PER_WORD == 8
|
||||
|
||||
# ifdef JS_HAS_BUILTIN_BITSCAN64
|
||||
# define js_FloorLog2wImpl(n) \
|
||||
((size_t)(JS_BITS_PER_WORD - 1 - js_bitscan_clz64(n)))
|
||||
# else
|
||||
extern size_t js_FloorLog2wImpl(size_t n);
|
||||
# endif
|
||||
|
||||
#else
|
||||
|
||||
# error "NOT SUPPORTED"
|
||||
|
||||
#endif
|
||||
|
||||
namespace js {
|
||||
|
||||
inline size_t
|
||||
CountTrailingZeros(size_t n)
|
||||
{
|
||||
JS_ASSERT(n != 0);
|
||||
#if JS_BYTES_PER_WORD != 4 && JS_BYTES_PER_WORD != 8
|
||||
# error "NOT SUPPORTED"
|
||||
#endif
|
||||
|
||||
#if JS_BYTES_PER_WORD == 4 && defined JS_HAS_BUILTIN_BITSCAN32
|
||||
return js_bitscan_ctz32(n);
|
||||
#elif JS_BYTES_PER_WORD == 8 && defined JS_HAS_BUILTIN_BITSCAN64
|
||||
return js_bitscan_ctz64(n);
|
||||
#else
|
||||
size_t count = 0;
|
||||
# if JS_BYTES_PER_WORD == 8
|
||||
if (!(n & size_t(0xFFFFFFFFU))) { count += 32; n >>= 32; }
|
||||
# endif
|
||||
if (!(n & 0xFFFF)) { count += 16; n >>= 16; }
|
||||
if (!(n & 0xFF)) { count += 8; n >>= 8; }
|
||||
if (!(n & 0xF)) { count += 4; n >>= 4; }
|
||||
if (!(n & 0x3)) { count += 2; n >>= 2; }
|
||||
if (!(n & 0x1)) { count += 1; n >>= 1; }
|
||||
return count + 1 - (n & 0x1);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Macros for rotate left. There is no rotate operation in the C Language so
|
||||
* the construct (a << 4) | (a >> 28) is used instead. Most compilers convert
|
||||
* this to a rotate instruction but some versions of MSVC don't without a
|
||||
* little help. To get MSVC to generate a rotate instruction, we have to use
|
||||
* the _rotl intrinsic and use a pragma to make _rotl inline.
|
||||
*
|
||||
* MSVC in VS2005 will do an inline rotate instruction on the above construct.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_AMD64) || \
|
||||
defined(_M_X64))
|
||||
#include <stdlib.h>
|
||||
#pragma intrinsic(_rotl)
|
||||
#define JS_ROTATE_LEFT32(a, bits) _rotl(a, bits)
|
||||
#else
|
||||
#define JS_ROTATE_LEFT32(a, bits) (((a) << (bits)) | ((a) >> (32 - (bits))))
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
#endif /* jsbit_h___ */
|
|
@ -53,7 +53,6 @@
|
|||
#include "jsnum.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsstr.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "vm/GlobalObject.h"
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@
|
|||
#include "jsstr.h"
|
||||
#include "jsbuiltins.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "jsatominlines.h"
|
||||
#include "jscntxtinlines.h"
|
||||
|
|
|
@ -41,9 +41,10 @@
|
|||
|
||||
#include "jsapi.h"
|
||||
#include "jscntxt.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jsstdint.h"
|
||||
#include "jsvector.h"
|
||||
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
JS_FRIEND_API(uint64_t)
|
||||
js_GetSCOffset(JSStructuredCloneWriter* writer);
|
||||
|
|
|
@ -533,21 +533,18 @@ js_DestroyContext(JSContext *cx, JSDestroyContextMode mode)
|
|||
#endif
|
||||
|
||||
if (last) {
|
||||
GCREASON(LASTCONTEXT);
|
||||
js_GC(cx, NULL, GC_LAST_CONTEXT);
|
||||
js_GC(cx, NULL, GC_LAST_CONTEXT, gcstats::LASTCONTEXT);
|
||||
|
||||
/* Take the runtime down, now that it has no contexts or atoms. */
|
||||
JS_LOCK_GC(rt);
|
||||
rt->state = JSRTS_DOWN;
|
||||
JS_NOTIFY_ALL_CONDVAR(rt->stateChange);
|
||||
} else {
|
||||
if (mode == JSDCM_FORCE_GC) {
|
||||
GCREASON(DESTROYCONTEXT);
|
||||
js_GC(cx, NULL, GC_NORMAL);
|
||||
} else if (mode == JSDCM_MAYBE_GC) {
|
||||
GCREASON(DESTROYCONTEXT);
|
||||
if (mode == JSDCM_FORCE_GC)
|
||||
js_GC(cx, NULL, GC_NORMAL, gcstats::DESTROYCONTEXT);
|
||||
else if (mode == JSDCM_MAYBE_GC)
|
||||
JS_MaybeGC(cx);
|
||||
}
|
||||
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
}
|
||||
|
@ -1165,7 +1162,7 @@ js_InvokeOperationCallback(JSContext *cx)
|
|||
JS_UNLOCK_GC(rt);
|
||||
|
||||
if (rt->gcIsNeeded) {
|
||||
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL);
|
||||
js_GC(cx, rt->gcTriggerCompartment, GC_NORMAL, rt->gcTriggerReason);
|
||||
|
||||
/*
|
||||
* On trace we can exceed the GC quota, see comments in NewGCArena. So
|
||||
|
@ -1342,6 +1339,7 @@ JSContext::JSContext(JSRuntime *rt)
|
|||
throwing(false),
|
||||
exception(UndefinedValue()),
|
||||
runOptions(0),
|
||||
reportGranularity(JS_DEFAULT_JITREPORT_GRANULARITY),
|
||||
localeCallbacks(NULL),
|
||||
resolvingList(NULL),
|
||||
generatingError(false),
|
||||
|
@ -1514,8 +1512,7 @@ JSRuntime::onTooMuchMalloc()
|
|||
*/
|
||||
js_WaitForGC(this);
|
||||
#endif
|
||||
GCREASON(TOOMUCHMALLOC);
|
||||
TriggerGC(this);
|
||||
TriggerGC(this, gcstats::TOOMUCHMALLOC);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
|
|
|
@ -45,21 +45,23 @@
|
|||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsatom.h"
|
||||
#include "jsclist.h"
|
||||
#include "jsdhash.h"
|
||||
#include "jsgc.h"
|
||||
#include "jsgcchunk.h"
|
||||
#include "jshashtable.h"
|
||||
#include "jspropertycache.h"
|
||||
#include "jspropertytree.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsvector.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
#include "ds/LifoAlloc.h"
|
||||
#include "gc/Statistics.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
#include "vm/StackSpace.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -430,6 +432,10 @@ struct JSRuntime {
|
|||
JSGCMode gcMode;
|
||||
volatile jsuword gcIsNeeded;
|
||||
js::WeakMapBase *gcWeakMapList;
|
||||
js::gcstats::Statistics gcStats;
|
||||
|
||||
/* The reason that an interrupt-triggered GC should be called. */
|
||||
js::gcstats::Reason gcTriggerReason;
|
||||
|
||||
/* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
|
||||
void *gcMarkStackObjs[js::OBJECT_MARK_STACK_SIZE / sizeof(void *)];
|
||||
|
@ -599,6 +605,9 @@ struct JSRuntime {
|
|||
/* Structured data callbacks are runtime-wide. */
|
||||
const JSStructuredCloneCallbacks *structuredCloneCallbacks;
|
||||
|
||||
/* Call this to accumulate telemetry data. */
|
||||
JSAccumulateTelemetryDataCallback telemetryCallback;
|
||||
|
||||
/*
|
||||
* The propertyRemovals counter is incremented for every JSObject::clear,
|
||||
* and for each JSObject::remove method call that frees a slot in the given
|
||||
|
@ -673,59 +682,13 @@ struct JSRuntime {
|
|||
*/
|
||||
int32 inOOMReport;
|
||||
|
||||
#if defined(MOZ_GCTIMER) || defined(JSGC_TESTPILOT)
|
||||
struct GCData {
|
||||
GCData()
|
||||
: firstEnter(0),
|
||||
firstEnterValid(false)
|
||||
#ifdef JSGC_TESTPILOT
|
||||
, infoEnabled(false),
|
||||
start(0),
|
||||
count(0)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
/*
|
||||
* Timestamp of the first GCTimer -- application runtime is determined
|
||||
* relative to this value.
|
||||
*/
|
||||
uint64 firstEnter;
|
||||
bool firstEnterValid;
|
||||
|
||||
void setFirstEnter(uint64 v) {
|
||||
JS_ASSERT(!firstEnterValid);
|
||||
firstEnter = v;
|
||||
firstEnterValid = true;
|
||||
}
|
||||
|
||||
#ifdef JSGC_TESTPILOT
|
||||
bool infoEnabled;
|
||||
|
||||
bool isTimerEnabled() {
|
||||
return infoEnabled;
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular buffer with GC data.
|
||||
* count may grow >= INFO_LIMIT, which would indicate data loss.
|
||||
*/
|
||||
static const size_t INFO_LIMIT = 64;
|
||||
JSGCInfo info[INFO_LIMIT];
|
||||
size_t start;
|
||||
size_t count;
|
||||
#else /* defined(MOZ_GCTIMER) */
|
||||
bool isTimerEnabled() {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
} gcData;
|
||||
#endif
|
||||
|
||||
JSRuntime();
|
||||
~JSRuntime();
|
||||
|
||||
bool init(uint32 maxbytes);
|
||||
|
||||
JSRuntime *thisFromCtor() { return this; }
|
||||
|
||||
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
|
||||
void reduceGCTriggerBytes(uint32 amount);
|
||||
|
||||
|
@ -970,6 +933,8 @@ struct JSContext
|
|||
uintN runOptions; /* see jsapi.h for JSOPTION_* */
|
||||
|
||||
public:
|
||||
int32 reportGranularity; /* see jsprobes.h */
|
||||
|
||||
/* Locale specific callbacks for string conversion. */
|
||||
JSLocaleCallbacks *localeCallbacks;
|
||||
|
||||
|
|
|
@ -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(¬es[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"
|
||||
|
|
220
js/src/jsgc.cpp
220
js/src/jsgc.cpp
|
@ -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 {
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче