зеркало из https://github.com/mozilla/pjs.git
Merge m-c to m-i.
This commit is contained in:
Коммит
9839c9abbf
|
@ -46,6 +46,10 @@
|
|||
label="&spellAddToDictionary.label;"
|
||||
accesskey="&spellAddToDictionary.accesskey;"
|
||||
oncommand="InlineSpellCheckerUI.addToDictionary();"/>
|
||||
<menuitem id="spell-undo-add-to-dictionary"
|
||||
label="&spellUndoAddToDictionary.label;"
|
||||
accesskey="&spellUndoAddToDictionary.accesskey;"
|
||||
oncommand="InlineSpellCheckerUI.undoAddToDictionary();" />
|
||||
<menuseparator id="spell-suggestions-separator"/>
|
||||
<menuitem id="context-openlinkincurrent"
|
||||
label="&openLinkCmdInCurrent.label;"
|
||||
|
|
|
@ -337,6 +337,7 @@ nsContextMenu.prototype = {
|
|||
.setAttribute("checked", canSpell && InlineSpellCheckerUI.enabled);
|
||||
|
||||
this.showItem("spell-add-to-dictionary", onMisspelling);
|
||||
this.showItem("spell-undo-add-to-dictionary", InlineSpellCheckerUI.canUndo());
|
||||
|
||||
// suggestion list
|
||||
this.showItem("spell-suggestions-separator", onMisspelling);
|
||||
|
|
|
@ -19,6 +19,7 @@ Browser context menu tests.
|
|||
/** Test for Login Manager: multiple login autocomplete. **/
|
||||
|
||||
netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
|
||||
Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
@ -514,12 +515,36 @@ function runTest(testNum) {
|
|||
"---", null,
|
||||
"spell-add-dictionaries", true], null,
|
||||
].concat(inspectItems));
|
||||
|
||||
contextMenu.ownerDocument.getElementById("spell-add-to-dictionary").doCommand(); // Add to dictionary
|
||||
closeContextMenu();
|
||||
openContextMenuFor(contenteditable); // Invoke context menu for next test.
|
||||
openContextMenuFor(textarea, false, true); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 15:
|
||||
// Context menu for textarea after a word has been added
|
||||
// to the dictionary
|
||||
checkContextMenu(["spell-undo-add-to-dictionary", true,
|
||||
"context-undo", false,
|
||||
"---", null,
|
||||
"context-cut", false,
|
||||
"context-copy", false,
|
||||
"context-paste", null, // ignore clipboard state
|
||||
"context-delete", false,
|
||||
"---", null,
|
||||
"context-selectall", true,
|
||||
"---", null,
|
||||
"spell-check-enabled", true,
|
||||
"spell-dictionaries", true,
|
||||
["spell-check-dictionary-en-US", true,
|
||||
"---", null,
|
||||
"spell-add-dictionaries", true], null,
|
||||
].concat(inspectItems));
|
||||
contextMenu.ownerDocument.getElementById("spell-undo-add-to-dictionary").doCommand(); // Undo add to dictionary
|
||||
closeContextMenu();
|
||||
openContextMenuFor(contenteditable);
|
||||
break;
|
||||
|
||||
case 15:
|
||||
case 16:
|
||||
// Context menu for contenteditable
|
||||
checkContextMenu(["spell-no-suggestions", false,
|
||||
"spell-add-to-dictionary", true,
|
||||
|
@ -544,7 +569,7 @@ function runTest(testNum) {
|
|||
openContextMenuFor(inputspell); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 16:
|
||||
case 17:
|
||||
// Context menu for spell-check input
|
||||
checkContextMenu(["*prodigality", true, // spelling suggestion
|
||||
"spell-add-to-dictionary", true,
|
||||
|
@ -569,13 +594,13 @@ function runTest(testNum) {
|
|||
openContextMenuFor(link); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 17:
|
||||
case 18:
|
||||
executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
|
||||
closeContextMenu();
|
||||
openContextMenuFor(pagemenu); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 18:
|
||||
case 19:
|
||||
// Context menu for element with assigned content context menu
|
||||
checkContextMenu(["+Plain item", {type: "", icon: "", checked: false, disabled: false},
|
||||
"+Disabled item", {type: "", icon: "", checked: false, disabled: true},
|
||||
|
@ -618,7 +643,7 @@ function runTest(testNum) {
|
|||
openContextMenuFor(pagemenu, true); // Invoke context menu for next test.
|
||||
break;
|
||||
|
||||
case 19:
|
||||
case 20:
|
||||
// Context menu for element with assigned content context menu
|
||||
// The shift key should bypass content context menu processing
|
||||
checkContextMenu(["context-back", false,
|
||||
|
|
|
@ -317,11 +317,9 @@ nsGNOMEShellService::SetDefaultBrowser(bool aClaimAllTypes,
|
|||
rv = bundleService->CreateBundle(BRAND_PROPERTIES, getter_AddRefs(brandBundle));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsString brandShortName, brandFullName;
|
||||
nsString brandShortName;
|
||||
brandBundle->GetStringFromName(NS_LITERAL_STRING("brandShortName").get(),
|
||||
getter_Copies(brandShortName));
|
||||
brandBundle->GetStringFromName(NS_LITERAL_STRING("brandFullName").get(),
|
||||
getter_Copies(brandFullName));
|
||||
|
||||
// use brandShortName as the application id.
|
||||
NS_ConvertUTF16toUTF8 id(brandShortName);
|
||||
|
|
82
configure.in
82
configure.in
|
@ -336,6 +336,7 @@ if test -n "$gonkdir" ; then
|
|||
fi
|
||||
|
||||
AC_DEFINE(ANDROID)
|
||||
AC_DEFINE(HAVE_SYS_UIO_H)
|
||||
CROSS_COMPILE=1
|
||||
MOZ_CHROME_FILE_FORMAT=omni
|
||||
ZLIB_DIR=yes
|
||||
|
@ -1864,20 +1865,15 @@ if test "$GNU_CC"; then
|
|||
_MOZ_RTTI_FLAGS_ON=-frtti
|
||||
_MOZ_RTTI_FLAGS_OFF=-fno-rtti
|
||||
|
||||
# Turn on GNU-specific warnings:
|
||||
# -Wall - turn on a lot of warnings
|
||||
# -pedantic - this is turned on below
|
||||
# -Wpointer-arith - enabled with -pedantic, but good to have even if not
|
||||
# -Werror=declaration-after-statement - MSVC doesn't like these
|
||||
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
|
||||
#
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement -Wempty-body"
|
||||
|
||||
# Turn off the following warnings that -Wall/-pedantic turn on:
|
||||
# -Woverlength-strings - we exceed the minimum maximum length all the time
|
||||
#
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-overlength-strings"
|
||||
|
||||
# Turn on GNU specific features
|
||||
# -Wall - turn on all warnings
|
||||
# -pedantic - make compiler warn about non-ANSI stuff, and
|
||||
# be a little bit stricter
|
||||
# -Wdeclaration-after-statement - MSVC doesn't like these
|
||||
# Warnings slamm took out for now (these were giving more noise than help):
|
||||
# -Wbad-function-cast - warns when casting a function to a new return type
|
||||
# -Wshadow - removed because it generates more noise than help --pete
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith -Wdeclaration-after-statement"
|
||||
if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
|
||||
# Don't use -Wcast-align with ICC or clang
|
||||
case "$CPU_ARCH" in
|
||||
|
@ -1893,26 +1889,12 @@ if test "$GNU_CC"; then
|
|||
dnl Turn pedantic on but disable the warnings for long long
|
||||
_PEDANTIC=1
|
||||
|
||||
if test -z "$INTEL_CC"; then
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W"
|
||||
fi
|
||||
|
||||
_DEFINES_CFLAGS='-include $(DEPTH)/mozilla-config.h -DMOZILLA_CLIENT'
|
||||
_USE_CPP_INCLUDE_FLAG=1
|
||||
|
||||
AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
|
||||
ac_cc_has_wtype_limits,
|
||||
[
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
_SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wtype-limits"
|
||||
AC_TRY_COMPILE([],
|
||||
[return(0);],
|
||||
ac_cc_has_wtype_limits="yes",
|
||||
ac_cc_has_wtype_limits="no")
|
||||
CFLAGS="$_SAVE_CFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
if test "$ac_cc_has_wtype_limits" = "yes"; then
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
|
||||
fi
|
||||
elif test "$SOLARIS_SUNPRO_CC"; then
|
||||
DSO_CFLAGS=''
|
||||
if test "$CPU_ARCH" = "sparc"; then
|
||||
|
@ -1940,22 +1922,8 @@ fi
|
|||
if test "$GNU_CXX"; then
|
||||
# FIXME: Let us build with strict aliasing. bug 414641.
|
||||
CXXFLAGS="$CXXFLAGS -fno-exceptions -fno-strict-aliasing"
|
||||
|
||||
# Turn on GNU-specific warnings:
|
||||
# -Wall - turn on a lot of warnings
|
||||
# -pedantic - this is turned on below
|
||||
# -Wpointer-arith - enabled with -pedantic, but good to have even if not
|
||||
# -Woverloaded-virtual - ???
|
||||
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
|
||||
#
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wempty-body"
|
||||
|
||||
# Turn off the following warnings that -Wall/-pedantic turn on:
|
||||
# -Woverlength-strings - we exceed the minimum maximum length all the time
|
||||
# -Wctor-dtor-privacy - ???
|
||||
#
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-overlength-strings -Wno-ctor-dtor-privacy"
|
||||
|
||||
# Turn on GNU specific features
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor"
|
||||
if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
|
||||
# Don't use -Wcast-align with ICC or clang
|
||||
case "$CPU_ARCH" in
|
||||
|
@ -2056,24 +2024,6 @@ if test "$GNU_CXX"; then
|
|||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
|
||||
ac_has_wtype_limits,
|
||||
[
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -Wtype-limits"
|
||||
AC_TRY_COMPILE([],
|
||||
[return(0);],
|
||||
ac_has_wtype_limits="yes",
|
||||
ac_has_wtype_limits="no")
|
||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
if test "$ac_has_wtype_limits" = "yes"; then
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
|
||||
fi
|
||||
|
||||
else
|
||||
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_MOZILLA_CONFIG_H_ $(ACDEFINES)'
|
||||
fi
|
||||
|
|
|
@ -2129,7 +2129,8 @@ nsGenericElement::GetBoundingClientRect(nsIDOMClientRect** aResult)
|
|||
}
|
||||
|
||||
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(frame,
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(frame));
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(frame),
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
rect->SetLayoutRect(r);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -2157,7 +2158,8 @@ nsGenericElement::GetClientRects(nsIDOMClientRectList** aResult)
|
|||
|
||||
nsLayoutUtils::RectListBuilder builder(rectList);
|
||||
nsLayoutUtils::GetAllInFlowRects(frame,
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder);
|
||||
nsLayoutUtils::GetContainingBlockForClientRect(frame), &builder,
|
||||
nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS);
|
||||
if (NS_FAILED(builder.mRV))
|
||||
return builder.mRV;
|
||||
*aResult = rectList.forget().get();
|
||||
|
|
|
@ -102,7 +102,8 @@ protected:
|
|||
|
||||
const txExpandedName key()
|
||||
{
|
||||
NS_ASSERTION(mCurrentPos < mMap.mItems.Length(),
|
||||
NS_ASSERTION(mCurrentPos >= 0 &&
|
||||
mCurrentPos < mMap.mItems.Length(),
|
||||
"invalid position in txExpandedNameMap::iterator");
|
||||
return txExpandedName(mMap.mItems[mCurrentPos].mNamespaceID,
|
||||
mMap.mItems[mCurrentPos].mLocalName);
|
||||
|
@ -111,7 +112,8 @@ protected:
|
|||
protected:
|
||||
void* itemValue()
|
||||
{
|
||||
NS_ASSERTION(mCurrentPos < mMap.mItems.Length(),
|
||||
NS_ASSERTION(mCurrentPos >= 0 &&
|
||||
mCurrentPos < mMap.mItems.Length(),
|
||||
"invalid position in txExpandedNameMap::iterator");
|
||||
return mMap.mItems[mCurrentPos].mValue;
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ function test() {
|
|||
|
||||
// Go offline and disable the cache, then try to load the test URL.
|
||||
Services.io.offline = true;
|
||||
gPrefService.setBoolPref("browser.cache.disk.enable", false);
|
||||
gPrefService.setBoolPref("browser.cache.memory.enable", false);
|
||||
Services.prefs.setBoolPref("browser.cache.disk.enable", false);
|
||||
Services.prefs.setBoolPref("browser.cache.memory.enable", false);
|
||||
content.location = "http://example.com/";
|
||||
}
|
||||
|
||||
|
@ -42,8 +42,8 @@ function checkPage() {
|
|||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
gPrefService.setBoolPref("browser.cache.disk.enable", true);
|
||||
gPrefService.setBoolPref("browser.cache.memory.enable", true);
|
||||
Services.prefs.setBoolPref("browser.cache.disk.enable", true);
|
||||
Services.prefs.setBoolPref("browser.cache.memory.enable", true);
|
||||
Services.io.offline = false;
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
|
|
@ -230,3 +230,12 @@ nsDOMMemoryMultiReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMMemoryMultiReporter::GetExplicitNonHeap(PRInt64* aAmount)
|
||||
{
|
||||
// This reporter only measures heap memory.
|
||||
*aAmount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -129,6 +129,8 @@ static PRLogModuleInfo* gJSDiagnostics;
|
|||
// a page) and doing the actual GC.
|
||||
#define NS_GC_DELAY 4000 // ms
|
||||
|
||||
#define NS_SHRINK_GC_BUFFERS_DELAY 4000 // ms
|
||||
|
||||
// The amount of time we wait from the first request to GC to actually
|
||||
// doing the first GC.
|
||||
#define NS_FIRST_GC_DELAY 10000 // ms
|
||||
|
@ -142,6 +144,7 @@ static PRLogModuleInfo* gJSDiagnostics;
|
|||
// if you add statics here, add them to the list in nsJSRuntime::Startup
|
||||
|
||||
static nsITimer *sGCTimer;
|
||||
static nsITimer *sShrinkGCBuffersTimer;
|
||||
static nsITimer *sCCTimer;
|
||||
|
||||
static bool sGCHasRun;
|
||||
|
@ -1098,8 +1101,9 @@ nsJSContext::~nsJSContext()
|
|||
void
|
||||
nsJSContext::DestroyJSContext()
|
||||
{
|
||||
if (!mContext)
|
||||
if (!mContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear our entry in the JSContext, bugzilla bug 66413
|
||||
::JS_SetContextPrivate(mContext, nsnull);
|
||||
|
@ -1108,14 +1112,14 @@ nsJSContext::DestroyJSContext()
|
|||
Preferences::UnregisterCallback(JSOptionChangedCallback,
|
||||
js_options_dot_str, this);
|
||||
|
||||
bool do_gc = mGCOnDestruction && !sGCTimer;
|
||||
|
||||
if (mGCOnDestruction) {
|
||||
PokeGC();
|
||||
}
|
||||
|
||||
// Let xpconnect destroy the JSContext when it thinks the time is right.
|
||||
nsIXPConnect *xpc = nsContentUtils::XPConnect();
|
||||
if (xpc) {
|
||||
xpc->ReleaseJSContext(mContext, !do_gc);
|
||||
} else if (do_gc) {
|
||||
::JS_DestroyContext(mContext);
|
||||
xpc->ReleaseJSContext(mContext, true);
|
||||
} else {
|
||||
::JS_DestroyContextNoGC(mContext);
|
||||
}
|
||||
|
@ -3224,6 +3228,7 @@ nsJSContext::GarbageCollectNow(bool shrinkingGC)
|
|||
SAMPLE_LABEL("GC", "GarbageCollectNow");
|
||||
|
||||
KillGCTimer();
|
||||
KillShrinkGCBuffersTimer();
|
||||
|
||||
// Reset sPendingLoadCount in case the timer that fired was a
|
||||
// timer we scheduled due to a normal GC timer firing while
|
||||
|
@ -3239,6 +3244,18 @@ nsJSContext::GarbageCollectNow(bool shrinkingGC)
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsJSContext::ShrinkGCBuffersNow()
|
||||
{
|
||||
NS_TIME_FUNCTION_MIN(1.0);
|
||||
SAMPLE_LABEL("GC", "ShrinkGCBuffersNow");
|
||||
|
||||
KillShrinkGCBuffersTimer();
|
||||
|
||||
JS_ShrinkGCBuffers(nsJSRuntime::sRuntime);
|
||||
}
|
||||
|
||||
//Static
|
||||
void
|
||||
nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener)
|
||||
|
@ -3296,6 +3313,14 @@ GCTimerFired(nsITimer *aTimer, void *aClosure)
|
|||
nsJSContext::GarbageCollectNow();
|
||||
}
|
||||
|
||||
void
|
||||
ShrinkGCBuffersTimerFired(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
NS_RELEASE(sShrinkGCBuffersTimer);
|
||||
|
||||
nsJSContext::ShrinkGCBuffersNow();
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
CCTimerFired(nsITimer *aTimer, void *aClosure)
|
||||
|
@ -3359,6 +3384,26 @@ nsJSContext::PokeGC()
|
|||
first = false;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsJSContext::PokeShrinkGCBuffers()
|
||||
{
|
||||
if (sShrinkGCBuffersTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sShrinkGCBuffersTimer);
|
||||
|
||||
if (!sShrinkGCBuffersTimer) {
|
||||
// Failed to create timer (probably because we're in XPCOM shutdown)
|
||||
return;
|
||||
}
|
||||
|
||||
sShrinkGCBuffersTimer->InitWithFuncCallback(ShrinkGCBuffersTimerFired, nsnull,
|
||||
NS_SHRINK_GC_BUFFERS_DELAY,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
nsJSContext::MaybePokeCC()
|
||||
|
@ -3400,6 +3445,17 @@ nsJSContext::KillGCTimer()
|
|||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsJSContext::KillShrinkGCBuffersTimer()
|
||||
{
|
||||
if (sShrinkGCBuffersTimer) {
|
||||
sShrinkGCBuffersTimer->Cancel();
|
||||
|
||||
NS_RELEASE(sShrinkGCBuffersTimer);
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
void
|
||||
nsJSContext::KillCCTimer()
|
||||
|
@ -3465,10 +3521,11 @@ DOMGCFinishedCallback(JSRuntime *rt, JSCompartment *comp, const char *status)
|
|||
}
|
||||
}
|
||||
|
||||
// If we didn't end up scheduling a GC, and there are unused
|
||||
// chunks waiting to expire, make sure we will GC again soon.
|
||||
if (!sGCTimer && JS_GetGCParameter(rt, JSGC_UNUSED_CHUNKS) > 0) {
|
||||
nsJSContext::PokeGC();
|
||||
// If we didn't end up scheduling a GC, make sure that we release GC buffers
|
||||
// soon after canceling previous shrinking attempt
|
||||
nsJSContext::KillShrinkGCBuffersTimer();
|
||||
if (!sGCTimer) {
|
||||
nsJSContext::PokeShrinkGCBuffers();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3808,6 +3865,7 @@ void
|
|||
nsJSRuntime::Shutdown()
|
||||
{
|
||||
nsJSContext::KillGCTimer();
|
||||
nsJSContext::KillShrinkGCBuffersTimer();
|
||||
nsJSContext::KillCCTimer();
|
||||
|
||||
NS_IF_RELEASE(gNameSpaceManager);
|
||||
|
|
|
@ -183,11 +183,15 @@ public:
|
|||
static void LoadEnd();
|
||||
|
||||
static void GarbageCollectNow(bool shrinkingGC = false);
|
||||
static void ShrinkGCBuffersNow();
|
||||
static void CycleCollectNow(nsICycleCollectorListener *aListener = nsnull);
|
||||
|
||||
static void PokeGC();
|
||||
static void KillGCTimer();
|
||||
|
||||
static void PokeShrinkGCBuffers();
|
||||
static void KillShrinkGCBuffersTimer();
|
||||
|
||||
static void PokeCC();
|
||||
static void MaybePokeCC();
|
||||
static void KillCCTimer();
|
||||
|
|
|
@ -58,6 +58,7 @@ _TEST_FILES = \
|
|||
test_bug631440.html \
|
||||
test_bug653364.html \
|
||||
test_bug629535.html \
|
||||
test_clientRects.html \
|
||||
test_consoleAPI.html \
|
||||
test_domWindowUtils.html \
|
||||
test_domWindowUtils_scrollXY.html \
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html id="d9" style="width:800px; height:1000px">
|
||||
<head>
|
||||
<title>Tests for getClientRects/getBoundingClientRect</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body style="margin:0" onload="doTest()">
|
||||
|
||||
<script>
|
||||
function isWithinEps(v1, v2, eps, msg) {
|
||||
if (eps) {
|
||||
ok(Math.abs(v1 - v2) < eps, msg + " (within " + eps + "); got " + v1 + ", expected " + v2);
|
||||
} else {
|
||||
is(v1, v2, msg);
|
||||
}
|
||||
}
|
||||
function checkRect(clientRect, r, eps, exprMsg, restMsg) {
|
||||
isWithinEps(clientRect.left, r[0], eps, exprMsg + ".left" + restMsg);
|
||||
isWithinEps(clientRect.top, r[1], eps, exprMsg + ".top" + restMsg);
|
||||
isWithinEps(clientRect.right, r[2], eps, exprMsg + ".right" + restMsg);
|
||||
isWithinEps(clientRect.bottom, r[3], eps, exprMsg + ".bottom" + restMsg);
|
||||
isWithinEps(clientRect.width, r[2] - r[0], eps, exprMsg + ".width" + restMsg);
|
||||
isWithinEps(clientRect.height, r[3] - r[1], eps, exprMsg + ".height" + restMsg);
|
||||
}
|
||||
function doc(id) {
|
||||
return document.getElementById(id).contentDocument;
|
||||
}
|
||||
function checkElement(id, list, eps, doc) {
|
||||
var e = (doc || document).getElementById(id);
|
||||
var clientRects = e.getClientRects();
|
||||
is(clientRects.length, list.length, "getClientRects().length for element '" + id + "'");
|
||||
var bounds = list.length > 0 ? list[0] : [0,0,0,0];
|
||||
for (var i = 0; i < clientRects.length && i < list.length; ++i) {
|
||||
var r = list[i];
|
||||
r[2] += r[0];
|
||||
r[3] += r[1];
|
||||
checkRect(clientRects[i], r, eps, "getClientRects()[" + i + "]", " for element '" + id + "'");
|
||||
if (r[2] != r[0] && r[3] != r[1]) {
|
||||
bounds[0] = Math.min(bounds[0], r[0]);
|
||||
bounds[1] = Math.min(bounds[1], r[1]);
|
||||
bounds[2] = Math.max(bounds[2], r[2]);
|
||||
bounds[3] = Math.max(bounds[3], r[3]);
|
||||
}
|
||||
}
|
||||
checkRect(e.getBoundingClientRect(), bounds, eps, "getBoundingClientRect()", " for element '" + id + "'");
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Simple case -->
|
||||
<div id="d1" style="position:absolute; left:50px; top:50px; width:20px; height:30px; background:pink;"></div>
|
||||
<!-- Multiple boxes -->
|
||||
<div style="position:absolute; left:50px; top:100px; width:400px; height:100px; -moz-column-count:2; -moz-column-gap:0; column-count:2; column-gap:0">
|
||||
<div id="d2">
|
||||
<div style="width:200px; height:100px; background:yellow"></div>
|
||||
<div style="width:200px; height:100px; background:lime"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- No boxes -->
|
||||
<div id="d3" style="display:none"></div>
|
||||
<!-- Element in transform -->
|
||||
<div style="-moz-transform:translate(50px, 50px); transform:translate(50px,50px); position:absolute; left:0; top:200px">
|
||||
<div id="d4" style="width:50px; height:50px; background:blue;"></div>
|
||||
</div>
|
||||
<svg style="position:absolute; left:50px; top:300px; width:100px; height:100px;">
|
||||
<!-- Element in SVG foreignobject -->
|
||||
<foreignObject x="20" y="30" width="40" height="40">
|
||||
<div id="d5" style="width:40px; height:40px; background:pink;"></div>
|
||||
</foreignObject>
|
||||
<!-- SVG Element -->
|
||||
<circle id="s1" cx="60" cy="60" r="10" fill="yellow"/>
|
||||
</svg>
|
||||
<!-- Element in transform with bounding-box -->
|
||||
<div style="-moz-transform:rotate(45deg); transform:rotate(45deg); position:absolute; left:50px; top:450px; width:100px; height:100px;">
|
||||
<div id="d6" style="width:100px; height:100px; background:orange;"></div>
|
||||
</div>
|
||||
<!-- Element in two transforms; we should combine transforms instead of taking bounding-box twice -->
|
||||
<div style="-moz-transform:rotate(45deg); transform:rotate(45deg); position:absolute; left:50px; top:550px; width:100px; height:100px;">
|
||||
<div style="-moz-transform:rotate(-45deg); transform:rotate(-45deg); width:100px; height:100px;">
|
||||
<div id="d7" style="width:100px; height:100px; background:lime;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Fixed-pos element -->
|
||||
<div id="d8" style="position:fixed; left:50px; top:700px; width:100px; height:100px; background:gray;"></div>
|
||||
<!-- Root element; see d9 -->
|
||||
<!-- Element in iframe -->
|
||||
<iframe id="f1" style="position:absolute; left:300px; top:0; width:100px; height:200px; border:none"
|
||||
src="data:text/html,<div id='d10' style='position:absolute; left:0; top:25px; width:100px; height:100px; background:cyan'>">
|
||||
</iframe>
|
||||
<!-- Root element in iframe -->
|
||||
<iframe id="f2" style="position:absolute; left:300px; top:250px; width:100px; height:200px; border:none"
|
||||
src="data:text/html,<html id='d11' style='width:100px; height:100px; background:magenta'>">
|
||||
</iframe>
|
||||
<!-- Fixed-pos element in iframe -->
|
||||
<iframe id="f3" style="position:absolute; left:300px; top:400px; border:none"
|
||||
src="data:text/html,<div id='d12' style='position:fixed; left:0; top:0; width:100px; height:100px;'>"></iframe>
|
||||
|
||||
<script>
|
||||
function doTest() {
|
||||
checkElement("d1", [[50,50,20,30]]);
|
||||
checkElement("d2", [[50,100,200,100],[250,100,200,100]]);
|
||||
checkElement("d3", []);
|
||||
checkElement("d4", [[50,250,50,50]]);
|
||||
checkElement("d5", [[70,330,40,40]]);
|
||||
checkElement("s1", [[100,350,20,20]]);
|
||||
var sqrt2 = Math.sqrt(2);
|
||||
checkElement("d6", [[100 - 50*sqrt2,500 - 50*sqrt2,100*sqrt2,100*sqrt2]], 0.1);
|
||||
checkElement("d7", [[50,550,100,100]]);
|
||||
checkElement("d8", [[50,700,100,100]]);
|
||||
checkElement("d9", [[0,0,800,1000]]);
|
||||
checkElement("d10", [[0,25,100,100]], 0, doc("f1"));
|
||||
checkElement("d11", [[0,0,100,100]], 0, doc("f2"));
|
||||
checkElement("d12", [[0,0,100,100]], 0, doc("f3"));
|
||||
SimpleTest.finish();
|
||||
}
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
</script>
|
||||
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -186,17 +186,14 @@ public:
|
|||
NS_LITERAL_CSTRING(")/");
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
CollectReports(nsIMemoryMultiReporterCallback* aCallback,
|
||||
nsISupports* aClosure)
|
||||
nsresult
|
||||
CollectForRuntime(bool aIsQuick, void* aData)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
IterateData data;
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
bool disabled;
|
||||
if (!mWorkerPrivate->BlockAndCollectRuntimeStats(&data, &disabled)) {
|
||||
if (!mWorkerPrivate->BlockAndCollectRuntimeStats(aIsQuick, aData, &disabled)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -217,12 +214,35 @@ public:
|
|||
mWorkerPrivate = nsnull;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
CollectReports(nsIMemoryMultiReporterCallback* aCallback,
|
||||
nsISupports* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
IterateData data;
|
||||
nsresult rv = CollectForRuntime(/* isQuick = */false, &data);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Always report, even if we're disabled, so that we at least get an entry
|
||||
// in about::memory.
|
||||
ReportJSRuntimeStats(data, mPathPrefix, aCallback, aClosure);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetExplicitNonHeap(PRInt64 *aAmount)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
return CollectForRuntime(/* isQuick = */true, aAmount);
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(WorkerMemoryReporter, nsIMemoryMultiReporter)
|
||||
|
@ -1378,16 +1398,17 @@ class CollectRuntimeStatsRunnable : public WorkerControlRunnable
|
|||
Mutex mMutex;
|
||||
CondVar mCondVar;
|
||||
volatile bool mDone;
|
||||
IterateData* mData;
|
||||
bool mIsQuick;
|
||||
void* mData;
|
||||
bool* mSucceeded;
|
||||
|
||||
public:
|
||||
CollectRuntimeStatsRunnable(WorkerPrivate* aWorkerPrivate, IterateData* aData,
|
||||
bool* aSucceeded)
|
||||
CollectRuntimeStatsRunnable(WorkerPrivate* aWorkerPrivate, bool aIsQuick,
|
||||
void* aData, bool* aSucceeded)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread, UnchangedBusyCount),
|
||||
mMutex("CollectRuntimeStatsRunnable::mMutex"),
|
||||
mCondVar(mMutex, "CollectRuntimeStatsRunnable::mCondVar"), mDone(false),
|
||||
mData(aData), mSucceeded(aSucceeded)
|
||||
mIsQuick(aIsQuick), mData(aData), mSucceeded(aSucceeded)
|
||||
{ }
|
||||
|
||||
bool
|
||||
|
@ -1429,7 +1450,9 @@ public:
|
|||
{
|
||||
JSAutoSuspendRequest asr(aCx);
|
||||
|
||||
*mSucceeded = CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
|
||||
*mSucceeded = mIsQuick ?
|
||||
mozilla::xpconnect::memory::GetExplicitNonHeapForRuntime(JS_GetRuntime(aCx), mData) :
|
||||
mozilla::xpconnect::memory::CollectCompartmentStatsForRuntime(JS_GetRuntime(aCx), mData);
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
@ -2569,7 +2592,7 @@ WorkerPrivate::ScheduleDeletion(bool aWasPending)
|
|||
}
|
||||
|
||||
bool
|
||||
WorkerPrivate::BlockAndCollectRuntimeStats(IterateData* aData, bool* aDisabled)
|
||||
WorkerPrivate::BlockAndCollectRuntimeStats(bool aIsQuick, void* aData, bool* aDisabled)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
NS_ASSERTION(aData, "Null data!");
|
||||
|
@ -2589,7 +2612,7 @@ WorkerPrivate::BlockAndCollectRuntimeStats(IterateData* aData, bool* aDisabled)
|
|||
bool succeeded;
|
||||
|
||||
nsRefPtr<CollectRuntimeStatsRunnable> runnable =
|
||||
new CollectRuntimeStatsRunnable(this, aData, &succeeded);
|
||||
new CollectRuntimeStatsRunnable(this, aIsQuick, aData, &succeeded);
|
||||
if (!runnable->Dispatch(nsnull)) {
|
||||
NS_WARNING("Failed to dispatch runnable!");
|
||||
succeeded = false;
|
||||
|
|
|
@ -661,8 +661,7 @@ public:
|
|||
ScheduleDeletion(bool aWasPending);
|
||||
|
||||
bool
|
||||
BlockAndCollectRuntimeStats(mozilla::xpconnect::memory::IterateData* aData,
|
||||
bool* aDisabled);
|
||||
BlockAndCollectRuntimeStats(bool isQuick, void* aData, bool* aDisabled);
|
||||
|
||||
bool
|
||||
DisableMemoryReporter();
|
||||
|
|
|
@ -43,7 +43,7 @@ interface nsISelection;
|
|||
interface nsIEditor;
|
||||
interface nsIEditorSpellCheck;
|
||||
|
||||
[scriptable, uuid(f456dda1-965d-470c-8c55-e51b38e45212)]
|
||||
[scriptable, uuid(df635540-d073-47b8-8678-18776130691d)]
|
||||
|
||||
interface nsIInlineSpellChecker : nsISupports
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ interface nsIInlineSpellChecker : nsISupports
|
|||
nsIDOMRange getMisspelledWord(in nsIDOMNode aNode, in long aOffset);
|
||||
void replaceWord(in nsIDOMNode aNode, in long aOffset, in AString aNewword);
|
||||
void addWordToDictionary(in AString aWord);
|
||||
void removeWordFromDictionary(in AString aWord);
|
||||
|
||||
void ignoreWord(in AString aWord);
|
||||
void ignoreWords([array, size_is(aCount)] in wstring aWordsToIgnore, in unsigned long aCount);
|
||||
|
|
|
@ -869,6 +869,24 @@ mozInlineSpellChecker::AddWordToDictionary(const nsAString &word)
|
|||
return ScheduleSpellCheck(status);
|
||||
}
|
||||
|
||||
// mozInlineSpellChecker::RemoveWordFromDictionary
|
||||
|
||||
NS_IMETHODIMP
|
||||
mozInlineSpellChecker::RemoveWordFromDictionary(const nsAString &word)
|
||||
{
|
||||
NS_ENSURE_TRUE(mSpellCheck, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
nsAutoString wordstr(word);
|
||||
nsresult rv = mSpellCheck->RemoveWordFromDictionary(wordstr.get());
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mozInlineSpellStatus status(this);
|
||||
nsCOMPtr<nsIRange> range = do_QueryInterface(NULL); // Check everything
|
||||
rv = status.InitForRange(range);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return ScheduleSpellCheck(status);
|
||||
}
|
||||
|
||||
// mozInlineSpellChecker::IgnoreWord
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
diff --git a/gfx/ycbcr/yuv_convert.cpp b/gfx/ycbcr/yuv_convert.cpp
|
||||
--- a/gfx/ycbcr/yuv_convert.cpp
|
||||
+++ b/gfx/ycbcr/yuv_convert.cpp
|
||||
@@ -337,16 +337,17 @@ NS_GFX_(void) ScaleYCbCrToRGB32(const ui
|
||||
source_dx_uv >> kFractionBits);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ScaleYUVToRGB32Row_C(y_ptr, u_ptr, v_ptr,
|
||||
dest_pixel, width, source_dx);
|
||||
}
|
||||
#else
|
||||
+ (void)source_dx_uv;
|
||||
ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
||||
dest_pixel, width, source_dx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
// MMX used for FastConvertYUVToRGB32Row and FilterRows requires emms.
|
||||
if (has_mmx)
|
||||
EMMS();
|
||||
diff --git a/gfx/ycbcr/yuv_row.h b/gfx/ycbcr/yuv_row.h
|
||||
--- a/gfx/ycbcr/yuv_row.h
|
||||
+++ b/gfx/ycbcr/yuv_row.h
|
||||
@@ -129,14 +129,14 @@ extern SIMD_ALIGNED(int16 kCoefficientsR
|
||||
#if defined(ARCH_CPU_X86) && !defined(ARCH_CPU_X86_64)
|
||||
#if defined(_MSC_VER)
|
||||
#define EMMS() __asm emms
|
||||
#pragma warning(disable: 4799)
|
||||
#else
|
||||
#define EMMS() asm("emms")
|
||||
#endif
|
||||
#else
|
||||
-#define EMMS()
|
||||
+#define EMMS() ((void)0)
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // MEDIA_BASE_YUV_ROW_H_
|
|
@ -25,5 +25,3 @@ convert.patch contains the following changes:
|
|||
win64.patch: SSE2 optimization for Microsoft Visual C++ x64 version
|
||||
|
||||
TypeFromSize.patch: Bug 656185 - Add a method to detect YUVType from plane sizes.
|
||||
|
||||
QuellGccWarnings.patch: Bug 711895 - Avoid some GCC compilation warnings.
|
||||
|
|
|
@ -9,4 +9,3 @@ cp $1/media/base/yuv_row_posix.cc yuv_row_c.cpp
|
|||
patch -p3 <convert.patch
|
||||
patch -p3 <win64.patch
|
||||
patch -p3 <TypeFromSize.patch
|
||||
patch -p3 <QuellGccWarnings.patch
|
||||
|
|
|
@ -342,7 +342,6 @@ NS_GFX_(void) ScaleYCbCrToRGB32(const uint8* y_buf,
|
|||
dest_pixel, width, source_dx);
|
||||
}
|
||||
#else
|
||||
(void)source_dx_uv;
|
||||
ScaleYUVToRGB32Row(y_ptr, u_ptr, v_ptr,
|
||||
dest_pixel, width, source_dx);
|
||||
#endif
|
||||
|
|
|
@ -134,7 +134,7 @@ extern SIMD_ALIGNED(int16 kCoefficientsRgbY[768][4]);
|
|||
#define EMMS() asm("emms")
|
||||
#endif
|
||||
#else
|
||||
#define EMMS() ((void)0)
|
||||
#define EMMS()
|
||||
#endif
|
||||
|
||||
} // extern "C"
|
||||
|
|
|
@ -181,7 +181,7 @@ class HashTable : private AllocPolicy
|
|||
friend class HashTable;
|
||||
|
||||
Range(Entry *c, Entry *e) : cur(c), end(e) {
|
||||
while (cur != end && !cur->isLive())
|
||||
while (cur < end && !cur->isLive())
|
||||
++cur;
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,8 @@ class HashTable : private AllocPolicy
|
|||
|
||||
void popFront() {
|
||||
JS_ASSERT(!empty());
|
||||
while (++cur != end && !cur->isLive());
|
||||
while (++cur < end && !cur->isLive())
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -342,14 +343,14 @@ class HashTable : private AllocPolicy
|
|||
Entry *newTable = (Entry *)alloc.malloc_(capacity * sizeof(Entry));
|
||||
if (!newTable)
|
||||
return NULL;
|
||||
for (Entry *e = newTable, *end = e + capacity; e != end; ++e)
|
||||
for (Entry *e = newTable, *end = e + capacity; e < end; ++e)
|
||||
new(e) Entry();
|
||||
return newTable;
|
||||
}
|
||||
|
||||
static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32_t capacity)
|
||||
{
|
||||
for (Entry *e = oldTable, *end = e + capacity; e != end; ++e)
|
||||
for (Entry *e = oldTable, *end = e + capacity; e < end; ++e)
|
||||
e->~Entry();
|
||||
alloc.free_(oldTable);
|
||||
}
|
||||
|
@ -565,7 +566,7 @@ class HashTable : private AllocPolicy
|
|||
table = newTable;
|
||||
|
||||
/* Copy only live entries, leaving removed ones behind. */
|
||||
for (Entry *src = oldTable, *end = src + oldCap; src != end; ++src) {
|
||||
for (Entry *src = oldTable, *end = src + oldCap; src < end; ++src) {
|
||||
if (src->isLive()) {
|
||||
src->unsetCollision();
|
||||
findFreeEntry(src->getKeyHash()) = Move(*src);
|
||||
|
@ -607,7 +608,7 @@ class HashTable : private AllocPolicy
|
|||
memset(table, 0, sizeof(*table) * capacity());
|
||||
} else {
|
||||
uint32_t tableCapacity = capacity();
|
||||
for (Entry *e = table, *end = table + tableCapacity; e != end; ++e)
|
||||
for (Entry *e = table, *end = table + tableCapacity; e < end; ++e)
|
||||
*e = Move(Entry());
|
||||
}
|
||||
removedCount = 0;
|
||||
|
|
|
@ -1806,20 +1806,14 @@ if test "$GNU_CC"; then
|
|||
_MOZ_RTTI_FLAGS_ON=-frtti
|
||||
_MOZ_RTTI_FLAGS_OFF=-fno-rtti
|
||||
|
||||
# Turn on GNU-specific warnings:
|
||||
# -Wall - turn on a lot of warnings
|
||||
# -pedantic - this is turned on below
|
||||
# -Wpointer-arith - enabled with -pedantic, but good to have even if not
|
||||
# -Wdeclaration-after-statement - MSVC doesn't like these
|
||||
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
|
||||
#
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -Wpointer-arith -Wdeclaration-after-statement -Wempty-body"
|
||||
|
||||
# Turn off the following warnings that -Wall/-pedantic turn on:
|
||||
# -Woverlength-strings - we exceed the minimum maximum length all the time
|
||||
#
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wno-overlength-strings"
|
||||
|
||||
# Turn on GNU specific features
|
||||
# -Wall - turn on all warnings
|
||||
# -pedantic - make compiler warn about non-ANSI stuff, and
|
||||
# be a little bit stricter
|
||||
# Warnings slamm took out for now (these were giving more noise than help):
|
||||
# -Wbad-function-cast - warns when casting a function to a new return type
|
||||
# -Wshadow - removed because it generates more noise than help --pete
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wall -W -Wno-unused -Wpointer-arith"
|
||||
if test -z "$INTEL_CC" -a -z "$CLANG_CC"; then
|
||||
# Don't use -Wcast-align with ICC or clang
|
||||
case "$CPU_ARCH" in
|
||||
|
@ -1835,26 +1829,12 @@ if test "$GNU_CC"; then
|
|||
dnl Turn pedantic on but disable the warnings for long long
|
||||
_PEDANTIC=1
|
||||
|
||||
if test -z "$INTEL_CC"; then
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -W"
|
||||
fi
|
||||
|
||||
_DEFINES_CFLAGS='-include $(DEPTH)/js-confdefs.h -DMOZILLA_CLIENT'
|
||||
_USE_CPP_INCLUDE_FLAG=1
|
||||
|
||||
AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
|
||||
ac_cc_has_wtype_limits,
|
||||
[
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_C
|
||||
_SAVE_CFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Wtype-limits"
|
||||
AC_TRY_COMPILE([],
|
||||
[return(0);],
|
||||
ac_cc_has_wtype_limits="yes",
|
||||
ac_cc_has_wtype_limits="no")
|
||||
CFLAGS="$_SAVE_CFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
if test "$ac_cc_has_wtype_limits" = "yes"; then
|
||||
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Wtype-limits"
|
||||
fi
|
||||
elif test "$SOLARIS_SUNPRO_CC"; then
|
||||
DSO_CFLAGS=''
|
||||
if test "$CPU_ARCH" = "sparc"; then
|
||||
|
@ -1880,21 +1860,8 @@ else
|
|||
fi
|
||||
|
||||
if test "$GNU_CXX"; then
|
||||
# Turn on GNU-specific warnings:
|
||||
# -Wall - turn on a lot of warnings
|
||||
# -pedantic - this is turned on below
|
||||
# -Wpointer-arith - enabled with -pedantic, but good to have even if not
|
||||
# -Woverloaded-virtual - ???
|
||||
# -Wempty-body - catches bugs, e.g. "if (c); foo();", few false positives
|
||||
#
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wempty-body"
|
||||
|
||||
# Turn off the following warnings that -Wall/-pedantic turn on:
|
||||
# -Woverlength-strings - we exceed the minimum maximum length all the time
|
||||
# -Wctor-dtor-privacy - ???
|
||||
#
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wno-overlength-strings -Wno-ctor-dtor-privacy"
|
||||
|
||||
# Turn on GNU specific features
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wall -Wpointer-arith -Woverloaded-virtual -Wsynth -Wno-ctor-dtor-privacy -Wno-non-virtual-dtor"
|
||||
if test -z "$INTEL_CXX" -a -z "$CLANG_CXX"; then
|
||||
# Don't use -Wcast-align with ICC or clang
|
||||
case "$CPU_ARCH" in
|
||||
|
@ -1995,24 +1962,6 @@ if test "$GNU_CXX"; then
|
|||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=return-type"
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK(whether the compiler supports -Wtype-limits,
|
||||
ac_has_wtype_limits,
|
||||
[
|
||||
AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -Wtype-limits"
|
||||
AC_TRY_COMPILE([],
|
||||
[return(0);],
|
||||
ac_has_wtype_limits="yes",
|
||||
ac_has_wtype_limits="no")
|
||||
CXXFLAGS="$_SAVE_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
if test "$ac_has_wtype_limits" = "yes"; then
|
||||
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Wtype-limits"
|
||||
fi
|
||||
|
||||
else
|
||||
_DEFINES_CXXFLAGS='-DMOZILLA_CLIENT -D_JS_CONFDEFS_H_ $(ACDEFINES)'
|
||||
fi
|
||||
|
|
|
@ -1863,23 +1863,29 @@ EmitIndexOp(JSContext *cx, JSOp op, uintN index, BytecodeEmitter *bce, JSOp *psu
|
|||
JS_END_MACRO
|
||||
|
||||
static bool
|
||||
EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL)
|
||||
EmitAtomOp(JSContext *cx, JSAtom *atom, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL)
|
||||
{
|
||||
JS_ASSERT(JOF_OPTYPE(op) == JOF_ATOM);
|
||||
|
||||
if (op == JSOP_GETPROP &&
|
||||
pn->pn_atom == cx->runtime->atomState.lengthAtom) {
|
||||
if (op == JSOP_GETPROP && atom == cx->runtime->atomState.lengthAtom) {
|
||||
/* Specialize length accesses for the interpreter. */
|
||||
op = JSOP_LENGTH;
|
||||
}
|
||||
|
||||
jsatomid index;
|
||||
if (!bce->makeAtomIndex(pn->pn_atom, &index))
|
||||
if (!bce->makeAtomIndex(atom, &index))
|
||||
return false;
|
||||
|
||||
return EmitIndexOp(cx, op, index, bce, psuffix);
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitAtomOp(JSContext *cx, ParseNode *pn, JSOp op, BytecodeEmitter *bce, JSOp *psuffix = NULL)
|
||||
{
|
||||
JS_ASSERT(pn->pn_atom != NULL);
|
||||
return EmitAtomOp(cx, pn->pn_atom, op, bce, psuffix);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
EmitObjectOp(JSContext *cx, ObjectBox *objbox, JSOp op, BytecodeEmitter *bce)
|
||||
{
|
||||
|
@ -5478,16 +5484,16 @@ EmitXMLTag(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
}
|
||||
|
||||
static bool
|
||||
EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
EmitXMLProcessingInstruction(JSContext *cx, BytecodeEmitter *bce, XMLProcessingInstruction &pi)
|
||||
{
|
||||
JS_ASSERT(!bce->inStrictMode());
|
||||
|
||||
jsatomid index;
|
||||
if (!bce->makeAtomIndex(pn->pn_pidata, &index))
|
||||
if (!bce->makeAtomIndex(pi.data(), &index))
|
||||
return false;
|
||||
if (!EmitIndexOp(cx, JSOP_QNAMEPART, index, bce))
|
||||
return false;
|
||||
if (!EmitAtomOp(cx, pn, JSOP_XMLPI, bce))
|
||||
if (!EmitAtomOp(cx, pi.target(), JSOP_XMLPI, bce))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
@ -6766,16 +6772,16 @@ EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrd
|
|||
}
|
||||
|
||||
static bool
|
||||
EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ConditionalExpression &conditional)
|
||||
{
|
||||
/* Emit the condition, then branch if false to the else part. */
|
||||
if (!EmitTree(cx, bce, pn->pn_kid1))
|
||||
if (!EmitTree(cx, bce, &conditional.condition()))
|
||||
return false;
|
||||
ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_COND);
|
||||
if (noteIndex < 0)
|
||||
return false;
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
|
||||
if (beq < 0 || !EmitTree(cx, bce, pn->pn_kid2))
|
||||
if (beq < 0 || !EmitTree(cx, bce, &conditional.thenExpression()))
|
||||
return false;
|
||||
|
||||
/* Jump around else, fixup the branch, emit else, fixup jump. */
|
||||
|
@ -6796,7 +6802,7 @@ EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
*/
|
||||
JS_ASSERT(bce->stackDepth > 0);
|
||||
bce->stackDepth--;
|
||||
if (!EmitTree(cx, bce, pn->pn_kid3))
|
||||
if (!EmitTree(cx, bce, &conditional.elseExpression()))
|
||||
return false;
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, bce, jmp);
|
||||
return SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq);
|
||||
|
@ -7221,8 +7227,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
return false;
|
||||
break;
|
||||
|
||||
case PNK_HOOK:
|
||||
ok = EmitConditionalExpression(cx, bce, pn);
|
||||
case PNK_CONDITIONAL:
|
||||
ok = EmitConditionalExpression(cx, bce, pn->asConditionalExpression());
|
||||
break;
|
||||
|
||||
case PNK_OR:
|
||||
|
@ -7441,7 +7447,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
case PNK_DEFSHARP:
|
||||
{
|
||||
JS_ASSERT(bce->hasSharps());
|
||||
int sharpnum = pn->pn_num;
|
||||
jsint sharpnum = pn->asDefSharpExpression().number();
|
||||
pn = pn->pn_kid;
|
||||
if (pn->isKind(PNK_RB)) {
|
||||
ok = EmitArray(cx, bce, pn, sharpnum);
|
||||
|
@ -7460,13 +7466,14 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
|
||||
if (!EmitTree(cx, bce, pn))
|
||||
return JS_FALSE;
|
||||
EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, bce->sharpSlotBase, (jsatomid) sharpnum);
|
||||
EMIT_UINT16PAIR_IMM_OP(JSOP_DEFSHARP, bce->sharpSlotBase, jsatomid(sharpnum));
|
||||
break;
|
||||
}
|
||||
|
||||
case PNK_USESHARP:
|
||||
JS_ASSERT(bce->hasSharps());
|
||||
EMIT_UINT16PAIR_IMM_OP(JSOP_USESHARP, bce->sharpSlotBase, (jsatomid) pn->pn_num);
|
||||
EMIT_UINT16PAIR_IMM_OP(JSOP_USESHARP, bce->sharpSlotBase,
|
||||
jsatomid(pn->asUseSharpExpression().number()));
|
||||
break;
|
||||
#endif /* JS_HAS_SHARP_VARS */
|
||||
|
||||
|
@ -7594,7 +7601,7 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
|||
break;
|
||||
|
||||
case PNK_XMLPI:
|
||||
if (!EmitXMLProcessingInstruction(cx, bce, pn))
|
||||
if (!EmitXMLProcessingInstruction(cx, bce, pn->asXMLProcessingInstruction()))
|
||||
return false;
|
||||
break;
|
||||
#endif /* JS_HAS_XML_SUPPORT */
|
||||
|
|
|
@ -273,11 +273,13 @@ FoldXMLConstants(JSContext *cx, ParseNode *pn, TreeContext *tc)
|
|||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
case PNK_XMLPI:
|
||||
str = js_MakeXMLPIString(cx, pn2->pn_pitarget, pn2->pn_pidata);
|
||||
case PNK_XMLPI: {
|
||||
XMLProcessingInstruction &pi = pn2->asXMLProcessingInstruction();
|
||||
str = js_MakeXMLPIString(cx, pi.target(), pi.data());
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
cantfold:
|
||||
default:
|
||||
|
@ -556,7 +558,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
|||
break;
|
||||
/* FALL THROUGH */
|
||||
|
||||
case PNK_HOOK:
|
||||
case PNK_CONDITIONAL:
|
||||
/* Reduce 'if (C) T; else E' into T for true C, E for false. */
|
||||
switch (pn1->getKind()) {
|
||||
case PNK_NUMBER:
|
||||
|
@ -591,8 +593,8 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
|||
* False condition and no else, or an empty then-statement was
|
||||
* moved up over pn. Either way, make pn an empty block (not an
|
||||
* empty statement, which does not decompile, even when labeled).
|
||||
* NB: pn must be a PNK_IF as PNK_HOOK can never have a null kid
|
||||
* or an empty statement for a child.
|
||||
* NB: pn must be a PNK_IF as PNK_CONDITIONAL can never have a null
|
||||
* kid or an empty statement for a child.
|
||||
*/
|
||||
pn->setKind(PNK_STATEMENTLIST);
|
||||
pn->setArity(PN_LIST);
|
||||
|
|
|
@ -535,7 +535,7 @@ CloneParseTree(ParseNode *opn, TreeContext *tc)
|
|||
|
||||
case PN_UNARY:
|
||||
NULLCHECK(pn->pn_kid = CloneParseTree(opn->pn_kid, tc));
|
||||
pn->pn_num = opn->pn_num;
|
||||
pn->pn_u.unary.num = opn->pn_u.unary.num;
|
||||
pn->pn_hidden = opn->pn_hidden;
|
||||
break;
|
||||
|
||||
|
|
|
@ -41,6 +41,8 @@
|
|||
#ifndef ParseNode_h__
|
||||
#define ParseNode_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "frontend/ParseMaps.h"
|
||||
|
@ -61,7 +63,7 @@ namespace js {
|
|||
enum ParseNodeKind {
|
||||
PNK_SEMI,
|
||||
PNK_COMMA,
|
||||
PNK_HOOK,
|
||||
PNK_CONDITIONAL,
|
||||
PNK_COLON,
|
||||
PNK_OR,
|
||||
PNK_AND,
|
||||
|
@ -313,7 +315,8 @@ enum ParseNodeKind {
|
|||
* PNK_MULASSIGN,
|
||||
* PNK_DIVASSIGN,
|
||||
* PNK_MODASSIGN
|
||||
* PNK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
|
||||
* pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* PNK_OR binary pn_left: first in || chain, pn_right: rest of chain
|
||||
* PNK_AND binary pn_left: first in && chain, pn_right: rest of chain
|
||||
* PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
|
||||
|
@ -485,6 +488,10 @@ struct Definition;
|
|||
class LoopControlStatement;
|
||||
class BreakStatement;
|
||||
class ContinueStatement;
|
||||
class XMLProcessingInstruction;
|
||||
class ConditionalExpression;
|
||||
class DefSharpExpression;
|
||||
class UseSharpExpression;
|
||||
|
||||
struct ParseNode {
|
||||
private:
|
||||
|
@ -495,6 +502,8 @@ struct ParseNode {
|
|||
pn_used : 1, /* name node is on a use-chain */
|
||||
pn_defn : 1; /* this node is a Definition */
|
||||
|
||||
void operator=(const ParseNode &other) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
|
||||
: pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
|
||||
|
@ -590,7 +599,7 @@ struct ParseNode {
|
|||
} binary;
|
||||
struct { /* one kid if unary */
|
||||
ParseNode *kid;
|
||||
jsint num; /* -1 or sharp variable number */
|
||||
jsint num; /* sharp variable number or unused */
|
||||
JSBool hidden; /* hidden genexp-induced JSOP_YIELD
|
||||
or directive prologue member (as
|
||||
pn_prologue) */
|
||||
|
@ -617,15 +626,20 @@ struct ParseNode {
|
|||
AtomDefnMapPtr defnMap;
|
||||
ParseNode *tree; /* sub-tree containing name uses */
|
||||
} nameset;
|
||||
struct { /* PN_NULLARY variant for E4X XML PI */
|
||||
PropertyName *target; /* target in <?target data?> */
|
||||
JSAtom *data; /* data (or null) in <?target data?> */
|
||||
} xmlpi;
|
||||
jsdouble dval; /* aligned numeric literal value */
|
||||
class {
|
||||
friend class LoopControlStatement;
|
||||
PropertyName *label; /* target of break/continue statement */
|
||||
} loopControl;
|
||||
class { /* E4X <?target data?> XML PI */
|
||||
friend class XMLProcessingInstruction;
|
||||
PropertyName *target; /* non-empty */
|
||||
JSAtom *data; /* may be empty, never null */
|
||||
} xmlpi;
|
||||
class {
|
||||
friend class UseSharpExpression;
|
||||
jsint number; /* #number# */
|
||||
} usesharp;
|
||||
} pn_u;
|
||||
|
||||
#define pn_funbox pn_u.name.funbox
|
||||
|
@ -646,7 +660,6 @@ struct ParseNode {
|
|||
#define pn_pval pn_u.binary.pval
|
||||
#define pn_iflags pn_u.binary.iflags
|
||||
#define pn_kid pn_u.unary.kid
|
||||
#define pn_num pn_u.unary.num
|
||||
#define pn_hidden pn_u.unary.hidden
|
||||
#define pn_prologue pn_u.unary.hidden
|
||||
#define pn_atom pn_u.name.atom
|
||||
|
@ -656,8 +669,6 @@ struct ParseNode {
|
|||
#define pn_names pn_u.nameset.defnMap
|
||||
#define pn_tree pn_u.nameset.tree
|
||||
#define pn_dval pn_u.dval
|
||||
#define pn_pitarget pn_u.xmlpi.target
|
||||
#define pn_pidata pn_u.xmlpi.data
|
||||
|
||||
protected:
|
||||
void init(TokenKind type, JSOp op, ParseNodeArity arity) {
|
||||
|
@ -924,6 +935,12 @@ struct ParseNode {
|
|||
/* Casting operations. */
|
||||
inline BreakStatement &asBreakStatement();
|
||||
inline ContinueStatement &asContinueStatement();
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
inline XMLProcessingInstruction &asXMLProcessingInstruction();
|
||||
#endif
|
||||
inline ConditionalExpression &asConditionalExpression();
|
||||
inline DefSharpExpression &asDefSharpExpression();
|
||||
inline UseSharpExpression &asUseSharpExpression();
|
||||
};
|
||||
|
||||
struct NullaryNode : public ParseNode {
|
||||
|
@ -1059,6 +1076,145 @@ ParseNode::asContinueStatement()
|
|||
return *static_cast<ContinueStatement *>(this);
|
||||
}
|
||||
|
||||
class DebuggerStatement : public ParseNode {
|
||||
public:
|
||||
DebuggerStatement(const TokenPos &pos)
|
||||
: ParseNode(PNK_DEBUGGER, JSOP_NOP, PN_NULLARY, pos)
|
||||
{ }
|
||||
};
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
class XMLProcessingInstruction : public ParseNode {
|
||||
public:
|
||||
XMLProcessingInstruction(PropertyName *target, JSAtom *data, const TokenPos &pos)
|
||||
: ParseNode(PNK_XMLPI, JSOP_NOP, PN_NULLARY, pos)
|
||||
{
|
||||
pn_u.xmlpi.target = target;
|
||||
pn_u.xmlpi.data = data;
|
||||
}
|
||||
|
||||
PropertyName *target() const {
|
||||
return pn_u.xmlpi.target;
|
||||
}
|
||||
|
||||
JSAtom *data() const {
|
||||
return pn_u.xmlpi.data;
|
||||
}
|
||||
};
|
||||
|
||||
inline XMLProcessingInstruction &
|
||||
ParseNode::asXMLProcessingInstruction()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_XMLPI));
|
||||
JS_ASSERT(isOp(JSOP_NOP));
|
||||
JS_ASSERT(pn_arity == PN_NULLARY);
|
||||
return *static_cast<XMLProcessingInstruction *>(this);
|
||||
}
|
||||
#endif
|
||||
|
||||
class ConditionalExpression : public ParseNode {
|
||||
public:
|
||||
ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr)
|
||||
: ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
|
||||
TokenPos::make(condition->pn_pos.begin, elseExpr->pn_pos.end))
|
||||
{
|
||||
JS_ASSERT(condition);
|
||||
JS_ASSERT(thenExpr);
|
||||
JS_ASSERT(elseExpr);
|
||||
pn_u.ternary.kid1 = condition;
|
||||
pn_u.ternary.kid2 = thenExpr;
|
||||
pn_u.ternary.kid3 = elseExpr;
|
||||
}
|
||||
|
||||
ParseNode &condition() const {
|
||||
return *pn_u.ternary.kid1;
|
||||
}
|
||||
|
||||
ParseNode &thenExpression() const {
|
||||
return *pn_u.ternary.kid2;
|
||||
}
|
||||
|
||||
ParseNode &elseExpression() const {
|
||||
return *pn_u.ternary.kid3;
|
||||
}
|
||||
};
|
||||
|
||||
inline ConditionalExpression &
|
||||
ParseNode::asConditionalExpression()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_CONDITIONAL));
|
||||
JS_ASSERT(isOp(JSOP_NOP));
|
||||
JS_ASSERT(pn_arity == PN_TERNARY);
|
||||
return *static_cast<ConditionalExpression *>(this);
|
||||
}
|
||||
|
||||
class DefSharpExpression : public ParseNode {
|
||||
public:
|
||||
DefSharpExpression(uint16_t number, ParseNode *expr,
|
||||
const TokenPtr &begin, const TokenPtr &end)
|
||||
: ParseNode(PNK_DEFSHARP, JSOP_NOP, PN_UNARY, TokenPos::make(begin, end))
|
||||
{
|
||||
pn_u.unary.num = number;
|
||||
pn_u.unary.kid = expr;
|
||||
}
|
||||
|
||||
jsint number() const {
|
||||
return pn_u.unary.num;
|
||||
}
|
||||
|
||||
ParseNode &expression() const {
|
||||
return *pn_u.unary.kid;
|
||||
}
|
||||
};
|
||||
|
||||
inline DefSharpExpression &
|
||||
ParseNode::asDefSharpExpression()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_DEFSHARP));
|
||||
JS_ASSERT(isOp(JSOP_NOP));
|
||||
JS_ASSERT(pn_arity == PN_UNARY);
|
||||
return *static_cast<DefSharpExpression *>(this);
|
||||
}
|
||||
|
||||
class UseSharpExpression : public ParseNode {
|
||||
public:
|
||||
UseSharpExpression(uint16_t number, const TokenPos &pos)
|
||||
: ParseNode(PNK_USESHARP, JSOP_NOP, PN_NULLARY, pos)
|
||||
{
|
||||
pn_u.usesharp.number = number;
|
||||
}
|
||||
|
||||
jsint number() const {
|
||||
return pn_u.usesharp.number;
|
||||
}
|
||||
};
|
||||
|
||||
inline UseSharpExpression &
|
||||
ParseNode::asUseSharpExpression()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_USESHARP));
|
||||
JS_ASSERT(isOp(JSOP_NOP));
|
||||
JS_ASSERT(pn_arity == PN_NULLARY);
|
||||
return *static_cast<UseSharpExpression *>(this);
|
||||
}
|
||||
|
||||
class ThisLiteral : public ParseNode {
|
||||
public:
|
||||
ThisLiteral(const TokenPos &pos) : ParseNode(PNK_THIS, JSOP_THIS, PN_NULLARY, pos) { }
|
||||
};
|
||||
|
||||
class NullLiteral : public ParseNode {
|
||||
public:
|
||||
NullLiteral(const TokenPos &pos) : ParseNode(PNK_NULL, JSOP_NULL, PN_NULLARY, pos) { }
|
||||
};
|
||||
|
||||
class BooleanLiteral : public ParseNode {
|
||||
public:
|
||||
BooleanLiteral(bool b, const TokenPos &pos)
|
||||
: ParseNode(b ? PNK_TRUE : PNK_FALSE, b ? JSOP_TRUE : JSOP_FALSE, PN_NULLARY, pos)
|
||||
{ }
|
||||
};
|
||||
|
||||
ParseNode *
|
||||
CloneLeftHandSide(ParseNode *opn, TreeContext *tc);
|
||||
|
||||
|
|
|
@ -2931,7 +2931,6 @@ Parser::letBlock(LetContext letContext)
|
|||
if (!semi)
|
||||
return NULL;
|
||||
|
||||
semi->pn_num = -1;
|
||||
semi->pn_kid = pnlet;
|
||||
|
||||
letContext = LetExpresion;
|
||||
|
@ -4226,7 +4225,7 @@ Parser::statement()
|
|||
return pn;
|
||||
|
||||
case TOK_DEBUGGER:
|
||||
pn = NullaryNode::create(PNK_DEBUGGER, tc);
|
||||
pn = tc->parser->new_<DebuggerStatement>(tokenStream.currentToken().pos);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
tc->flags |= TCF_FUN_HEAVYWEIGHT;
|
||||
|
@ -4643,37 +4642,30 @@ Parser::orExpr1()
|
|||
JS_ALWAYS_INLINE ParseNode *
|
||||
Parser::condExpr1()
|
||||
{
|
||||
ParseNode *pn = orExpr1();
|
||||
if (pn && tokenStream.isCurrentTokenType(TOK_HOOK)) {
|
||||
ParseNode *pn1 = pn;
|
||||
pn = TernaryNode::create(PNK_HOOK, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
ParseNode *condition = orExpr1();
|
||||
if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
|
||||
return condition;
|
||||
|
||||
/*
|
||||
* Always accept the 'in' operator in the middle clause of a ternary,
|
||||
* where it's unambiguous, even if we might be parsing the init of a
|
||||
* for statement.
|
||||
*/
|
||||
uintN oldflags = tc->flags;
|
||||
tc->flags &= ~TCF_IN_FOR_INIT;
|
||||
ParseNode *pn2 = assignExpr();
|
||||
tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
|
||||
/*
|
||||
* Always accept the 'in' operator in the middle clause of a ternary,
|
||||
* where it's unambiguous, even if we might be parsing the init of a
|
||||
* for statement.
|
||||
*/
|
||||
uintN oldflags = tc->flags;
|
||||
tc->flags &= ~TCF_IN_FOR_INIT;
|
||||
ParseNode *thenExpr = assignExpr();
|
||||
tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
|
||||
if (!thenExpr)
|
||||
return NULL;
|
||||
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
|
||||
ParseNode *pn3 = assignExpr();
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
pn->pn_pos.begin = pn1->pn_pos.begin;
|
||||
pn->pn_pos.end = pn3->pn_pos.end;
|
||||
pn->pn_kid1 = pn1;
|
||||
pn->pn_kid2 = pn2;
|
||||
pn->pn_kid3 = pn3;
|
||||
tokenStream.getToken(); /* need to read one token past the end */
|
||||
}
|
||||
return pn;
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
|
||||
|
||||
ParseNode *elseExpr = assignExpr();
|
||||
if (!elseExpr)
|
||||
return NULL;
|
||||
|
||||
tokenStream.getToken(); /* read one token past the end */
|
||||
return new_<ConditionalExpression>(condition, thenExpr, elseExpr);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -6363,13 +6355,10 @@ Parser::xmlElementContent(ParseNode *pn)
|
|||
pn2->pn_xflags &= ~PNX_XMLROOT;
|
||||
pn->pn_xflags |= pn2->pn_xflags;
|
||||
} else if (tt == TOK_XMLPI) {
|
||||
pn2 = NullaryNode::create(PNK_XMLPI, tc);
|
||||
const Token &tok = tokenStream.currentToken();
|
||||
pn2 = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
|
||||
if (!pn2)
|
||||
return false;
|
||||
const Token &tok = tokenStream.currentToken();
|
||||
pn2->setOp(tok.t_op);
|
||||
pn2->pn_pitarget = tok.xmlPITarget();
|
||||
pn2->pn_pidata = tok.xmlPIData();
|
||||
} else {
|
||||
JS_ASSERT(tt == TOK_XMLCDATA || tt == TOK_XMLCOMMENT);
|
||||
pn2 = atomNode(tt == TOK_XMLCDATA ? PNK_XMLCDATA : PNK_XMLCOMMENT,
|
||||
|
@ -6576,16 +6565,6 @@ Parser::parseXMLText(JSObject *chain, bool allowList)
|
|||
|
||||
#endif /* JS_HAS_XMLSUPPORT */
|
||||
|
||||
static ParseNode *
|
||||
PrimaryExprNode(ParseNodeKind kind, JSOp op, TreeContext *tc)
|
||||
{
|
||||
ParseNode *pn = NullaryNode::create(kind, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->setOp(op);
|
||||
return pn;
|
||||
}
|
||||
|
||||
ParseNode *
|
||||
Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
||||
{
|
||||
|
@ -6954,40 +6933,45 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
#endif
|
||||
|
||||
#if JS_HAS_SHARP_VARS
|
||||
case TOK_DEFSHARP:
|
||||
pn = UnaryNode::create(PNK_DEFSHARP, tc);
|
||||
if (!pn)
|
||||
case TOK_DEFSHARP: {
|
||||
if (!tc->ensureSharpSlots())
|
||||
return NULL;
|
||||
pn->pn_num = tokenStream.currentToken().sharpNumber();
|
||||
const Token &tok = tokenStream.currentToken();
|
||||
TokenPtr begin = tok.pos.begin;
|
||||
uint16_t number = tok.sharpNumber();
|
||||
|
||||
tt = tokenStream.getToken(TSF_OPERAND);
|
||||
pn->pn_kid = primaryExpr(tt, JS_FALSE);
|
||||
if (!pn->pn_kid)
|
||||
ParseNode *expr = primaryExpr(tt, false);
|
||||
if (!expr)
|
||||
return NULL;
|
||||
if (pn->pn_kid->isKind(PNK_USESHARP) ||
|
||||
pn->pn_kid->isKind(PNK_DEFSHARP) ||
|
||||
pn->pn_kid->isKind(PNK_STRING) ||
|
||||
pn->pn_kid->isKind(PNK_NUMBER) ||
|
||||
pn->pn_kid->isKind(PNK_TRUE) ||
|
||||
pn->pn_kid->isKind(PNK_FALSE) ||
|
||||
pn->pn_kid->isKind(PNK_NULL) ||
|
||||
pn->pn_kid->isKind(PNK_THIS))
|
||||
if (expr->isKind(PNK_USESHARP) ||
|
||||
expr->isKind(PNK_DEFSHARP) ||
|
||||
expr->isKind(PNK_STRING) ||
|
||||
expr->isKind(PNK_NUMBER) ||
|
||||
expr->isKind(PNK_TRUE) ||
|
||||
expr->isKind(PNK_FALSE) ||
|
||||
expr->isKind(PNK_NULL) ||
|
||||
expr->isKind(PNK_THIS))
|
||||
{
|
||||
reportErrorNumber(pn->pn_kid, JSREPORT_ERROR, JSMSG_BAD_SHARP_VAR_DEF);
|
||||
reportErrorNumber(expr, JSREPORT_ERROR, JSMSG_BAD_SHARP_VAR_DEF);
|
||||
return NULL;
|
||||
}
|
||||
if (!tc->ensureSharpSlots())
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
case TOK_USESHARP:
|
||||
/* Check for forward/dangling references at runtime, to allow eval. */
|
||||
pn = NullaryNode::create(PNK_USESHARP, tc);
|
||||
pn = new_<DefSharpExpression>(number, expr, begin, tokenStream.currentToken().pos.end);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_USESHARP: {
|
||||
if (!tc->ensureSharpSlots())
|
||||
return NULL;
|
||||
pn->pn_num = tokenStream.currentToken().sharpNumber();
|
||||
/* Check for forward/dangling references at runtime, to allow eval. */
|
||||
const Token &tok = tokenStream.currentToken();
|
||||
pn = new_<UseSharpExpression>(tok.sharpNumber(), tok.pos);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
#endif /* JS_HAS_SHARP_VARS */
|
||||
|
||||
case TOK_LP:
|
||||
|
@ -7053,14 +7037,14 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
break;
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
case TOK_XMLPI:
|
||||
case TOK_XMLPI: {
|
||||
JS_ASSERT(!tc->inStrictMode());
|
||||
pn = NullaryNode::create(PNK_XMLPI, tc);
|
||||
const Token &tok = tokenStream.currentToken();
|
||||
pn = new_<XMLProcessingInstruction>(tok.xmlPITarget(), tok.xmlPIData(), tok.pos);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_pitarget = tokenStream.currentToken().xmlPITarget();
|
||||
pn->pn_pidata = tokenStream.currentToken().xmlPIData();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
case TOK_NAME:
|
||||
|
@ -7223,13 +7207,13 @@ Parser::primaryExpr(TokenKind tt, JSBool afterDot)
|
|||
break;
|
||||
|
||||
case TOK_TRUE:
|
||||
return PrimaryExprNode(PNK_TRUE, JSOP_TRUE, tc);
|
||||
return new_<BooleanLiteral>(true, tokenStream.currentToken().pos);
|
||||
case TOK_FALSE:
|
||||
return PrimaryExprNode(PNK_FALSE, JSOP_FALSE, tc);
|
||||
return new_<BooleanLiteral>(false, tokenStream.currentToken().pos);
|
||||
case TOK_THIS:
|
||||
return PrimaryExprNode(PNK_THIS, JSOP_THIS, tc);
|
||||
return new_<ThisLiteral>(tokenStream.currentToken().pos);
|
||||
case TOK_NULL:
|
||||
return PrimaryExprNode(PNK_NULL, JSOP_NULL, tc);
|
||||
return new_<NullLiteral>(tokenStream.currentToken().pos);
|
||||
|
||||
case TOK_ERROR:
|
||||
/* The scanner or one of its subroutines reported the error. */
|
||||
|
|
|
@ -330,8 +330,8 @@ struct Token {
|
|||
private:
|
||||
friend struct Token;
|
||||
struct { /* pair for <?target data?> XML PI */
|
||||
JSAtom *data; /* auxiliary atom table entry */
|
||||
PropertyName *target; /* main atom table entry */
|
||||
PropertyName *target; /* non-empty */
|
||||
JSAtom *data; /* maybe empty, never null */
|
||||
} xmlpi;
|
||||
uint16_t sharpNumber; /* sharp variable number: #1# or #1= */
|
||||
jsdouble number; /* floating point number */
|
||||
|
@ -359,6 +359,9 @@ struct Token {
|
|||
}
|
||||
|
||||
void setProcessingInstruction(PropertyName *target, JSAtom *data) {
|
||||
JS_ASSERT(target);
|
||||
JS_ASSERT(data);
|
||||
JS_ASSERT(!target->empty());
|
||||
u.xmlpi.target = target;
|
||||
u.xmlpi.data = data;
|
||||
}
|
||||
|
|
|
@ -426,6 +426,7 @@ class ReadBarriered
|
|||
T *value;
|
||||
|
||||
public:
|
||||
ReadBarriered() : value(NULL) {}
|
||||
ReadBarriered(T *value) : value(value) {}
|
||||
|
||||
T *get() const {
|
||||
|
@ -437,6 +438,9 @@ class ReadBarriered
|
|||
|
||||
operator T*() const { return get(); }
|
||||
|
||||
T &operator*() const { return *get(); }
|
||||
T *operator->() const { return get(); }
|
||||
|
||||
T *unsafeGet() { return value; }
|
||||
|
||||
void set(T *v) { value = v; }
|
||||
|
|
|
@ -404,24 +404,11 @@ DoGetElement(JSContext *cx, JSObject *obj, uint32_t index, JSBool *hole, Value *
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
static void
|
||||
AssertGreaterThanZero(IndexType index)
|
||||
{
|
||||
JS_ASSERT(index >= 0);
|
||||
}
|
||||
|
||||
template<>
|
||||
void
|
||||
AssertGreaterThanZero(jsuint index)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename IndexType>
|
||||
static JSBool
|
||||
GetElement(JSContext *cx, JSObject *obj, IndexType index, JSBool *hole, Value *vp)
|
||||
{
|
||||
AssertGreaterThanZero(index);
|
||||
JS_ASSERT(index >= 0);
|
||||
if (obj->isDenseArray() && index < obj->getDenseArrayInitializedLength() &&
|
||||
!(*vp = obj->getDenseArrayElement(uint32_t(index))).isMagic(JS_ARRAY_HOLE)) {
|
||||
*hole = JS_FALSE;
|
||||
|
|
|
@ -104,7 +104,6 @@ ThreadData::ThreadData(JSRuntime *rt)
|
|||
#ifdef JS_THREADSAFE
|
||||
requestDepth(0),
|
||||
#endif
|
||||
waiveGCQuota(false),
|
||||
tempLifoAlloc(TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE),
|
||||
execAlloc(NULL),
|
||||
bumpAlloc(NULL),
|
||||
|
@ -152,17 +151,22 @@ ThreadData::sizeOfExcludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal,
|
|||
* The computedSize is 0 because sizeof(DtoaState) isn't available here and
|
||||
* it's not worth making it available.
|
||||
*/
|
||||
*normal = mallocSizeOf(dtoaState, /* sizeof(DtoaState) */0);
|
||||
if (normal)
|
||||
*normal = mallocSizeOf(dtoaState, /* sizeof(DtoaState) */0);
|
||||
|
||||
*temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
if (temporary)
|
||||
*temporary = tempLifoAlloc.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
size_t method = 0, regexp = 0, unused = 0;
|
||||
if (execAlloc)
|
||||
execAlloc->sizeOfCode(&method, ®exp, &unused);
|
||||
JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */
|
||||
*regexpCode = regexp + unused;
|
||||
if (regexpCode) {
|
||||
size_t method = 0, regexp = 0, unused = 0;
|
||||
if (execAlloc)
|
||||
execAlloc->sizeOfCode(&method, ®exp, &unused);
|
||||
JS_ASSERT(method == 0); /* this execAlloc is only used for regexp code */
|
||||
*regexpCode = regexp + unused;
|
||||
}
|
||||
|
||||
*stackCommitted = stackSpace.sizeOfCommitted();
|
||||
if (stackCommitted)
|
||||
*stackCommitted = stackSpace.sizeOfCommitted();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -253,7 +257,8 @@ JSThread::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf, size_t *normal, si
|
|||
size_t *regexpCode, size_t *stackCommitted)
|
||||
{
|
||||
data.sizeOfExcludingThis(mallocSizeOf, normal, temporary, regexpCode, stackCommitted);
|
||||
*normal += mallocSizeOf(this, sizeof(JSThread));
|
||||
if (normal)
|
||||
*normal += mallocSizeOf(this, sizeof(JSThread));
|
||||
}
|
||||
|
||||
JSThread *
|
||||
|
@ -1593,13 +1598,13 @@ JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
|
|||
* Retry when we are done with the background sweeping and have stopped
|
||||
* all the allocations and released the empty GC chunks.
|
||||
*/
|
||||
{
|
||||
ShrinkGCBuffers(this);
|
||||
#ifdef JS_THREADSAFE
|
||||
{
|
||||
AutoLockGC lock(this);
|
||||
gcHelperThread.waitBackgroundSweepOrAllocEnd();
|
||||
#endif
|
||||
gcChunkPool.expire(this, true);
|
||||
}
|
||||
#endif
|
||||
if (!p)
|
||||
p = OffTheBooks::malloc_(nbytes);
|
||||
else if (p == reinterpret_cast<void *>(1))
|
||||
|
|
|
@ -140,12 +140,6 @@ struct ThreadData {
|
|||
/* Keeper of the contiguous stack used by all contexts in this thread. */
|
||||
StackSpace stackSpace;
|
||||
|
||||
/*
|
||||
* Flag indicating that we are waiving any soft limits on the GC heap
|
||||
* because we want allocations to be infallible (except when we hit OOM).
|
||||
*/
|
||||
bool waiveGCQuota;
|
||||
|
||||
/* Temporary arena pool used while compiling and decompiling. */
|
||||
static const size_t TEMP_LIFO_ALLOC_PRIMARY_CHUNK_SIZE = 1 << 12;
|
||||
LifoAlloc tempLifoAlloc;
|
||||
|
|
|
@ -125,12 +125,18 @@ JS_NewObjectWithUniqueType(JSContext *cx, JSClass *clasp, JSObject *proto, JSObj
|
|||
return obj;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_FRIEND_API(void)
|
||||
JS_ShrinkingGC(JSContext *cx)
|
||||
{
|
||||
js_GC(cx, NULL, GC_SHRINK, gcstats::PUBLIC_API);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JS_ShrinkGCBuffers(JSRuntime *rt)
|
||||
{
|
||||
ShrinkGCBuffers(rt);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSPrincipals *)
|
||||
JS_GetCompartmentPrincipals(JSCompartment *compartment)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,9 @@ JS_ObjectCountDynamicSlots(JSObject *obj);
|
|||
extern JS_FRIEND_API(void)
|
||||
JS_ShrinkingGC(JSContext *cx);
|
||||
|
||||
extern JS_FRIEND_API(void)
|
||||
JS_ShrinkGCBuffers(JSRuntime *rt);
|
||||
|
||||
extern JS_FRIEND_API(size_t)
|
||||
JS_GetE4XObjectsCreated(JSContext *cx);
|
||||
|
||||
|
|
225
js/src/jsgc.cpp
225
js/src/jsgc.cpp
|
@ -517,6 +517,22 @@ ChunkPool::expire(JSRuntime *rt, bool releaseAll)
|
|||
return freeList;
|
||||
}
|
||||
|
||||
static void
|
||||
FreeChunkList(Chunk *chunkListHead)
|
||||
{
|
||||
while (Chunk *chunk = chunkListHead) {
|
||||
JS_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
chunkListHead = chunk->info.next;
|
||||
FreeChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ChunkPool::expireAndFree(JSRuntime *rt, bool releaseAll)
|
||||
{
|
||||
FreeChunkList(expire(rt, releaseAll));
|
||||
}
|
||||
|
||||
JS_FRIEND_API(int64_t)
|
||||
ChunkPool::countCleanDecommittedArenas(JSRuntime *rt)
|
||||
{
|
||||
|
@ -553,16 +569,6 @@ Chunk::release(JSRuntime *rt, Chunk *chunk)
|
|||
FreeChunk(chunk);
|
||||
}
|
||||
|
||||
static void
|
||||
FreeChunkList(Chunk *chunkListHead)
|
||||
{
|
||||
while (Chunk *chunk = chunkListHead) {
|
||||
JS_ASSERT(!chunk->info.numArenasFreeCommitted);
|
||||
chunkListHead = chunk->info.next;
|
||||
FreeChunk(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
Chunk::prepareToBeFreed(JSRuntime *rt)
|
||||
{
|
||||
|
@ -923,11 +929,12 @@ InFreeList(ArenaHeader *aheader, uintptr_t addr)
|
|||
}
|
||||
|
||||
/*
|
||||
* Returns CGCT_VALID and mark it if the w can be a live GC thing and sets
|
||||
* thingKind accordingly. Otherwise returns the reason for rejection.
|
||||
* Tests whether w is a (possibly dead) GC thing. Returns CGCT_VALID and
|
||||
* details about the thing if so. On failure, returns the reason for rejection.
|
||||
*/
|
||||
inline ConservativeGCTest
|
||||
MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
||||
IsAddressableGCThing(JSRuntime *rt, jsuword w,
|
||||
gc::AllocKind *thingKindPtr, ArenaHeader **arenaHeader, void **thing)
|
||||
{
|
||||
/*
|
||||
* We assume that the compiler never uses sub-word alignment to store
|
||||
|
@ -953,7 +960,7 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
|||
|
||||
Chunk *chunk = Chunk::fromAddress(addr);
|
||||
|
||||
if (!trc->runtime->gcChunkSet.has(chunk))
|
||||
if (!rt->gcChunkSet.has(chunk))
|
||||
return CGCT_NOTCHUNK;
|
||||
|
||||
/*
|
||||
|
@ -974,7 +981,7 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
|||
if (!aheader->allocated())
|
||||
return CGCT_FREEARENA;
|
||||
|
||||
JSCompartment *curComp = trc->runtime->gcCurrentCompartment;
|
||||
JSCompartment *curComp = rt->gcCurrentCompartment;
|
||||
if (curComp && curComp != aheader->compartment)
|
||||
return CGCT_OTHERCOMPARTMENT;
|
||||
|
||||
|
@ -988,20 +995,41 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
|||
uintptr_t shift = (offset - minOffset) % Arena::thingSize(thingKind);
|
||||
addr -= shift;
|
||||
|
||||
if (thing)
|
||||
*thing = reinterpret_cast<void *>(addr);
|
||||
if (arenaHeader)
|
||||
*arenaHeader = aheader;
|
||||
if (thingKindPtr)
|
||||
*thingKindPtr = thingKind;
|
||||
return CGCT_VALID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns CGCT_VALID and mark it if the w can be a live GC thing and sets
|
||||
* thingKind accordingly. Otherwise returns the reason for rejection.
|
||||
*/
|
||||
inline ConservativeGCTest
|
||||
MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
||||
{
|
||||
void *thing;
|
||||
ArenaHeader *aheader;
|
||||
AllocKind thingKind;
|
||||
ConservativeGCTest status = IsAddressableGCThing(trc->runtime, w, &thingKind, &aheader, &thing);
|
||||
if (status != CGCT_VALID)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* Check if the thing is free. We must use the list of free spans as at
|
||||
* this point we no longer have the mark bits from the previous GC run and
|
||||
* we must account for newly allocated things.
|
||||
*/
|
||||
if (InFreeList(aheader, addr))
|
||||
if (InFreeList(aheader, uintptr_t(thing)))
|
||||
return CGCT_NOTLIVE;
|
||||
|
||||
void *thing = reinterpret_cast<void *>(addr);
|
||||
|
||||
#ifdef DEBUG
|
||||
const char pattern[] = "machine_stack %lx";
|
||||
char nameBuf[sizeof(pattern) - 3 + sizeof(addr) * 2];
|
||||
JS_snprintf(nameBuf, sizeof(nameBuf), "machine_stack %lx", (unsigned long) addr);
|
||||
char nameBuf[sizeof(pattern) - 3 + sizeof(thing) * 2];
|
||||
JS_snprintf(nameBuf, sizeof(nameBuf), "machine_stack %lx", (unsigned long) thing);
|
||||
JS_SET_TRACING_NAME(trc, nameBuf);
|
||||
#endif
|
||||
MarkKind(trc, thing, MapAllocToTraceKind(thingKind));
|
||||
|
@ -1011,10 +1039,11 @@ MarkIfGCThingWord(JSTracer *trc, jsuword w)
|
|||
GCMarker *marker = static_cast<GCMarker *>(trc);
|
||||
if (marker->conservativeDumpFileName)
|
||||
marker->conservativeRoots.append(thing);
|
||||
if (shift)
|
||||
if (jsuword(thing) != w)
|
||||
marker->conservativeStats.unaligned++;
|
||||
}
|
||||
#endif
|
||||
|
||||
return CGCT_VALID;
|
||||
}
|
||||
|
||||
|
@ -1154,6 +1183,12 @@ RecordNativeStackTopForGC(JSContext *cx)
|
|||
|
||||
} /* namespace js */
|
||||
|
||||
bool
|
||||
js_IsAddressableGCThing(JSRuntime *rt, jsuword w, gc::AllocKind *thingKind, void **thing)
|
||||
{
|
||||
return js::IsAddressableGCThing(rt, w, thingKind, NULL, thing) == CGCT_VALID;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
CheckLeakedRoots(JSRuntime *rt);
|
||||
|
@ -1182,7 +1217,7 @@ js_FinishGC(JSRuntime *rt)
|
|||
* Finish the pool after the background thread stops in case it was doing
|
||||
* the background sweeping.
|
||||
*/
|
||||
FreeChunkList(rt->gcChunkPool.expire(rt, true));
|
||||
rt->gcChunkPool.expireAndFree(rt, true);
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!rt->gcRootsHash.empty())
|
||||
|
@ -1342,7 +1377,7 @@ JSRuntime::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
|||
void
|
||||
JSRuntime::reduceGCTriggerBytes(uint32_t amount) {
|
||||
JS_ASSERT(amount > 0);
|
||||
JS_ASSERT(gcTriggerBytes >= amount);
|
||||
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||
if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
|
||||
return;
|
||||
gcTriggerBytes -= amount;
|
||||
|
@ -1361,7 +1396,7 @@ JSCompartment::setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind)
|
|||
void
|
||||
JSCompartment::reduceGCTriggerBytes(uint32_t amount) {
|
||||
JS_ASSERT(amount > 0);
|
||||
JS_ASSERT(gcTriggerBytes >= amount);
|
||||
JS_ASSERT(gcTriggerBytes - amount >= 0);
|
||||
if (gcTriggerBytes - amount < GC_ALLOCATION_THRESHOLD * GC_HEAP_GROWTH_FACTOR)
|
||||
return;
|
||||
gcTriggerBytes -= amount;
|
||||
|
@ -1641,12 +1676,6 @@ RunLastDitchGC(JSContext *cx)
|
|||
#endif
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsGCAllowed(JSContext *cx)
|
||||
{
|
||||
return !JS_THREAD_DATA(cx)->waiveGCQuota;
|
||||
}
|
||||
|
||||
/* static */ void *
|
||||
ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
||||
{
|
||||
|
@ -1658,7 +1687,7 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
|||
|
||||
bool runGC = !!rt->gcIsNeeded;
|
||||
for (;;) {
|
||||
if (JS_UNLIKELY(runGC) && IsGCAllowed(cx)) {
|
||||
if (JS_UNLIKELY(runGC)) {
|
||||
RunLastDitchGC(cx);
|
||||
|
||||
/* Report OOM of the GC failed to free enough memory. */
|
||||
|
@ -1679,14 +1708,11 @@ ArenaLists::refillFreeList(JSContext *cx, AllocKind thingKind)
|
|||
return thing;
|
||||
|
||||
/*
|
||||
* We failed to allocate. Run the GC if we can unless we have done it
|
||||
* already. Otherwise report OOM but first schedule a new GC soon.
|
||||
* We failed to allocate. Run the GC if we haven't done it already.
|
||||
* Otherwise report OOM.
|
||||
*/
|
||||
if (runGC || !IsGCAllowed(cx)) {
|
||||
AutoLockGC lock(rt);
|
||||
TriggerGC(rt, gcstats::REFILL);
|
||||
if (runGC)
|
||||
break;
|
||||
}
|
||||
runGC = true;
|
||||
}
|
||||
|
||||
|
@ -2397,28 +2423,53 @@ GCHelperThread::threadLoop()
|
|||
}
|
||||
|
||||
bool
|
||||
GCHelperThread::prepareForBackgroundSweep(JSContext *cx)
|
||||
GCHelperThread::prepareForBackgroundSweep()
|
||||
{
|
||||
JS_ASSERT(cx->runtime == rt);
|
||||
JS_ASSERT(state == IDLE);
|
||||
size_t maxArenaLists = MAX_BACKGROUND_FINALIZE_KINDS * rt->compartments.length();
|
||||
if (!finalizeVector.reserve(maxArenaLists))
|
||||
return false;
|
||||
context = cx;
|
||||
return true;
|
||||
return finalizeVector.reserve(maxArenaLists);
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void
|
||||
GCHelperThread::startBackgroundSweep(bool shouldShrink)
|
||||
void
|
||||
GCHelperThread::startBackgroundSweep(JSContext *cx, bool shouldShrink)
|
||||
{
|
||||
/* The caller takes the GC lock. */
|
||||
JS_ASSERT(state == IDLE);
|
||||
JS_ASSERT(cx);
|
||||
JS_ASSERT(!finalizationContext);
|
||||
finalizationContext = cx;
|
||||
shrinkFlag = shouldShrink;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::startBackgroundShrink()
|
||||
{
|
||||
switch (state) {
|
||||
case IDLE:
|
||||
JS_ASSERT(!finalizationContext);
|
||||
shrinkFlag = true;
|
||||
state = SWEEPING;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
break;
|
||||
case SWEEPING:
|
||||
shrinkFlag = true;
|
||||
break;
|
||||
case ALLOCATING:
|
||||
case CANCEL_ALLOCATION:
|
||||
/*
|
||||
* If we have started background allocation there is nothing to
|
||||
* shrink.
|
||||
*/
|
||||
break;
|
||||
case SHUTDOWN:
|
||||
JS_NOT_REACHED("No shrink on shutdown");
|
||||
}
|
||||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void
|
||||
GCHelperThread::waitBackgroundSweepEnd()
|
||||
|
@ -2470,9 +2521,8 @@ GCHelperThread::replenishAndFreeLater(void *ptr)
|
|||
void
|
||||
GCHelperThread::doSweep()
|
||||
{
|
||||
JS_ASSERT(context);
|
||||
|
||||
{
|
||||
if (JSContext *cx = finalizationContext) {
|
||||
finalizationContext = NULL;
|
||||
AutoUnlockGC unlock(rt);
|
||||
|
||||
/*
|
||||
|
@ -2480,11 +2530,9 @@ GCHelperThread::doSweep()
|
|||
* finalizeObjects.
|
||||
*/
|
||||
for (ArenaHeader **i = finalizeVector.begin(); i != finalizeVector.end(); ++i)
|
||||
ArenaLists::backgroundFinalize(context, *i);
|
||||
ArenaLists::backgroundFinalize(cx, *i);
|
||||
finalizeVector.resize(0);
|
||||
|
||||
context = NULL;
|
||||
|
||||
if (freeCursor) {
|
||||
void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
|
||||
freeElementsAndArray(array, freeCursor);
|
||||
|
@ -2499,7 +2547,18 @@ GCHelperThread::doSweep()
|
|||
freeVector.resize(0);
|
||||
}
|
||||
|
||||
ExpireChunksAndArenas(rt, shouldShrink());
|
||||
bool shrinking = shrinkFlag;
|
||||
ExpireChunksAndArenas(rt, shrinking);
|
||||
|
||||
/*
|
||||
* The main thread may have called ShrinkGCBuffers while
|
||||
* ExpireChunksAndArenas(rt, false) was running, so we recheck the flag
|
||||
* afterwards.
|
||||
*/
|
||||
if (!shrinking && shrinkFlag) {
|
||||
shrinkFlag = false;
|
||||
ExpireChunksAndArenas(rt, true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
@ -2982,7 +3041,7 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
rt->gcHelperThread.waitBackgroundSweepOrAllocEnd();
|
||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||
if (rt->gcHelperThread.prepareForBackgroundSweep(cx))
|
||||
if (rt->gcHelperThread.prepareForBackgroundSweep())
|
||||
cx->gcBackgroundFree = &rt->gcHelperThread;
|
||||
}
|
||||
#endif
|
||||
|
@ -2993,12 +3052,10 @@ GCCycle(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind)
|
|||
js_PurgeThreads_PostGlobalSweep(cx);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (gckind != GC_LAST_CONTEXT && rt->state != JSRTS_LANDING) {
|
||||
if (cx->gcBackgroundFree) {
|
||||
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
||||
cx->gcBackgroundFree = NULL;
|
||||
rt->gcHelperThread.startBackgroundSweep(gckind == GC_SHRINK);
|
||||
} else {
|
||||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
rt->gcHelperThread.startBackgroundSweep(cx, gckind == GC_SHRINK);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -3076,6 +3133,18 @@ js_GC(JSContext *cx, JSCompartment *comp, JSGCInvocationKind gckind, gcstats::Re
|
|||
|
||||
namespace js {
|
||||
|
||||
void
|
||||
ShrinkGCBuffers(JSRuntime *rt)
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
JS_ASSERT(!rt->gcRunning);
|
||||
#ifndef JS_THREADSAFE
|
||||
ExpireChunksAndArenas(rt, true);
|
||||
#else
|
||||
rt->gcHelperThread.startBackgroundShrink();
|
||||
#endif
|
||||
}
|
||||
|
||||
class AutoCopyFreeListToArenas {
|
||||
JSRuntime *rt;
|
||||
|
||||
|
@ -3154,6 +3223,28 @@ struct IterateCellCallbackOp
|
|||
void operator()(Cell *cell) { (*callback)(cx, data, cell, traceKind, thingSize); }
|
||||
};
|
||||
|
||||
void
|
||||
IterateCompartments(JSContext *cx, void *data,
|
||||
IterateCompartmentCallback compartmentCallback)
|
||||
{
|
||||
CHECK_REQUEST(cx);
|
||||
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JS_ASSERT(!rt->gcRunning);
|
||||
|
||||
AutoLockGC lock(rt);
|
||||
AutoGCSession gcsession(cx);
|
||||
#ifdef JS_THREADSAFE
|
||||
rt->gcHelperThread.waitBackgroundSweepEnd();
|
||||
#endif
|
||||
AutoUnlockGC unlock(rt);
|
||||
|
||||
AutoCopyFreeListToArenas copy(rt);
|
||||
for (CompartmentsIter c(rt); !c.done(); c.next()) {
|
||||
(*compartmentCallback)(cx, data, c);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
IterateCompartmentsArenasCells(JSContext *cx, void *data,
|
||||
IterateCompartmentCallback compartmentCallback,
|
||||
|
@ -3279,19 +3370,17 @@ void
|
|||
RunDebugGC(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
if (IsGCAllowed(cx)) {
|
||||
JSRuntime *rt = cx->runtime;
|
||||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
/*
|
||||
* If rt->gcDebugCompartmentGC is true, only GC the current
|
||||
* compartment. But don't GC the atoms compartment.
|
||||
*/
|
||||
rt->gcTriggerCompartment = rt->gcDebugCompartmentGC ? cx->compartment : NULL;
|
||||
if (rt->gcTriggerCompartment == rt->atomsCompartment)
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
/*
|
||||
* If rt->gcDebugCompartmentGC is true, only GC the current
|
||||
* compartment. But don't GC the atoms compartment.
|
||||
*/
|
||||
rt->gcTriggerCompartment = rt->gcDebugCompartmentGC ? cx->compartment : NULL;
|
||||
if (rt->gcTriggerCompartment == rt->atomsCompartment)
|
||||
rt->gcTriggerCompartment = NULL;
|
||||
|
||||
RunLastDitchGC(cx);
|
||||
}
|
||||
RunLastDitchGC(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -808,6 +808,9 @@ class ChunkPool {
|
|||
*/
|
||||
Chunk *expire(JSRuntime *rt, bool releaseAll);
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void expireAndFree(JSRuntime *rt, bool releaseAll);
|
||||
|
||||
/* Must be called either during the GC or with the GC lock taken. */
|
||||
JS_FRIEND_API(int64_t) countCleanDecommittedArenas(JSRuntime *rt);
|
||||
};
|
||||
|
@ -1360,6 +1363,9 @@ js_GCThingIsMarked(void *thing, uintN color);
|
|||
extern void
|
||||
js_TraceStackFrame(JSTracer *trc, js::StackFrame *fp);
|
||||
|
||||
extern bool
|
||||
js_IsAddressableGCThing(JSRuntime *rt, jsuword w, js::gc::AllocKind *thingKind, void **thing);
|
||||
|
||||
namespace js {
|
||||
|
||||
extern JS_REQUIRES_STACK void
|
||||
|
@ -1382,6 +1388,9 @@ TriggerCompartmentGC(JSCompartment *comp, js::gcstats::Reason reason);
|
|||
extern void
|
||||
MaybeGC(JSContext *cx);
|
||||
|
||||
extern void
|
||||
ShrinkGCBuffers(JSRuntime *rt);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
|
@ -1453,7 +1462,7 @@ class GCHelperThread {
|
|||
PRCondVar *done;
|
||||
volatile State state;
|
||||
|
||||
JSContext *context;
|
||||
JSContext *finalizationContext;
|
||||
bool shrinkFlag;
|
||||
|
||||
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
||||
|
@ -1489,6 +1498,8 @@ class GCHelperThread {
|
|||
wakeup(NULL),
|
||||
done(NULL),
|
||||
state(IDLE),
|
||||
finalizationContext(NULL),
|
||||
shrinkFlag(false),
|
||||
freeCursor(NULL),
|
||||
freeCursorEnd(NULL),
|
||||
backgroundAllocation(true)
|
||||
|
@ -1498,7 +1509,10 @@ class GCHelperThread {
|
|||
void finish();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
inline void startBackgroundSweep(bool shouldShrink);
|
||||
void startBackgroundSweep(JSContext *cx, bool shouldShrink);
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void startBackgroundShrink();
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
void waitBackgroundSweepEnd();
|
||||
|
@ -1543,7 +1557,7 @@ class GCHelperThread {
|
|||
}
|
||||
|
||||
/* Must be called with the GC lock taken. */
|
||||
bool prepareForBackgroundSweep(JSContext *cx);
|
||||
bool prepareForBackgroundSweep();
|
||||
};
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
@ -1772,6 +1786,12 @@ typedef void (*IterateArenaCallback)(JSContext *cx, void *data, gc::Arena *arena
|
|||
typedef void (*IterateCellCallback)(JSContext *cx, void *data, void *thing,
|
||||
JSGCTraceKind traceKind, size_t thingSize);
|
||||
|
||||
/*
|
||||
* This function calls |compartmentCallback| on every compartment.
|
||||
*/
|
||||
extern JS_FRIEND_API(void)
|
||||
IterateCompartments(JSContext *cx, void *data,
|
||||
IterateCompartmentCallback compartmentCallback);
|
||||
/*
|
||||
* This function calls |compartmentCallback| on every compartment,
|
||||
* |arenaCallback| on every in-use arena, and |cellCallback| on every in-use
|
||||
|
|
|
@ -2617,7 +2617,7 @@ struct types::ObjectTableKey
|
|||
|
||||
struct types::ObjectTableEntry
|
||||
{
|
||||
TypeObject *object;
|
||||
ReadBarriered<TypeObject> object;
|
||||
Type *types;
|
||||
};
|
||||
|
||||
|
@ -5837,9 +5837,6 @@ JSObject::getNewType(JSContext *cx, JSFunction *fun)
|
|||
if (type->newScript && type->newScript->fun != fun)
|
||||
type->clearNewScript(cx);
|
||||
|
||||
if (cx->compartment->needsBarrier())
|
||||
TypeObject::readBarrier(type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -5905,9 +5902,6 @@ JSCompartment::getLazyType(JSContext *cx, JSObject *proto)
|
|||
TypeObject *type = *p;
|
||||
JS_ASSERT(type->lazy());
|
||||
|
||||
if (cx->compartment->needsBarrier())
|
||||
TypeObject::readBarrier(type);
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
|
|
|
@ -898,7 +898,7 @@ struct TypeObjectEntry
|
|||
static inline HashNumber hash(JSObject *base);
|
||||
static inline bool match(TypeObject *key, JSObject *lookup);
|
||||
};
|
||||
typedef HashSet<TypeObject *, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
|
||||
typedef HashSet<ReadBarriered<TypeObject>, TypeObjectEntry, SystemAllocPolicy> TypeObjectSet;
|
||||
|
||||
/*
|
||||
* Call to mark a script's arguments as having been created, recompile any
|
||||
|
@ -1120,14 +1120,14 @@ class TypeScript
|
|||
};
|
||||
|
||||
struct ArrayTableKey;
|
||||
typedef HashMap<ArrayTableKey,TypeObject*,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
|
||||
typedef HashMap<ArrayTableKey,ReadBarriered<TypeObject>,ArrayTableKey,SystemAllocPolicy> ArrayTypeTable;
|
||||
|
||||
struct ObjectTableKey;
|
||||
struct ObjectTableEntry;
|
||||
typedef HashMap<ObjectTableKey,ObjectTableEntry,ObjectTableKey,SystemAllocPolicy> ObjectTypeTable;
|
||||
|
||||
struct AllocationSiteKey;
|
||||
typedef HashMap<AllocationSiteKey,TypeObject*,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
|
||||
typedef HashMap<AllocationSiteKey,ReadBarriered<TypeObject>,AllocationSiteKey,SystemAllocPolicy> AllocationSiteTable;
|
||||
|
||||
/* Type information for a compartment. */
|
||||
struct TypeCompartment
|
||||
|
|
|
@ -1279,9 +1279,8 @@ TypeObject::readBarrier(TypeObject *type)
|
|||
{
|
||||
#ifdef JSGC_INCREMENTAL
|
||||
JSCompartment *comp = type->compartment();
|
||||
JS_ASSERT(comp->needsBarrier());
|
||||
|
||||
MarkTypeObjectUnbarriered(comp->barrierTracer(), type, "read barrier");
|
||||
if (comp->needsBarrier())
|
||||
MarkTypeObjectUnbarriered(comp->barrierTracer(), type, "read barrier");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,8 @@
|
|||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
|
||||
#include "methodjit/Compiler.h"
|
||||
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#define TYPEOF(cx,v) (JSVAL_IS_NULL(v) ? JSTYPE_NULL : JS_TypeOfValue(cx,v))
|
||||
|
@ -115,15 +117,114 @@ Probes::JITGranularityRequested()
|
|||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
/*
|
||||
* Flatten the tree of inlined frames into a series of native code regions, one
|
||||
* for each contiguous section of native code that belongs to a single
|
||||
* ActiveFrame. (Note that some of these regions may be zero-length, for
|
||||
* example if two ActiveFrames end at the same place.)
|
||||
*/
|
||||
typedef mjit::Compiler::ActiveFrame ActiveFrame;
|
||||
|
||||
bool
|
||||
Probes::JITWatcher::CollectNativeRegions(RegionVector ®ions,
|
||||
JSRuntime *rt,
|
||||
mjit::JITScript *jit,
|
||||
mjit::JSActiveFrame *outerFrame,
|
||||
mjit::JSActiveFrame **inlineFrames)
|
||||
{
|
||||
regions.resize(jit->nInlineFrames * 2 + 2);
|
||||
|
||||
mjit::JSActiveFrame **stack =
|
||||
rt->array_new<mjit::JSActiveFrame*>(jit->nInlineFrames+2);
|
||||
if (!stack)
|
||||
return false;
|
||||
uint32_t depth = 0;
|
||||
uint32_t ip = 0;
|
||||
|
||||
stack[depth++] = NULL;
|
||||
stack[depth++] = outerFrame;
|
||||
regions[0].frame = outerFrame;
|
||||
regions[0].script = outerFrame->script;
|
||||
regions[0].pc = outerFrame->script->code;
|
||||
regions[0].enter = true;
|
||||
ip++;
|
||||
|
||||
for (uint32_t i = 0; i <= jit->nInlineFrames; i++) {
|
||||
mjit::JSActiveFrame *frame = (i < jit->nInlineFrames) ? inlineFrames[i] : outerFrame;
|
||||
|
||||
// Not a down frame; pop the current frame, then pop until we reach
|
||||
// this frame's parent, recording subframe ends as we go
|
||||
while (stack[depth-1] != frame->parent) {
|
||||
depth--;
|
||||
JS_ASSERT(depth > 0);
|
||||
// Pop up from regions[ip-1].frame to top of the stack: start a
|
||||
// region in the destination frame and close off the source
|
||||
// (origin) frame at the end of its script
|
||||
mjit::JSActiveFrame *src = regions[ip-1].frame;
|
||||
mjit::JSActiveFrame *dst = stack[depth-1];
|
||||
JS_ASSERT_IF(!dst, i == jit->nInlineFrames);
|
||||
regions[ip].frame = dst;
|
||||
regions[ip].script = dst ? dst->script : NULL;
|
||||
regions[ip].pc = src->parentPC + 1;
|
||||
regions[ip-1].endpc = src->script->code + src->script->length;
|
||||
regions[ip].enter = false;
|
||||
ip++;
|
||||
}
|
||||
|
||||
if (i < jit->nInlineFrames) {
|
||||
// Push a frame (enter an inlined function). Start a region at the
|
||||
// beginning of the new frame's script, and end the previous region
|
||||
// at parentPC.
|
||||
stack[depth++] = frame;
|
||||
|
||||
regions[ip].frame = frame;
|
||||
regions[ip].script = frame->script;
|
||||
regions[ip].pc = frame->script->code;
|
||||
regions[ip-1].endpc = frame->parentPC;
|
||||
regions[ip].enter = true;
|
||||
ip++;
|
||||
}
|
||||
}
|
||||
|
||||
// Final region is always zero-length and not particularly useful
|
||||
ip--;
|
||||
regions.popBack();
|
||||
|
||||
mjit::JSActiveFrame *prev = NULL;
|
||||
for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter) {
|
||||
mjit::JSActiveFrame *frame = iter->frame;
|
||||
if (iter->enter) {
|
||||
// Pushing down a frame, so region starts at the beginning of the
|
||||
// (destination) frame
|
||||
iter->mainOffset = frame->mainCodeStart;
|
||||
iter->stubOffset = frame->stubCodeStart;
|
||||
} else {
|
||||
// Popping up a level, so region starts at the end of the (source) frame
|
||||
iter->mainOffset = prev->mainCodeEnd;
|
||||
iter->stubOffset = prev->stubCodeEnd;
|
||||
}
|
||||
prev = frame;
|
||||
}
|
||||
|
||||
JS_ASSERT(ip == 2 * jit->nInlineFrames + 1);
|
||||
rt->array_delete(stack);
|
||||
|
||||
// All of the stub code comes immediately after the main code
|
||||
for (NativeRegion *iter = regions.begin(); iter != regions.end(); ++iter)
|
||||
iter->stubOffset += outerFrame->mainCodeEnd;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Probes::registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
|
||||
JSScript *script, JSFunction *fun,
|
||||
js::mjit::Compiler_ActiveFrame **inlineFrames,
|
||||
js::mjit::JSActiveFrame *outerFrame,
|
||||
js::mjit::JSActiveFrame **inlineFrames,
|
||||
void *mainCodeAddress, size_t mainCodeSize,
|
||||
void *stubCodeAddress, size_t stubCodeSize)
|
||||
{
|
||||
for (JITWatcher **p = jitWatchers.begin(); p != jitWatchers.end(); ++p)
|
||||
(*p)->registerMJITCode(cx, jscr, script, fun,
|
||||
(*p)->registerMJITCode(cx, jscr, outerFrame,
|
||||
inlineFrames,
|
||||
mainCodeAddress, mainCodeSize,
|
||||
stubCodeAddress, stubCodeSize);
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace js {
|
|||
|
||||
namespace mjit {
|
||||
struct NativeAddressInfo;
|
||||
struct Compiler_ActiveFrame;
|
||||
struct JSActiveFrame;
|
||||
}
|
||||
|
||||
namespace Probes {
|
||||
|
@ -230,12 +230,31 @@ enum JITReportGranularity {
|
|||
*/
|
||||
class JITWatcher {
|
||||
public:
|
||||
struct NativeRegion {
|
||||
mjit::JSActiveFrame *frame;
|
||||
JSScript *script;
|
||||
size_t inlinedOffset;
|
||||
jsbytecode *pc;
|
||||
jsbytecode *endpc;
|
||||
uintptr_t mainOffset;
|
||||
uintptr_t stubOffset;
|
||||
bool enter;
|
||||
};
|
||||
|
||||
typedef Vector<NativeRegion, 0, RuntimeAllocPolicy> RegionVector;
|
||||
|
||||
virtual JITReportGranularity granularityRequested() = 0;
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
static bool CollectNativeRegions(RegionVector ®ions,
|
||||
JSRuntime *rt,
|
||||
mjit::JITScript *jit,
|
||||
mjit::JSActiveFrame *outerFrame,
|
||||
mjit::JSActiveFrame **inlineFrames);
|
||||
|
||||
virtual void registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
|
||||
JSScript *script, JSFunction *fun,
|
||||
mjit::Compiler_ActiveFrame** inlineFrames,
|
||||
mjit::JSActiveFrame *outerFrame,
|
||||
mjit::JSActiveFrame **inlineFrames,
|
||||
void *mainCodeAddress, size_t mainCodeSize,
|
||||
void *stubCodeAddress, size_t stubCodeSize) = 0;
|
||||
|
||||
|
@ -282,8 +301,8 @@ JITGranularityRequested();
|
|||
*/
|
||||
void
|
||||
registerMJITCode(JSContext *cx, js::mjit::JITScript *jscr,
|
||||
JSScript *script, JSFunction *fun,
|
||||
mjit::Compiler_ActiveFrame** inlineFrames,
|
||||
mjit::JSActiveFrame *outerFrame,
|
||||
mjit::JSActiveFrame **inlineFrames,
|
||||
void *mainCodeAddress, size_t mainCodeSize,
|
||||
void *stubCodeAddress, size_t stubCodeSize);
|
||||
|
||||
|
|
|
@ -619,8 +619,6 @@ class NodeBuilder
|
|||
|
||||
bool xmlComment(Value text, TokenPos *pos, Value *dst);
|
||||
|
||||
bool xmlPI(Value target, TokenPos *pos, Value *dst);
|
||||
|
||||
bool xmlPI(Value target, Value content, TokenPos *pos, Value *dst);
|
||||
};
|
||||
|
||||
|
@ -1570,12 +1568,6 @@ NodeBuilder::xmlComment(Value text, TokenPos *pos, Value *dst)
|
|||
return newNode(AST_XMLCOMMENT, pos, "contents", text, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::xmlPI(Value target, TokenPos *pos, Value *dst)
|
||||
{
|
||||
return xmlPI(target, NullValue(), pos, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::xmlPI(Value target, Value contents, TokenPos *pos, Value *dst)
|
||||
{
|
||||
|
@ -2410,7 +2402,7 @@ ASTSerializer::expression(ParseNode *pn, Value *dst)
|
|||
builder.sequenceExpression(exprs, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_HOOK:
|
||||
case PNK_CONDITIONAL:
|
||||
{
|
||||
Value test, cons, alt;
|
||||
|
||||
|
@ -2630,13 +2622,16 @@ ASTSerializer::expression(ParseNode *pn, Value *dst)
|
|||
|
||||
case PNK_DEFSHARP:
|
||||
{
|
||||
DefSharpExpression &defsharp = pn->asDefSharpExpression();
|
||||
Value expr;
|
||||
return expression(pn->pn_kid, &expr) &&
|
||||
builder.graphExpression(pn->pn_num, expr, &pn->pn_pos, dst);
|
||||
return expression(&defsharp.expression(), &expr) &&
|
||||
builder.graphExpression(defsharp.number(), expr, &defsharp.pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_USESHARP:
|
||||
return builder.graphIndexExpression(pn->pn_num, &pn->pn_pos, dst);
|
||||
case PNK_USESHARP: {
|
||||
UseSharpExpression &expr = pn->asUseSharpExpression();
|
||||
return builder.graphIndexExpression(expr.number(), &expr.pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_ARRAYCOMP:
|
||||
/* NB: it's no longer the case that pn_count could be 2. */
|
||||
|
@ -2795,14 +2790,13 @@ ASTSerializer::xml(ParseNode *pn, Value *dst)
|
|||
case PNK_XMLCOMMENT:
|
||||
return builder.xmlComment(atomContents(pn->pn_atom), &pn->pn_pos, dst);
|
||||
|
||||
case PNK_XMLPI:
|
||||
if (!pn->pn_pidata)
|
||||
return builder.xmlPI(atomContents(pn->pn_pitarget), &pn->pn_pos, dst);
|
||||
else
|
||||
return builder.xmlPI(atomContents(pn->pn_pitarget),
|
||||
atomContents(pn->pn_pidata),
|
||||
&pn->pn_pos,
|
||||
dst);
|
||||
case PNK_XMLPI: {
|
||||
XMLProcessingInstruction &pi = pn->asXMLProcessingInstruction();
|
||||
return builder.xmlPI(atomContents(pi.target()),
|
||||
atomContents(pi.data()),
|
||||
&pi.pn_pos,
|
||||
dst);
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
|
|
@ -1275,14 +1275,8 @@ BaseShape::getUnowned(JSContext *cx, const BaseShape &base)
|
|||
|
||||
BaseShapeSet::AddPtr p = table.lookupForAdd(&base);
|
||||
|
||||
if (p) {
|
||||
UnownedBaseShape *base = *p;
|
||||
|
||||
if (cx->compartment->needsBarrier())
|
||||
BaseShape::readBarrier(base);
|
||||
|
||||
return base;
|
||||
}
|
||||
if (p)
|
||||
return *p;
|
||||
|
||||
BaseShape *nbase_ = js_NewGCBaseShape(cx);
|
||||
if (!nbase_)
|
||||
|
@ -1382,14 +1376,8 @@ EmptyShape::getInitialShape(JSContext *cx, Class *clasp, JSObject *proto, JSObje
|
|||
|
||||
InitialShapeSet::AddPtr p = table.lookupForAdd(lookup);
|
||||
|
||||
if (p) {
|
||||
Shape *shape = p->shape;
|
||||
|
||||
if (cx->compartment->needsBarrier())
|
||||
Shape::readBarrier(shape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
if (p)
|
||||
return p->shape;
|
||||
|
||||
BaseShape base(clasp, parent, objectFlags);
|
||||
UnownedBaseShape *nbase = BaseShape::getUnowned(cx, base);
|
||||
|
|
|
@ -493,7 +493,7 @@ struct BaseShapeEntry
|
|||
static inline HashNumber hash(const BaseShape *base);
|
||||
static inline bool match(UnownedBaseShape *key, const BaseShape *lookup);
|
||||
};
|
||||
typedef HashSet<UnownedBaseShape *, BaseShapeEntry, SystemAllocPolicy> BaseShapeSet;
|
||||
typedef HashSet<ReadBarriered<UnownedBaseShape>, BaseShapeEntry, SystemAllocPolicy> BaseShapeSet;
|
||||
|
||||
struct Shape : public js::gc::Cell
|
||||
{
|
||||
|
@ -975,7 +975,7 @@ struct InitialShapeEntry
|
|||
* certain classes (e.g. String, RegExp) which may add certain baked-in
|
||||
* properties.
|
||||
*/
|
||||
js::Shape *shape;
|
||||
ReadBarriered<Shape> shape;
|
||||
|
||||
/*
|
||||
* Matching prototype for the entry. The shape of an object determines its
|
||||
|
|
|
@ -362,9 +362,8 @@ Shape::readBarrier(const Shape *shape)
|
|||
{
|
||||
#ifdef JSGC_INCREMENTAL
|
||||
JSCompartment *comp = shape->compartment();
|
||||
JS_ASSERT(comp->needsBarrier());
|
||||
|
||||
MarkShapeUnbarriered(comp->barrierTracer(), shape, "read barrier");
|
||||
if (comp->needsBarrier())
|
||||
MarkShapeUnbarriered(comp->barrierTracer(), shape, "read barrier");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -391,9 +390,8 @@ BaseShape::readBarrier(BaseShape *base)
|
|||
{
|
||||
#ifdef JSGC_INCREMENTAL
|
||||
JSCompartment *comp = base->compartment();
|
||||
JS_ASSERT(comp->needsBarrier());
|
||||
|
||||
MarkBaseShapeUnbarriered(comp->barrierTracer(), base, "read barrier");
|
||||
if (comp->needsBarrier())
|
||||
MarkBaseShapeUnbarriered(comp->barrierTracer(), base, "read barrier");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -1687,7 +1687,9 @@ class TypedArrayTemplate
|
|||
{
|
||||
JS_ASSERT(tarray);
|
||||
|
||||
JS_ASSERT(0 <= begin);
|
||||
JS_ASSERT(begin <= getLength(tarray));
|
||||
JS_ASSERT(0 <= end);
|
||||
JS_ASSERT(end <= getLength(tarray));
|
||||
|
||||
JSObject *bufobj = getBuffer(tarray);
|
||||
|
|
|
@ -1621,11 +1621,12 @@ ParseNodeToXML(Parser *parser, ParseNode *pn,
|
|||
goto skip_child;
|
||||
xml_class = JSXML_CLASS_COMMENT;
|
||||
} else if (pn->isKind(PNK_XMLPI)) {
|
||||
XMLProcessingInstruction &pi = pn->asXMLProcessingInstruction();
|
||||
if (IS_XML(str)) {
|
||||
Value v = StringValue(str);
|
||||
JSAutoByteString bytes;
|
||||
if (js_ValueToPrintable(cx, v, &bytes)) {
|
||||
ReportCompileErrorNumber(cx, &parser->tokenStream, pn,
|
||||
ReportCompileErrorNumber(cx, &parser->tokenStream, &pi,
|
||||
JSREPORT_ERROR, JSMSG_RESERVED_ID, bytes.ptr());
|
||||
}
|
||||
goto fail;
|
||||
|
@ -1634,11 +1635,11 @@ ParseNodeToXML(Parser *parser, ParseNode *pn,
|
|||
if (flags & XSF_IGNORE_PROCESSING_INSTRUCTIONS)
|
||||
goto skip_child;
|
||||
|
||||
qn = ParseNodeToQName(parser, pn, inScopeNSes, JS_FALSE);
|
||||
qn = ParseNodeToQName(parser, &pi, inScopeNSes, JS_FALSE);
|
||||
if (!qn)
|
||||
goto fail;
|
||||
|
||||
str = pn->pn_pidata ? pn->pn_pidata : cx->runtime->emptyString;
|
||||
str = pi.data();
|
||||
xml_class = JSXML_CLASS_PROCESSING_INSTRUCTION;
|
||||
} else {
|
||||
/* CDATA section content, or element text. */
|
||||
|
|
|
@ -486,8 +486,10 @@ void
|
|||
mjit::Compiler::popActiveFrame()
|
||||
{
|
||||
JS_ASSERT(a->parent);
|
||||
a->mainCodeEnd = masm.size();
|
||||
a->stubCodeEnd = stubcc.size();
|
||||
this->PC = a->parentPC;
|
||||
this->a = a->parent;
|
||||
this->a = (ActiveFrame *) a->parent;
|
||||
this->script = a->script;
|
||||
this->analysis = this->script->analysis();
|
||||
|
||||
|
@ -551,9 +553,14 @@ mjit::Compiler::performCompilation(JITScript **jitp)
|
|||
|
||||
#undef CHECK_STATUS
|
||||
|
||||
mjit::JSActiveFrame::JSActiveFrame()
|
||||
: parent(NULL), parentPC(NULL), script(NULL), inlineIndex(UINT32_MAX)
|
||||
{
|
||||
}
|
||||
|
||||
mjit::Compiler::ActiveFrame::ActiveFrame(JSContext *cx)
|
||||
: parent(NULL), parentPC(NULL), script(NULL), jumpMap(NULL),
|
||||
inlineIndex(UINT32_MAX), varTypes(NULL), needReturnValue(false),
|
||||
: jumpMap(NULL),
|
||||
varTypes(NULL), needReturnValue(false),
|
||||
syncReturnValue(false), returnValueDouble(false), returnSet(false),
|
||||
returnEntry(NULL), returnJumps(NULL), exitState(NULL)
|
||||
{}
|
||||
|
@ -922,6 +929,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
return Compile_Abort;
|
||||
}
|
||||
|
||||
a->mainCodeEnd = masm.size();
|
||||
a->stubCodeEnd = stubcc.size();
|
||||
|
||||
for (size_t i = 0; i < branchPatches.length(); i++) {
|
||||
Label label = labelOf(branchPatches[i].pc, branchPatches[i].inlineIndex);
|
||||
branchPatches[i].jump.linkTo(label, &masm);
|
||||
|
@ -1385,8 +1395,9 @@ mjit::Compiler::finishThisUp(JITScript **jitp)
|
|||
JSC::ExecutableAllocator::makeExecutable(result, masm.size() + stubcc.size());
|
||||
JSC::ExecutableAllocator::cacheFlush(result, masm.size() + stubcc.size());
|
||||
|
||||
Probes::registerMJITCode(cx, jit, script, script->function() ? script->function() : NULL,
|
||||
(mjit::Compiler_ActiveFrame**) inlineFrames.begin(),
|
||||
Probes::registerMJITCode(cx, jit,
|
||||
a,
|
||||
(JSActiveFrame**) inlineFrames.begin(),
|
||||
result, masm.size(),
|
||||
result + masm.size(), stubcc.size());
|
||||
|
||||
|
|
|
@ -62,6 +62,27 @@ struct InvariantCodePatch {
|
|||
InvariantCodePatch() : hasPatch(false) {}
|
||||
};
|
||||
|
||||
struct JSActiveFrame {
|
||||
JSActiveFrame *parent;
|
||||
jsbytecode *parentPC;
|
||||
JSScript *script;
|
||||
|
||||
/*
|
||||
* Index into inlineFrames or OUTER_FRAME, matches this frame's index in
|
||||
* the cross script SSA.
|
||||
*/
|
||||
uint32_t inlineIndex;
|
||||
|
||||
/* JIT code generation tracking state */
|
||||
size_t mainCodeStart;
|
||||
size_t stubCodeStart;
|
||||
size_t mainCodeEnd;
|
||||
size_t stubCodeEnd;
|
||||
size_t inlinePCOffset;
|
||||
|
||||
JSActiveFrame();
|
||||
};
|
||||
|
||||
class Compiler : public BaseCompiler
|
||||
{
|
||||
friend class StubCompiler;
|
||||
|
@ -355,26 +376,12 @@ class Compiler : public BaseCompiler
|
|||
*/
|
||||
|
||||
public:
|
||||
struct ActiveFrame {
|
||||
ActiveFrame *parent;
|
||||
jsbytecode *parentPC;
|
||||
JSScript *script;
|
||||
struct ActiveFrame : public JSActiveFrame {
|
||||
Label *jumpMap;
|
||||
|
||||
/*
|
||||
* Index into inlineFrames or OUTER_FRAME, matches this frame's index
|
||||
* in the cross script SSA.
|
||||
*/
|
||||
uint32_t inlineIndex;
|
||||
|
||||
/* Current types for non-escaping vars in the script. */
|
||||
VarType *varTypes;
|
||||
|
||||
/* JIT code generation tracking state */
|
||||
size_t mainCodeStart;
|
||||
size_t stubCodeStart;
|
||||
size_t inlinePCOffset;
|
||||
|
||||
/* State for managing return from inlined frames. */
|
||||
bool needReturnValue; /* Return value will be used. */
|
||||
bool syncReturnValue; /* Return value should be fully synced. */
|
||||
|
@ -470,7 +477,7 @@ private:
|
|||
return PC;
|
||||
ActiveFrame *scan = a;
|
||||
while (scan && scan->parent != outer)
|
||||
scan = scan->parent;
|
||||
scan = static_cast<ActiveFrame *>(scan->parent);
|
||||
return scan->parentPC;
|
||||
}
|
||||
|
||||
|
@ -491,7 +498,7 @@ private:
|
|||
while (na->parent) {
|
||||
if (na->exitState)
|
||||
return true;
|
||||
na = na->parent;
|
||||
na = static_cast<ActiveFrame *>(na->parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -909,6 +909,7 @@ mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
|
|||
return compileRound(arg, Round);
|
||||
}
|
||||
if (native == js_math_sqrt && type == JSVAL_TYPE_DOUBLE &&
|
||||
masm.supportsFloatingPointSqrt() &&
|
||||
(argType == JSVAL_TYPE_INT32 || argType == JSVAL_TYPE_DOUBLE)) {
|
||||
return compileMathSqrt(arg);
|
||||
}
|
||||
|
@ -949,6 +950,7 @@ mjit::Compiler::inlineNativeFunction(uint32_t argc, bool callingNew)
|
|||
JSValueType arg2Type = arg2->isTypeKnown() ? arg2->getKnownType() : JSVAL_TYPE_UNKNOWN;
|
||||
|
||||
if (native == js_math_pow && type == JSVAL_TYPE_DOUBLE &&
|
||||
masm.supportsFloatingPointSqrt() &&
|
||||
(arg1Type == JSVAL_TYPE_DOUBLE || arg1Type == JSVAL_TYPE_INT32) &&
|
||||
arg2Type == JSVAL_TYPE_DOUBLE && arg2->isConstant())
|
||||
{
|
||||
|
|
|
@ -140,27 +140,23 @@ static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
|
|||
static uint32_t StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
|
||||
#endif
|
||||
|
||||
// Called from JaegerTrampoline only
|
||||
extern "C" void JS_FASTCALL
|
||||
PushActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.oldregs = &f.cx->stack.regs();
|
||||
f.cx->stack.repointRegs(&f.regs);
|
||||
f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
|
||||
f.entryfp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
|
||||
f.regs.clearInlined();
|
||||
}
|
||||
|
||||
// Called from JaegerTrampolineReturn, JaegerThrowpoline, JaegerInterpoline
|
||||
extern "C" void JS_FASTCALL
|
||||
PopActiveVMFrame(VMFrame &f)
|
||||
{
|
||||
f.entryfp->script()->compartment()->jaegerCompartment()->popActiveFrame();
|
||||
}
|
||||
|
||||
extern "C" void JS_FASTCALL
|
||||
SetVMFrameRegs(VMFrame &f)
|
||||
{
|
||||
f.oldregs = &f.cx->stack.regs();
|
||||
|
||||
/* Restored on exit from EnterMethodJIT. */
|
||||
f.cx->stack.repointRegs(&f.regs);
|
||||
f.cx->stack.repointRegs(f.oldregs);
|
||||
}
|
||||
|
||||
#if defined(__APPLE__) || (defined(XP_WIN) && !defined(JS_CPU_X64)) || defined(XP_OS2)
|
||||
|
@ -328,8 +324,6 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
/* Set cx->regs and set the active frame. Save rdx and align frame in one. */
|
||||
"pushq %rdx" "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n"
|
||||
"movq %rsp, %rdi" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
|
||||
|
||||
/* Jump into the JIT'd code. */
|
||||
|
@ -514,8 +508,6 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
|
||||
/* Jump into the JIT'd code. */
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n"
|
||||
"movl %esp, %ecx" "\n"
|
||||
"call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
|
||||
|
||||
"movl 28(%esp), %ebp" "\n" /* load fp for JIT code */
|
||||
|
@ -730,8 +722,6 @@ SYMBOL_STRING(JaegerTrampoline) ":" "\n"
|
|||
/* Preserve 'fp' (r1) in r10 (JSFrameReg). */
|
||||
" mov r10, r1" "\n"
|
||||
|
||||
" mov r0, sp" "\n"
|
||||
" blx " SYMBOL_STRING_VMFRAME(SetVMFrameRegs) "\n"
|
||||
" mov r0, sp" "\n"
|
||||
" blx " SYMBOL_STRING_VMFRAME(PushActiveVMFrame)"\n"
|
||||
|
||||
|
@ -877,8 +867,6 @@ extern "C" {
|
|||
|
||||
/* Jump into into the JIT'd code. */
|
||||
mov ecx, esp;
|
||||
call SetVMFrameRegs;
|
||||
mov ecx, esp;
|
||||
call PushActiveVMFrame;
|
||||
|
||||
mov ebp, [esp + 28]; /* load fp for JIT code */
|
||||
|
@ -1055,7 +1043,6 @@ mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimi
|
|||
#endif
|
||||
|
||||
JS_ASSERT(cx->fp() == fp);
|
||||
FrameRegs &oldRegs = cx->regs();
|
||||
|
||||
JSBool ok;
|
||||
{
|
||||
|
@ -1069,9 +1056,6 @@ mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimi
|
|||
JaegerSpew(JSpew_Prof, "script run took %d ms\n", prof.time_ms());
|
||||
#endif
|
||||
|
||||
/* Undo repointRegs in SetVMFrameRegs. */
|
||||
cx->stack.repointRegs(&oldRegs);
|
||||
|
||||
JaegerStatus status = cx->compartment->jaegerCompartment()->lastUnfinished();
|
||||
if (status) {
|
||||
if (partial) {
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
|
||||
extern js_InternalThrow:PROC
|
||||
extern SetVMFrameRegs:PROC
|
||||
extern PushActiveVMFrame:PROC
|
||||
extern PopActiveVMFrame:PROC
|
||||
extern js_InternalInterpret:PROC
|
||||
|
@ -95,8 +94,6 @@ JaegerTrampoline PROC FRAME
|
|||
push r8
|
||||
mov rcx, rsp
|
||||
sub rsp, 20h
|
||||
call SetVMFrameRegs
|
||||
lea rcx, [rsp+20h]
|
||||
call PushActiveVMFrame
|
||||
add rsp, 20h
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
|
||||
|
||||
.extern js_InternalThrow
|
||||
.extern SetVMFrameRegs
|
||||
.extern PushActiveVMFrame
|
||||
.extern PopActiveVMFrame
|
||||
.extern js_InternalInterpret
|
||||
|
@ -101,8 +100,6 @@ JaegerTrampoline:
|
|||
push r8
|
||||
mov rcx, rsp
|
||||
sub rsp, 0x20
|
||||
call SetVMFrameRegs
|
||||
lea rcx, [rsp+0x20]
|
||||
call PushActiveVMFrame
|
||||
add rsp, 0x20
|
||||
|
||||
|
|
|
@ -79,8 +79,6 @@ JaegerTrampoline:
|
|||
/* Set cx->regs and set the active frame. Save rdx and align frame in one. */
|
||||
pushq %rdx
|
||||
movq %rsp, %rdi
|
||||
call SetVMFrameRegs
|
||||
movq %rsp, %rdi
|
||||
call PushActiveVMFrame
|
||||
|
||||
/* Jump into into the JIT'd code. */
|
||||
|
|
|
@ -66,7 +66,6 @@ JaegerTrampoline:
|
|||
/* Jump into the JIT'd code. */
|
||||
/* No fastcall for sunstudio. */
|
||||
pushl %esp
|
||||
call SetVMFrameRegs
|
||||
call PushActiveVMFrame
|
||||
popl %edx
|
||||
|
||||
|
|
|
@ -51,8 +51,6 @@ JaegerTrampoline:
|
|||
st %i1, [%fp - 24] ! entryFp
|
||||
st %i1, [%fp - 20] ! entryncode
|
||||
st %g0, [%fp - 16] ! stubRejoin
|
||||
call SetVMFrameRegs
|
||||
mov %sp, %o0
|
||||
call PushActiveVMFrame
|
||||
mov %sp, %o0
|
||||
ld [%fp - 36], %l0 ! fp
|
||||
|
|
|
@ -1259,6 +1259,15 @@ CompartmentMemoryCallback(JSContext *cx, void *vdata, JSCompartment *compartment
|
|||
JS::SizeOfCompartmentShapeTable(compartment, JsMallocSizeOf);
|
||||
}
|
||||
|
||||
void
|
||||
ExplicitNonHeapCompartmentCallback(JSContext *cx, void *data, JSCompartment *compartment)
|
||||
{
|
||||
size_t *n = static_cast<size_t *>(data);
|
||||
#ifdef JS_METHODJIT
|
||||
*n += JS::SizeOfCompartmentMjitCode(compartment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ChunkCallback(JSContext *cx, void *vdata, js::gc::Chunk *chunk)
|
||||
{
|
||||
|
@ -1541,8 +1550,9 @@ CompartmentStats::CompartmentStats(JSContext *cx, JSCompartment *c)
|
|||
}
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, void *vdata)
|
||||
{
|
||||
IterateData *data = (IterateData *)vdata;
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx) {
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
|
@ -1688,6 +1698,60 @@ CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
JSBool
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data)
|
||||
{
|
||||
PRInt64 *amount = (PRInt64 *)data;
|
||||
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx) {
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
return NS_ERROR_ABORT;
|
||||
}
|
||||
|
||||
// explicit/<compartment>/gc-heap/*
|
||||
*amount = PRInt64(JS_GetGCParameter(rt, JSGC_TOTAL_CHUNKS)) *
|
||||
js::gc::ChunkSize;
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
// explicit/<compartment>/mjit-code
|
||||
size_t n = 0;
|
||||
js::IterateCompartments(cx, &n, ExplicitNonHeapCompartmentCallback);
|
||||
*amount += n;
|
||||
|
||||
{
|
||||
#ifndef JS_THREADSAFE
|
||||
#error "This code assumes JS_THREADSAFE is defined"
|
||||
#endif
|
||||
|
||||
// Need the GC lock to call JS_ContextIteratorUnlocked() and to
|
||||
// access rt->threads.
|
||||
js::AutoLockGC lock(rt);
|
||||
|
||||
// explicit/runtime/threads/regexp-code
|
||||
// explicit/runtime/threads/stack-committed
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
size_t regexpCode, stackCommitted;
|
||||
thread->sizeOfIncludingThis(JsMallocSizeOf,
|
||||
NULL,
|
||||
NULL,
|
||||
®expCode,
|
||||
&stackCommitted);
|
||||
|
||||
*amount += regexpCode;
|
||||
*amount += stackCommitted;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define SLOP_BYTES_STRING \
|
||||
" The measurement includes slop bytes caused by the heap allocator rounding up request sizes."
|
||||
|
||||
|
@ -1958,7 +2022,7 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
|||
"Memory on the garbage-collected JavaScript heap, within chunks with at "
|
||||
"least one allocated GC thing, that could be holding useful data but "
|
||||
"currently isn't. Memory here is mutually exclusive with memory reported"
|
||||
"under gc-heap-decommitted.",
|
||||
"under 'explicit/js/gc-heap-decommitted'.",
|
||||
callback, closure);
|
||||
|
||||
ReportGCHeapBytes(pathPrefix +
|
||||
|
@ -1967,7 +2031,7 @@ ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
|||
"Memory on the garbage-collected JavaScript heap taken by completely empty "
|
||||
"chunks, that soon will be released unless claimed for new allocations. "
|
||||
"Memory here is mutually exclusive with memory reported under "
|
||||
"gc-heap-decommitted.",
|
||||
"'explicit/js/gc-heap-decommitted'.",
|
||||
callback, closure);
|
||||
|
||||
ReportGCHeapBytes(pathPrefix +
|
||||
|
@ -2105,6 +2169,17 @@ public:
|
|||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetExplicitNonHeap(PRInt64 *n)
|
||||
{
|
||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
|
||||
|
||||
if (!GetExplicitNonHeapForRuntime(rt, n))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(XPConnectJSCompartmentsMultiReporter
|
||||
|
|
|
@ -311,7 +311,9 @@ struct IterateData
|
|||
};
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, void *data);
|
||||
JSBool
|
||||
GetExplicitNonHeapForRuntime(JSRuntime *rt, void *data);
|
||||
|
||||
void
|
||||
ReportJSRuntimeStats(const IterateData &data, const nsACString &pathPrefix,
|
||||
|
|
|
@ -460,7 +460,7 @@ GetDisplayPortBounds(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem)
|
|||
}
|
||||
|
||||
const nsRect* displayport = aBuilder->GetDisplayPort();
|
||||
nsRect result = nsLayoutUtils::TransformRectToBoundsInAncestor(
|
||||
nsRect result = nsLayoutUtils::TransformAncestorRectToFrame(
|
||||
frame,
|
||||
nsRect(0, 0, displayport->width, displayport->height),
|
||||
aBuilder->ReferenceFrame());
|
||||
|
|
|
@ -194,6 +194,8 @@ static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printset
|
|||
//switch to page layout
|
||||
#include "nsGfxCIID.h"
|
||||
|
||||
#include "nsObserverService.h"
|
||||
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -509,6 +511,18 @@ public:
|
|||
nsCOMPtr<nsIDocument> mTop;
|
||||
};
|
||||
|
||||
class nsDocumentShownDispatcher : public nsRunnable
|
||||
{
|
||||
public:
|
||||
nsDocumentShownDispatcher(nsIDocument *aDocument)
|
||||
: mDocument(aDocument) {}
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// DocumentViewerImpl
|
||||
|
@ -2039,6 +2053,10 @@ DocumentViewerImpl::Show(void)
|
|||
}
|
||||
}
|
||||
|
||||
// Notify observers that a new page has been shown. (But not right now;
|
||||
// running JS at this time is not safe.)
|
||||
NS_DispatchToMainThread(new nsDocumentShownDispatcher(mDocument));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -4371,3 +4389,17 @@ DocumentViewerImpl::SetPrintPreviewPresentation(nsIViewManager* aViewManager,
|
|||
mPresContext = aPresContext;
|
||||
mPresShell = aPresShell;
|
||||
}
|
||||
|
||||
// Fires the "document-shown" event so that interested parties (right now, the
|
||||
// mobile browser) are aware of it.
|
||||
NS_IMETHODIMP
|
||||
nsDocumentShownDispatcher::Run()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> observerService =
|
||||
mozilla::services::GetObserverService();
|
||||
if (observerService) {
|
||||
observerService->NotifyObservers(mDocument, "document-shown", NULL);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -975,7 +975,7 @@ nsLayoutUtils::GetEventCoordinatesRelativeTo(const nsEvent* aEvent, nsIFrame* aF
|
|||
* out how to convert back to aFrame's coordinates and must use the CTM.
|
||||
*/
|
||||
if (transformFound)
|
||||
return InvertTransformsToRoot(aFrame, widgetToView);
|
||||
return TransformRootPointToFrame(aFrame, widgetToView);
|
||||
|
||||
/* Otherwise, all coordinate systems are translations of one another,
|
||||
* so we can just subtract out the different.
|
||||
|
@ -1117,68 +1117,62 @@ nsLayoutUtils::MatrixTransformPoint(const nsPoint &aPoint,
|
|||
NSFloatPixelsToAppUnits(float(image.y), aFactor));
|
||||
}
|
||||
|
||||
static gfxPoint
|
||||
InvertTransformsToAncestor(nsIFrame *aFrame,
|
||||
const gfxPoint &aPoint,
|
||||
nsIFrame *aStopAtAncestor = nsnull)
|
||||
static gfx3DMatrix
|
||||
GetTransformToAncestor(nsIFrame *aFrame, nsIFrame *aAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Why are you inverting transforms when there is no frame?");
|
||||
|
||||
/* To invert everything to the root, we'll get the CTM, invert it, and use it to transform
|
||||
* the point.
|
||||
*/
|
||||
nsIFrame *parent = nsnull;
|
||||
gfx3DMatrix ctm = aFrame->GetTransformMatrix(&parent);
|
||||
gfxPoint result = aPoint;
|
||||
|
||||
if (parent && parent != aStopAtAncestor) {
|
||||
result = InvertTransformsToAncestor(parent, aPoint, aStopAtAncestor);
|
||||
nsIFrame* parent;
|
||||
gfx3DMatrix ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
|
||||
while (parent && parent != aAncestor) {
|
||||
ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
|
||||
}
|
||||
return ctm;
|
||||
}
|
||||
|
||||
result = ctm.Inverse().ProjectPoint(result);
|
||||
return result;
|
||||
static gfxPoint
|
||||
TransformGfxPointFromAncestor(nsIFrame *aFrame,
|
||||
const gfxPoint &aPoint,
|
||||
nsIFrame *aAncestor)
|
||||
{
|
||||
gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor);
|
||||
return ctm.Inverse().ProjectPoint(aPoint);
|
||||
}
|
||||
|
||||
static gfxRect
|
||||
InvertGfxRectToAncestor(nsIFrame *aFrame,
|
||||
const gfxRect &aRect,
|
||||
nsIFrame *aStopAtAncestor = nsnull)
|
||||
TransformGfxRectFromAncestor(nsIFrame *aFrame,
|
||||
const gfxRect &aRect,
|
||||
nsIFrame *aAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aFrame, "Why are you inverting transforms when there is no frame?");
|
||||
gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor);
|
||||
return ctm.Inverse().ProjectRectBounds(aRect);
|
||||
}
|
||||
|
||||
/* To invert everything to the root, we'll get the CTM, invert it, and use it to transform
|
||||
* the point.
|
||||
*/
|
||||
nsIFrame *parent = nsnull;
|
||||
gfx3DMatrix ctm = aFrame->GetTransformMatrix(&parent);
|
||||
gfxRect result = aRect;
|
||||
|
||||
if (parent && parent != aStopAtAncestor) {
|
||||
result = InvertGfxRectToAncestor(parent, aRect, aStopAtAncestor);
|
||||
}
|
||||
|
||||
result = ctm.Inverse().ProjectRectBounds(result);
|
||||
return result;
|
||||
static gfxRect
|
||||
TransformGfxRectToAncestor(nsIFrame *aFrame,
|
||||
const gfxRect &aRect,
|
||||
nsIFrame *aAncestor)
|
||||
{
|
||||
gfx3DMatrix ctm = GetTransformToAncestor(aFrame, aAncestor);
|
||||
return ctm.ProjectRectBounds(aRect);
|
||||
}
|
||||
|
||||
nsPoint
|
||||
nsLayoutUtils::InvertTransformsToRoot(nsIFrame *aFrame,
|
||||
const nsPoint &aPoint)
|
||||
nsLayoutUtils::TransformRootPointToFrame(nsIFrame *aFrame,
|
||||
const nsPoint &aPoint)
|
||||
{
|
||||
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
gfxPoint result(NSAppUnitsToFloatPixels(aPoint.x, factor),
|
||||
NSAppUnitsToFloatPixels(aPoint.y, factor));
|
||||
|
||||
result = InvertTransformsToAncestor(aFrame, result);
|
||||
result = TransformGfxPointFromAncestor(aFrame, result, nsnull);
|
||||
|
||||
return nsPoint(NSFloatPixelsToAppUnits(float(result.x), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.y), factor));
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame,
|
||||
const nsRect &aRect,
|
||||
nsIFrame* aStopAtAncestor)
|
||||
nsLayoutUtils::TransformAncestorRectToFrame(nsIFrame* aFrame,
|
||||
const nsRect &aRect,
|
||||
nsIFrame* aAncestor)
|
||||
{
|
||||
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
|
||||
|
@ -1186,7 +1180,7 @@ nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame,
|
|||
NSAppUnitsToFloatPixels(aRect.width, factor),
|
||||
NSAppUnitsToFloatPixels(aRect.height, factor));
|
||||
|
||||
result = InvertGfxRectToAncestor(aFrame, result, aStopAtAncestor);
|
||||
result = TransformGfxRectFromAncestor(aFrame, result, aAncestor);
|
||||
|
||||
return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.y), factor),
|
||||
|
@ -1194,6 +1188,25 @@ nsLayoutUtils::TransformRectToBoundsInAncestor(nsIFrame* aFrame,
|
|||
NSFloatPixelsToAppUnits(float(result.height), factor));
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::TransformFrameRectToAncestor(nsIFrame* aFrame,
|
||||
const nsRect& aRect,
|
||||
nsIFrame* aAncestor)
|
||||
{
|
||||
float factor = aFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
gfxRect result(NSAppUnitsToFloatPixels(aRect.x, factor),
|
||||
NSAppUnitsToFloatPixels(aRect.y, factor),
|
||||
NSAppUnitsToFloatPixels(aRect.width, factor),
|
||||
NSAppUnitsToFloatPixels(aRect.height, factor));
|
||||
|
||||
result = TransformGfxRectToAncestor(aFrame, result, aAncestor);
|
||||
|
||||
return nsRect(NSFloatPixelsToAppUnits(float(result.x), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.y), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.width), factor),
|
||||
NSFloatPixelsToAppUnits(float(result.height), factor));
|
||||
}
|
||||
|
||||
static nsIntPoint GetWidgetOffset(nsIWidget* aWidget, nsIWidget*& aRootWidget) {
|
||||
nsIntPoint offset(0, 0);
|
||||
nsIWidget* parent = aWidget->GetParent();
|
||||
|
@ -1834,27 +1847,35 @@ nsLayoutUtils::GetAllInFlowBoxes(nsIFrame* aFrame, BoxCallback* aCallback)
|
|||
}
|
||||
|
||||
struct BoxToBorderRect : public nsLayoutUtils::BoxCallback {
|
||||
nsIFrame* mRelativeTo;
|
||||
nsIFrame* mRelativeTo;
|
||||
nsLayoutUtils::RectCallback* mCallback;
|
||||
PRUint32 mFlags;
|
||||
|
||||
BoxToBorderRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback)
|
||||
: mRelativeTo(aRelativeTo), mCallback(aCallback) {}
|
||||
BoxToBorderRect(nsIFrame* aRelativeTo, nsLayoutUtils::RectCallback* aCallback,
|
||||
PRUint32 aFlags)
|
||||
: mRelativeTo(aRelativeTo), mCallback(aCallback), mFlags(aFlags) {}
|
||||
|
||||
virtual void AddBox(nsIFrame* aFrame) {
|
||||
nsRect r;
|
||||
nsIFrame* outer = nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(aFrame, &r);
|
||||
if (outer) {
|
||||
mCallback->AddRect(r + outer->GetOffsetTo(mRelativeTo));
|
||||
} else
|
||||
mCallback->AddRect(nsRect(aFrame->GetOffsetTo(mRelativeTo), aFrame->GetSize()));
|
||||
if (!outer) {
|
||||
outer = aFrame;
|
||||
r = nsRect(nsPoint(0, 0), aFrame->GetSize());
|
||||
}
|
||||
if (mFlags & nsLayoutUtils::RECTS_ACCOUNT_FOR_TRANSFORMS) {
|
||||
r = nsLayoutUtils::TransformFrameRectToAncestor(outer, r, mRelativeTo);
|
||||
} else {
|
||||
r += outer->GetOffsetTo(mRelativeTo);
|
||||
}
|
||||
mCallback->AddRect(r);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
nsLayoutUtils::GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback)
|
||||
RectCallback* aCallback, PRUint32 aFlags)
|
||||
{
|
||||
BoxToBorderRect converter(aRelativeTo, aCallback);
|
||||
BoxToBorderRect converter(aRelativeTo, aCallback, aFlags);
|
||||
GetAllInFlowBoxes(aFrame, &converter);
|
||||
}
|
||||
|
||||
|
@ -1880,19 +1901,14 @@ void nsLayoutUtils::RectListBuilder::AddRect(const nsRect& aRect) {
|
|||
|
||||
nsIFrame* nsLayoutUtils::GetContainingBlockForClientRect(nsIFrame* aFrame)
|
||||
{
|
||||
// get the nearest enclosing SVG foreign object frame or the root frame
|
||||
while (aFrame->GetParent() &&
|
||||
!aFrame->IsFrameOfType(nsIFrame::eSVGForeignObject)) {
|
||||
aFrame = aFrame->GetParent();
|
||||
}
|
||||
|
||||
return aFrame;
|
||||
return aFrame->PresContext()->PresShell()->GetRootFrame();
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo) {
|
||||
nsLayoutUtils::GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
PRUint32 aFlags) {
|
||||
RectAccumulator accumulator;
|
||||
GetAllInFlowRects(aFrame, aRelativeTo, &accumulator);
|
||||
GetAllInFlowRects(aFrame, aRelativeTo, &accumulator, aFlags);
|
||||
return accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect
|
||||
: accumulator.mResultRect;
|
||||
}
|
||||
|
|
|
@ -515,11 +515,21 @@ public:
|
|||
bool aShouldIgnoreSuppression = false,
|
||||
bool aIgnoreRootScrollFrame = false);
|
||||
|
||||
|
||||
/**
|
||||
* Transform aRect relative to aAncestor down to the coordinate system of
|
||||
* aFrame. Computes the bounding-box of the true quadrilateral.
|
||||
*/
|
||||
static nsRect TransformAncestorRectToFrame(nsIFrame* aFrame,
|
||||
const nsRect& aRect,
|
||||
nsIFrame* aAncestor);
|
||||
|
||||
static nsRect TransformRectToBoundsInAncestor(nsIFrame* aFrame,
|
||||
const nsRect& aRect,
|
||||
nsIFrame* aStopAtAncestor);
|
||||
/**
|
||||
* Transform aRect relative to aFrame up to the coordinate system of
|
||||
* aAncestor. Computes the bounding-box of the true quadrilateral.
|
||||
*/
|
||||
static nsRect TransformFrameRectToAncestor(nsIFrame* aFrame,
|
||||
const nsRect& aRect,
|
||||
nsIFrame* aAncestor);
|
||||
|
||||
/**
|
||||
* Given a point in the global coordinate space, returns that point expressed
|
||||
|
@ -530,8 +540,8 @@ public:
|
|||
* @param aPoint The point, in the global space, to get in the frame-local space.
|
||||
* @return aPoint, expressed in aFrame's canonical coordinate space.
|
||||
*/
|
||||
static nsPoint InvertTransformsToRoot(nsIFrame* aFrame,
|
||||
const nsPoint &aPt);
|
||||
static nsPoint TransformRootPointToFrame(nsIFrame* aFrame,
|
||||
const nsPoint &aPt);
|
||||
|
||||
/**
|
||||
* Helper function that, given a rectangle and a matrix, returns the smallest
|
||||
|
@ -694,8 +704,8 @@ public:
|
|||
};
|
||||
|
||||
struct RectAccumulator : public RectCallback {
|
||||
nsRect mResultRect;
|
||||
nsRect mFirstRect;
|
||||
nsRect mResultRect;
|
||||
nsRect mFirstRect;
|
||||
bool mSeenFirstRect;
|
||||
|
||||
RectAccumulator();
|
||||
|
@ -713,6 +723,9 @@ public:
|
|||
|
||||
static nsIFrame* GetContainingBlockForClientRect(nsIFrame* aFrame);
|
||||
|
||||
enum {
|
||||
RECTS_ACCOUNT_FOR_TRANSFORMS = 0x01
|
||||
};
|
||||
/**
|
||||
* Collect all CSS border-boxes associated with aFrame and its
|
||||
* continuations, "drilling down" through outer table frames and
|
||||
|
@ -721,15 +734,22 @@ public:
|
|||
* into account) and passed to the callback in frame-tree order.
|
||||
* If aFrame is null, no boxes are returned.
|
||||
* For SVG frames, returns one rectangle, the bounding box.
|
||||
* If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
|
||||
* the boxes into aRelativeTo coordinates, transforms (including CSS
|
||||
* and SVG transforms) are taken into account.
|
||||
*/
|
||||
static void GetAllInFlowRects(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
RectCallback* aCallback);
|
||||
RectCallback* aCallback, PRUint32 aFlags = 0);
|
||||
|
||||
/**
|
||||
* Computes the union of all rects returned by GetAllInFlowRects. If
|
||||
* the union is empty, returns the first rect.
|
||||
* If aFlags includes RECTS_ACCOUNT_FOR_TRANSFORMS, then when converting
|
||||
* the boxes into aRelativeTo coordinates, transforms (including CSS
|
||||
* and SVG transforms) are taken into account.
|
||||
*/
|
||||
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo);
|
||||
static nsRect GetAllInFlowRectsUnion(nsIFrame* aFrame, nsIFrame* aRelativeTo,
|
||||
PRUint32 aFlags = 0);
|
||||
|
||||
enum {
|
||||
EXCLUDE_BLUR_SHADOWS = 0x01
|
||||
|
|
|
@ -722,6 +722,13 @@ PresShell::MemoryReporter::CollectReports(nsIMemoryMultiReporterCallback* aCb,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PresShell::MemoryReporter::GetExplicitNonHeap(PRInt64 *aAmount) {
|
||||
// This reporter doesn't do any KIND_NONHEAP measurements.
|
||||
*aAmount = 0;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class nsAutoCauseReflowNotifier
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -36,7 +36,9 @@ runtests();
|
|||
function runtests() {
|
||||
function doClick() {
|
||||
document.getElementById("test2").addEventListener("mousedown", testFinish, true);
|
||||
synthesizeMouseAtCenter(document.getElementById("test2"), { type: "mousedown" })
|
||||
// Don't target the center because the center could actually be outside the
|
||||
// viewport.
|
||||
synthesizeMouse(document.getElementById("test2"), 10, 10, { type: "mousedown" })
|
||||
}
|
||||
setTimeout(doClick, 300);
|
||||
}
|
||||
|
|
|
@ -550,8 +550,8 @@ nsComboboxControlFrame::GetCSSTransformTranslation()
|
|||
bool is3DTransform = false;
|
||||
gfxMatrix transform;
|
||||
while (frame) {
|
||||
nsIFrame* parent = nsnull;
|
||||
gfx3DMatrix ctm = frame->GetTransformMatrix(&parent);
|
||||
nsIFrame* parent;
|
||||
gfx3DMatrix ctm = frame->GetTransformMatrix(nsnull, &parent);
|
||||
gfxMatrix matrix;
|
||||
if (ctm.Is2D(&matrix)) {
|
||||
transform = transform * matrix;
|
||||
|
|
|
@ -531,8 +531,8 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine,
|
|||
guessRight == (mRight.mActive && mRight.IsNeeded())) {
|
||||
break;
|
||||
} else {
|
||||
guessLeft = mLeft.IsNeeded();
|
||||
guessRight = mRight.IsNeeded();
|
||||
guessLeft = mLeft.mActive && mLeft.IsNeeded();
|
||||
guessRight = mRight.mActive && mRight.IsNeeded();
|
||||
mLeft.Reset();
|
||||
mRight.Reset();
|
||||
aFramesToHide->Clear();
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml"><body>
|
||||
|
||||
<div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>
|
||||
|
||||
<math xmlns="http://www.w3.org/1998/Math/MathML"><mover>abcdef</mover></math>
|
||||
|
||||
</div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div></div>
|
||||
|
||||
</body></html>
|
|
@ -382,3 +382,5 @@ load 683702-1.xhtml
|
|||
load 688996-1.html
|
||||
load 688996-2.html
|
||||
load 683712.html
|
||||
load text-overflow-bug713610.html
|
||||
load 700031.xhtml
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body>
|
||||
<div style="text-overflow: ellipsis; padding-right: 4000px; overflow: scroll;"><span style="-moz-transform: translatex(-50px); border-right-style: dashed;"></span></div>
|
||||
</body>
|
||||
</html>
|
|
@ -4541,7 +4541,8 @@ nsIFrame::InvalidateInternal(const nsRect& aDamageRect, nscoord aX, nscoord aY,
|
|||
}
|
||||
|
||||
gfx3DMatrix
|
||||
nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
||||
nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
|
||||
nsIFrame** aOutAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aOutAncestor, "Need a place to put the ancestor!");
|
||||
|
||||
|
@ -4553,7 +4554,8 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
|||
/* Compute the delta to the parent, which we need because we are converting
|
||||
* coordinates to our parent.
|
||||
*/
|
||||
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this), "Cannot transform the viewport frame!");
|
||||
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
|
||||
"Cannot transform the viewport frame!");
|
||||
PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
|
||||
|
||||
gfx3DMatrix result =
|
||||
|
@ -4582,7 +4584,7 @@ nsIFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
|||
return gfx3DMatrix();
|
||||
|
||||
/* Keep iterating while the frame can't possibly be transformed. */
|
||||
while (!(*aOutAncestor)->IsTransformed()) {
|
||||
while (!(*aOutAncestor)->IsTransformed() && *aOutAncestor != aStopAtAncestor) {
|
||||
/* If no parent, stop iterating. Otherwise, update the ancestor. */
|
||||
nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(*aOutAncestor);
|
||||
if (!parent)
|
||||
|
|
|
@ -71,11 +71,11 @@ private:
|
|||
nsRect mRects[2];
|
||||
public:
|
||||
nsRect& Overflow(size_t aIndex) {
|
||||
NS_ASSERTION(aIndex < 2, "index out of range");
|
||||
NS_ASSERTION(0 <= aIndex && aIndex < 2, "index out of range");
|
||||
return mRects[aIndex];
|
||||
}
|
||||
const nsRect& Overflow(size_t aIndex) const {
|
||||
NS_ASSERTION(aIndex < 2, "index out of range");
|
||||
NS_ASSERTION(0 <= aIndex && aIndex < 2, "index out of range");
|
||||
return mRects[aIndex];
|
||||
}
|
||||
|
||||
|
|
|
@ -1932,17 +1932,20 @@ public:
|
|||
virtual nsIAtom* GetType() const = 0;
|
||||
|
||||
/**
|
||||
* Returns a transformation matrix that converts points in this frame's coordinate space
|
||||
* to points in some ancestor frame's coordinate space. The frame decides which ancestor
|
||||
* it will use as a reference point. If this frame has no ancestor, aOutAncestor will be
|
||||
* set to null.
|
||||
* Returns a transformation matrix that converts points in this frame's
|
||||
* coordinate space to points in some ancestor frame's coordinate space.
|
||||
* The frame decides which ancestor it will use as a reference point.
|
||||
* If this frame has no ancestor, aOutAncestor will be set to null.
|
||||
*
|
||||
* @param aOutAncestor [out] The ancestor frame the frame has chosen. If this frame has no
|
||||
* ancestor, aOutAncestor will be nsnull.
|
||||
* @return A gfxMatrix that converts points in this frame's coordinate space into
|
||||
* points in aOutAncestor's coordinate space.
|
||||
* @param aStopAtAncestor don't look further than aStopAtAncestor. If null,
|
||||
* all ancestors (including across documents) will be traversed.
|
||||
* @param aOutAncestor [out] The ancestor frame the frame has chosen. If
|
||||
* this frame has no ancestor, *aOutAncestor will be set to null.
|
||||
* @return A gfxMatrix that converts points in this frame's coordinate space
|
||||
* into points in aOutAncestor's coordinate space.
|
||||
*/
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame **aOutAncestor);
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aStopAtAncestor,
|
||||
nsIFrame **aOutAncestor);
|
||||
|
||||
/**
|
||||
* Bit-flags to pass to IsFrameOfType()
|
||||
|
|
|
@ -2337,8 +2337,10 @@ nsTextFrame::GetTrimmedOffsets(const nsTextFragment* aFrag,
|
|||
{
|
||||
NS_ASSERTION(mTextRun, "Need textrun here");
|
||||
// This should not be used during reflow. We need our TEXT_REFLOW_FLAGS
|
||||
// to be set correctly.
|
||||
NS_ASSERTION(!(GetStateBits() & NS_FRAME_FIRST_REFLOW),
|
||||
// to be set correctly. If our parent wasn't reflowed due to the frame
|
||||
// tree being too deep then the return value doesn't matter.
|
||||
NS_ASSERTION(!(GetStateBits() & NS_FRAME_FIRST_REFLOW) ||
|
||||
(GetParent()->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE),
|
||||
"Can only call this on frames that have been reflowed");
|
||||
NS_ASSERTION(!(GetStateBits() & NS_FRAME_IN_REFLOW),
|
||||
"Can only call this on frames that are not being reflowed");
|
||||
|
|
|
@ -140,7 +140,12 @@ nsSVGForeignObjectFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
|||
{
|
||||
nsSVGForeignObjectFrameBase::DidSetStyleContext(aOldStyleContext);
|
||||
|
||||
UpdateGraphic();
|
||||
// No need to invalidate before first reflow - that will happen elsewhere.
|
||||
// Moreover we haven't been initialised properly yet so we may not have the
|
||||
// right state bits.
|
||||
if (!(GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
|
||||
UpdateGraphic();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -278,7 +283,8 @@ nsSVGForeignObjectFrame::PaintSVG(nsSVGRenderState *aContext,
|
|||
}
|
||||
|
||||
gfx3DMatrix
|
||||
nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame **aOutAncestor)
|
||||
nsSVGForeignObjectFrame::GetTransformMatrix(nsIFrame* aAncestor,
|
||||
nsIFrame **aOutAncestor)
|
||||
{
|
||||
NS_PRECONDITION(aOutAncestor, "We need an ancestor to write to!");
|
||||
|
||||
|
|
|
@ -93,7 +93,8 @@ public:
|
|||
/**
|
||||
* Foreign objects can return a transform matrix.
|
||||
*/
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame **aOutAncestor);
|
||||
virtual gfx3DMatrix GetTransformMatrix(nsIFrame* aAncestor,
|
||||
nsIFrame **aOutAncestor);
|
||||
|
||||
/**
|
||||
* Get the "type" of the frame
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
|
||||
<marker id="m"></marker>
|
||||
|
||||
<script>
|
||||
window.addEventListener("load", function() {
|
||||
document.getElementById("m").appendChild(document.createElementNS("http://www.w3.org/2000/svg", "foreignObject"));
|
||||
}, false);
|
||||
</script>
|
||||
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 314 B |
|
@ -121,3 +121,4 @@ load 692203-2.svg
|
|||
load 693424-1.svg
|
||||
load 709920-1.svg
|
||||
load 709920-2.svg
|
||||
load 713413-1.svg
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<body onload="document.getElementById('b').setAttribute('colspan', '2');">
|
||||
<table rules="all"><tr><td rowspan="3"></td><td id="b" rowspan="2"></td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
|
@ -123,3 +123,4 @@ load 695430-1.html
|
|||
load 707622-1.html
|
||||
load 705996-1.html
|
||||
load 705996-2.html
|
||||
load 710098-1.html
|
||||
|
|
|
@ -2182,7 +2182,7 @@ void nsCellMap::ShrinkWithoutCell(nsTableCellMap& aMap,
|
|||
// get the rowspan and colspan from the cell map since the content may have changed
|
||||
bool zeroColSpan;
|
||||
PRUint32 numCols = aMap.GetColCount();
|
||||
PRInt32 rowSpan = GetRowSpan(aRowIndex, aColIndex, false);
|
||||
PRInt32 rowSpan = GetRowSpan(aRowIndex, aColIndex, true);
|
||||
PRUint32 colSpan = GetEffectiveColSpan(aMap, aRowIndex, aColIndex, zeroColSpan);
|
||||
PRUint32 endRowIndex = aRowIndex + rowSpan - 1;
|
||||
PRUint32 endColIndex = aColIndex + colSpan - 1;
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* Implementations of runtime and static assertion macros for C and C++. */
|
||||
|
||||
#ifndef mozilla_Assertions_h_
|
||||
#define mozilla_Assertions_h_
|
||||
|
||||
|
|
|
@ -38,6 +38,11 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Implements a smart pointer asserted to remain within a range specified at
|
||||
* construction.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_RangedPtr_h_
|
||||
#define mozilla_RangedPtr_h_
|
||||
|
||||
|
|
|
@ -38,16 +38,14 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* Helpers for defining and using refcounted objects. */
|
||||
|
||||
#ifndef mozilla_RefPtr_h_
|
||||
#define mozilla_RefPtr_h_
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
/**
|
||||
* Helpers for defining and using refcounted objects.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template<typename T> class RefCounted;
|
||||
|
|
|
@ -37,6 +37,11 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/*
|
||||
* Miscellaneous uncategorized functionality. Please add new functionality to
|
||||
* new headers, or to other appropriate existing headers, not here.
|
||||
*/
|
||||
|
||||
#ifndef mozilla_Util_h_
|
||||
#define mozilla_Util_h_
|
||||
|
||||
|
|
|
@ -615,8 +615,11 @@ abstract public class GeckoApp
|
|||
if (mLastUri == lastHistoryEntry.mUri &&
|
||||
mLastTitle == lastHistoryEntry.mTitle)
|
||||
return;
|
||||
|
||||
mLastViewport = mSoftwareLayerClient.getGeckoViewportMetrics().toJSON();
|
||||
|
||||
ViewportMetrics viewportMetrics = mSoftwareLayerClient.getGeckoViewportMetrics();
|
||||
if (viewportMetrics != null)
|
||||
mLastViewport = viewportMetrics.toJSON();
|
||||
|
||||
mLastUri = lastHistoryEntry.mUri;
|
||||
mLastTitle = lastHistoryEntry.mTitle;
|
||||
Bitmap bitmap = mSoftwareLayerClient.getBitmap();
|
||||
|
|
|
@ -78,6 +78,7 @@ public class GeckoEvent {
|
|||
public static final int ACTIVITY_START = 17;
|
||||
public static final int BROADCAST = 19;
|
||||
public static final int VIEWPORT = 20;
|
||||
public static final int EXPOSE = 21;
|
||||
|
||||
public static final int IME_COMPOSITION_END = 0;
|
||||
public static final int IME_COMPOSITION_BEGIN = 1;
|
||||
|
|
|
@ -165,10 +165,6 @@ public class ProfileMigrator {
|
|||
// Places URL hit is newer than Android,
|
||||
// allow it to be updated with places date
|
||||
allowUpdate = true;
|
||||
} else {
|
||||
Log.i(LOGTAG, "Android history is newer, not adding: " + url
|
||||
+ " date: " + (new Date(date)).toString()
|
||||
+ " android: " + (new Date(androidDate)).toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,7 +174,6 @@ public class ProfileMigrator {
|
|||
if (title != null) {
|
||||
BrowserDB.updateHistoryTitle(mCr, url, title);
|
||||
}
|
||||
Log.i(LOGTAG, "Adding history: " + url);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -203,8 +198,6 @@ public class ProfileMigrator {
|
|||
String title = cursor.getString(titleCol);
|
||||
// Convert from us (Places) to ms (Java, Android)
|
||||
long date = cursor.getLong(dateCol) / (long)1000;
|
||||
Log.i(LOGTAG, "History: " + title + " URL: " + url
|
||||
+ " time: " + (new Date(date)).toString());
|
||||
addHistory(androidHistory, url, title, date);
|
||||
placesHistory.add(url);
|
||||
cursor.moveToNext();
|
||||
|
@ -231,7 +224,6 @@ public class ProfileMigrator {
|
|||
|
||||
protected void addBookmark(String url, String title) {
|
||||
if (!BrowserDB.isBookmark(mCr, url)) {
|
||||
Log.i(LOGTAG, "Adding bookmark: " + url);
|
||||
if (title == null) {
|
||||
title = url;
|
||||
}
|
||||
|
@ -254,7 +246,6 @@ public class ProfileMigrator {
|
|||
while (!cursor.isAfterLast()) {
|
||||
String url = cursor.getString(urlCol);
|
||||
String title = cursor.getString(titleCol);
|
||||
Log.i(LOGTAG, "Bookmark: " + title + " URL: " + url);
|
||||
addBookmark(url, title);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
|
@ -272,12 +263,13 @@ public class ProfileMigrator {
|
|||
protected void addFavicon(String url, String mime, byte[] data) {
|
||||
ByteArrayInputStream byteStream = new ByteArrayInputStream(data);
|
||||
BitmapDrawable image = (BitmapDrawable) Drawable.createFromStream(byteStream, "src");
|
||||
try {
|
||||
BrowserDB.updateFaviconForUrl(mCr, url, image);
|
||||
Log.i(LOGTAG, "Favicon added: " + mime + " URL: " + url);
|
||||
} catch (SQLiteException e) {
|
||||
Log.i(LOGTAG, "Favicon failed: " + mime + " URL: " + url
|
||||
+ " error:" + e.getMessage());
|
||||
if (image != null) {
|
||||
try {
|
||||
BrowserDB.updateFaviconForUrl(mCr, url, image);
|
||||
} catch (SQLiteException e) {
|
||||
Log.i(LOGTAG, "Migrating favicon failed: " + mime + " URL: " + url
|
||||
+ " error:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -349,6 +341,8 @@ public class ProfileMigrator {
|
|||
dbFile.delete();
|
||||
dbFileWal.delete();
|
||||
dbFileShm.delete();
|
||||
|
||||
Log.i(LOGTAG, "Profile migration finished");
|
||||
} catch (SQLiteException e) {
|
||||
if (db != null) {
|
||||
db.close();
|
||||
|
|
|
@ -140,7 +140,8 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
|||
layerController.setViewportMetrics(mGeckoViewport);
|
||||
}
|
||||
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:Update", this);
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:Expose", this);
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateAndDraw", this);
|
||||
GeckoAppShell.registerGeckoEventListener("Viewport:UpdateLater", this);
|
||||
}
|
||||
|
||||
|
@ -340,19 +341,15 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL
|
|||
}
|
||||
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
if ("Viewport:Update".equals(event)) {
|
||||
beginTransaction(mTileLayer);
|
||||
try {
|
||||
updateViewport(message.getString("viewport"), false);
|
||||
} catch (JSONException e) {
|
||||
Log.e(LOGTAG, "Unable to update viewport", e);
|
||||
} finally {
|
||||
endTransaction(mTileLayer);
|
||||
}
|
||||
if ("Viewport:Expose".equals(event)) {
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.EXPOSE));
|
||||
} else if ("Viewport:UpdateAndDraw".equals(event)) {
|
||||
mUpdateViewportOnEndDraw = true;
|
||||
|
||||
// Redraw everything.
|
||||
Rect rect = new Rect(0, 0, mBufferSize.width, mBufferSize.height);
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.DRAW, rect));
|
||||
} else if ("Viewport:UpdateLater".equals(event)) {
|
||||
if (!mTileLayer.inTransaction()) {
|
||||
Log.e(LOGTAG, "Viewport:UpdateLater called while not in transaction. You should be using Viewport:Update instead!");
|
||||
}
|
||||
mUpdateViewportOnEndDraw = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,7 +264,10 @@ public class PanZoomController
|
|||
// the screen orientation changed) so abort it and start a new one to
|
||||
// ensure the viewport doesn't contain out-of-bounds areas
|
||||
case NOTHING:
|
||||
bounce();
|
||||
// Don't do animations here; they're distracting and can cause flashes on page
|
||||
// transitions.
|
||||
mController.setViewportMetrics(getValidViewportMetrics());
|
||||
mController.notifyLayerClientOfGeometryChange();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -666,18 +669,18 @@ public class PanZoomController
|
|||
if (flingingX || flingingY) {
|
||||
mX.displace(); mY.displace();
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
/*
|
||||
* If we're still flinging with an appreciable velocity, stop here. The threshold is
|
||||
* higher in the case of overscroll, so we bounce back eagerly when overscrolling but
|
||||
* coast smoothly to a stop when not.
|
||||
*/
|
||||
float excess = PointUtils.distance(new PointF(mX.getExcess(), mY.getExcess()));
|
||||
PointF velocityVector = new PointF(mX.getRealVelocity(), mY.getRealVelocity());
|
||||
float threshold = (excess >= 1.0f) ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD;
|
||||
if (PointUtils.distance(velocityVector) >= threshold)
|
||||
return;
|
||||
/*
|
||||
* If we're still flinging with an appreciable velocity, stop here. The threshold is
|
||||
* higher in the case of overscroll, so we bounce back eagerly when overscrolling but
|
||||
* coast smoothly to a stop when not.
|
||||
*/
|
||||
float excess = PointUtils.distance(new PointF(mX.getExcess(), mY.getExcess()));
|
||||
PointF velocityVector = new PointF(mX.getRealVelocity(), mY.getRealVelocity());
|
||||
float threshold = (excess >= 1.0f) ? STOPPED_THRESHOLD : FLING_STOPPED_THRESHOLD;
|
||||
if (PointUtils.distance(velocityVector) >= threshold)
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform a bounce-back animation if overscrolled, unless panning is being overridden
|
||||
|
|
|
@ -155,6 +155,16 @@ var Strings = {};
|
|||
});
|
||||
});
|
||||
|
||||
var MetadataProvider = {
|
||||
getDrawMetadata: function getDrawMetadata() {
|
||||
return BrowserApp.getDrawMetadata();
|
||||
},
|
||||
|
||||
drawingAllowed: function drawingAllowed() {
|
||||
return !BrowserApp.selectedTab.suppressDrawing;
|
||||
}
|
||||
};
|
||||
|
||||
var BrowserApp = {
|
||||
_tabs: [],
|
||||
_selectedTab: null,
|
||||
|
@ -169,7 +179,7 @@ var BrowserApp = {
|
|||
BrowserEventHandler.init();
|
||||
ViewportHandler.init();
|
||||
|
||||
getBridge().setDrawMetadataProvider(this.getDrawMetadata.bind(this));
|
||||
getBridge().setDrawMetadataProvider(MetadataProvider);
|
||||
|
||||
Services.obs.addObserver(this, "Tab:Add", false);
|
||||
Services.obs.addObserver(this, "Tab:Load", false);
|
||||
|
@ -190,6 +200,7 @@ var BrowserApp = {
|
|||
Services.obs.addObserver(this, "Viewport:Change", false);
|
||||
Services.obs.addObserver(this, "AgentMode:Change", false);
|
||||
Services.obs.addObserver(this, "SearchEngines:Get", false);
|
||||
Services.obs.addObserver(this, "document-shown", false);
|
||||
|
||||
function showFullScreenWarning() {
|
||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertFullScreenToast"), "short");
|
||||
|
@ -427,7 +438,6 @@ var BrowserApp = {
|
|||
},
|
||||
|
||||
quit: function quit() {
|
||||
Cu.reportError("got quit quit message");
|
||||
window.QueryInterface(Ci.nsIDOMChromeWindow).minimize();
|
||||
window.close();
|
||||
},
|
||||
|
@ -639,8 +649,65 @@ var BrowserApp = {
|
|||
return;
|
||||
let focused = doc.activeElement;
|
||||
if ((focused instanceof HTMLInputElement && focused.mozIsTextField(false)) || (focused instanceof HTMLTextAreaElement)) {
|
||||
focused.scrollIntoView(false);
|
||||
BrowserApp.getTabForBrowser(aBrowser).sendViewportUpdate();
|
||||
let tab = BrowserApp.getTabForBrowser(aBrowser);
|
||||
let win = aBrowser.contentWindow;
|
||||
|
||||
// tell gecko to scroll the field into view. this will scroll any nested scrollable elements
|
||||
// as well as the browser's content window, and modify the scrollX and scrollY on the content window.
|
||||
focused.scrollIntoView(true);
|
||||
|
||||
// update userScrollPos so that we don't send a duplicate viewport update by triggering
|
||||
// our scroll listener
|
||||
tab.userScrollPos.x = win.scrollX;
|
||||
tab.userScrollPos.y = win.scrollY;
|
||||
|
||||
// note that:
|
||||
// 1. because of the way we do zooming using a CSS transform, gecko does not take into
|
||||
// account the effect of the zoom on the viewport size.
|
||||
// 2. if the input element is near the bottom/right of the page (less than one viewport
|
||||
// height/width away from the bottom/right), the scrollIntoView call will make gecko scroll to the
|
||||
// bottom/right of the page in an attempt to align the input field with the top of the viewport.
|
||||
// however, since gecko doesn't know about the zoom, what it thinks is the "bottom/right of
|
||||
// the page" isn't actually the bottom/right of the page at the current zoom level, and we
|
||||
// need to adjust this further.
|
||||
// 3. we can't actually adjust this by changing the window scroll position, as gecko already thinks
|
||||
// we're at the bottom/right, so instead we do it by changing the viewportExcess on the tab and
|
||||
// moving the browser element.
|
||||
|
||||
let visibleContentWidth = tab._viewport.width / tab._viewport.zoom;
|
||||
let visibleContentHeight = tab._viewport.height / tab._viewport.zoom;
|
||||
// get the rect that the focused element occupies relative to what gecko thinks the viewport is,
|
||||
// and adjust it by viewportExcess to so that it is relative to what the user sees as the viewport.
|
||||
let focusedRect = focused.getBoundingClientRect();
|
||||
focusedRect = {
|
||||
left: focusedRect.left - tab.viewportExcess.x,
|
||||
right: focusedRect.right - tab.viewportExcess.x,
|
||||
top: focusedRect.top - tab.viewportExcess.y,
|
||||
bottom: focusedRect.bottom - tab.viewportExcess.y
|
||||
};
|
||||
let transformChanged = false;
|
||||
if (focusedRect.right >= visibleContentWidth && focusedRect.left > 0) {
|
||||
// the element is too far off the right side, so we need to scroll to the right more
|
||||
tab.viewportExcess.x += Math.min(focusedRect.left, focusedRect.right - visibleContentWidth);
|
||||
transformChanged = true;
|
||||
} else if (focusedRect.left < 0) {
|
||||
// the element is too far off the left side, so we need to scroll to the left more
|
||||
tab.viewportExcess.x += focusedRect.left;
|
||||
transformChanged = true;
|
||||
}
|
||||
if (focusedRect.bottom >= visibleContentHeight && focusedRect.top > 0) {
|
||||
// the element is too far down, so we need to scroll down more
|
||||
tab.viewportExcess.y += Math.min(focusedRect.top, focusedRect.bottom - visibleContentHeight);
|
||||
transformChanged = true;
|
||||
} else if (focusedRect.top < 0) {
|
||||
// the element is too far up, so we need to scroll up more
|
||||
tab.viewportExcess.y += focusedRect.top;
|
||||
transformChanged = true;
|
||||
}
|
||||
if (transformChanged)
|
||||
tab.updateTransform();
|
||||
// finally, let java know where we ended up
|
||||
tab.sendViewportUpdate();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -705,6 +772,20 @@ var BrowserApp = {
|
|||
ViewportHandler.onResize();
|
||||
} else if (aTopic == "SearchEngines:Get") {
|
||||
this.getSearchEngines();
|
||||
} else if (aTopic == "document-shown") {
|
||||
let tab = this.selectedTab;
|
||||
if (tab.browser.contentDocument != aSubject) {
|
||||
return;
|
||||
}
|
||||
|
||||
ViewportHandler.resetMetadata(tab);
|
||||
|
||||
// Unsuppress drawing unless the page was being thawed from the bfcache (which is an atomic
|
||||
// operation, so there is no drawing to suppress).
|
||||
if (tab.suppressDrawing) {
|
||||
tab.sendExposeEvent();
|
||||
tab.suppressDrawing = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -712,7 +793,7 @@ var BrowserApp = {
|
|||
delete this.defaultBrowserWidth;
|
||||
let width = Services.prefs.getIntPref("browser.viewport.desktopWidth");
|
||||
return this.defaultBrowserWidth = width;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var NativeWindow = {
|
||||
|
@ -1184,6 +1265,12 @@ Tab.prototype = {
|
|||
this.browser.addEventListener("PluginClickToPlay", this, true);
|
||||
this.browser.addEventListener("pagehide", this, true);
|
||||
|
||||
let chromeEventHandler = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler;
|
||||
chromeEventHandler.addEventListener("DOMWindowCreated", this, false);
|
||||
|
||||
Services.obs.addObserver(this, "http-on-modify-request", false);
|
||||
|
||||
if (!aParams.delayLoad) {
|
||||
|
@ -1320,20 +1407,22 @@ Tab.prototype = {
|
|||
transformChanged = true;
|
||||
}
|
||||
|
||||
if (transformChanged)
|
||||
this.updateTransform();
|
||||
},
|
||||
|
||||
updateTransform: function() {
|
||||
let hasZoom = (Math.abs(this._viewport.zoom - 1.0) >= 1e-6);
|
||||
let x = this._viewport.offsetX + Math.round(-this.viewportExcess.x * this._viewport.zoom);
|
||||
let y = this._viewport.offsetY + Math.round(-this.viewportExcess.y * this._viewport.zoom);
|
||||
|
||||
if (transformChanged) {
|
||||
let x = this._viewport.offsetX + Math.round(-excessX * this._viewport.zoom);
|
||||
let y = this._viewport.offsetY + Math.round(-excessY * this._viewport.zoom);
|
||||
let transform =
|
||||
"translate(" + x + "px, " +
|
||||
y + "px)";
|
||||
if (hasZoom)
|
||||
transform += " scale(" + this._viewport.zoom + ")";
|
||||
|
||||
let transform =
|
||||
"translate(" + x + "px, " +
|
||||
y + "px)";
|
||||
if (hasZoom)
|
||||
transform += " scale(" + this._viewport.zoom + ")";
|
||||
|
||||
this.browser.style.MozTransform = transform;
|
||||
}
|
||||
this.browser.style.MozTransform = transform;
|
||||
},
|
||||
|
||||
get viewport() {
|
||||
|
@ -1393,8 +1482,7 @@ Tab.prototype = {
|
|||
return;
|
||||
sendMessageToJava({
|
||||
gecko: {
|
||||
type: "Viewport:Update",
|
||||
viewport: JSON.stringify(this.viewport)
|
||||
type: "Viewport:UpdateAndDraw"
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -1537,6 +1625,18 @@ Tab.prototype = {
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case "DOMWindowCreated": {
|
||||
// Conveniently, this call to getBrowserForDocument() will return null if the document is
|
||||
// not the top-level content document of the browser.
|
||||
let browser = BrowserApp.getBrowserForDocument(aEvent.originalTarget);
|
||||
if (!browser)
|
||||
break;
|
||||
|
||||
let tab = BrowserApp.getTabForBrowser(browser);
|
||||
tab.suppressDrawing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -1796,6 +1896,16 @@ Tab.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
sendExposeEvent: function() {
|
||||
// Now that the document is actually on the screen, send an expose event.
|
||||
this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
sendMessageToJava({
|
||||
gecko: {
|
||||
type: "Viewport:Expose"
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISHistoryListener,
|
||||
|
|
|
@ -65,7 +65,9 @@ function checkScrollbarsPosition(aX) {
|
|||
|
||||
let verticalRect = verticalScrollbar.getBoundingClientRect();
|
||||
let margin = parseInt(verticalScrollbar.getAttribute("end"));
|
||||
let expectedPosition = window.innerWidth - aX - margin;
|
||||
let matches = verticalScrollbar.style.MozTransform.match(/^translate\(([-0-9]+)px/);
|
||||
let translateX = matches ? parseInt(matches[1]) : 0;
|
||||
let expectedPosition = window.innerWidth - aX - margin + translateX;
|
||||
is(verticalRect.right, expectedPosition, "The vertical scrollbar should be position to " + expectedPosition + " (got " + verticalRect.right + ")");
|
||||
|
||||
EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mouseup" });
|
||||
|
|
|
@ -65,7 +65,9 @@ function checkScrollbarsPosition(aX) {
|
|||
|
||||
let verticalRect = verticalScrollbar.getBoundingClientRect();
|
||||
let margin = parseInt(verticalScrollbar.getAttribute("end"));
|
||||
let expectedPosition = window.innerWidth - aX - margin;
|
||||
let matches = verticalScrollbar.style.MozTransform.match(/^translate\(([-0-9]+)px/);
|
||||
let translateX = matches ? parseInt(matches[1]) : 0;
|
||||
let expectedPosition = window.innerWidth - aX - margin + translateX;
|
||||
is(verticalRect.right, expectedPosition, "The vertical scrollbar should be position to " + expectedPosition + " (got " + verticalRect.right + ")");
|
||||
|
||||
EventUtils.synthesizeMouse(browser, width / 2, height * 3 / 4, { type: "mouseup" });
|
||||
|
|
|
@ -16,7 +16,11 @@
|
|||
|
||||
var SimpleTest = { };
|
||||
var parentRunner = null;
|
||||
var isPrimaryTestWindow = !!parent.TestRunner;
|
||||
|
||||
// In normal test runs, the window that has a TestRunner in its parent is
|
||||
// the primary window. In single test runs, if there is no parent and there
|
||||
// is no opener then it is the primary window.
|
||||
var isPrimaryTestWindow = !!parent.TestRunner || (parent == window && !opener);
|
||||
|
||||
// Finds the TestRunner for this test run and the SpecialPowers object (in
|
||||
// case it is not defined) from a parent/opener window.
|
||||
|
|
|
@ -236,6 +236,9 @@ Reporter.prototype = {
|
|||
},
|
||||
|
||||
treeNameMatches: function(aTreeName) {
|
||||
// Nb: the '/' must be present, because we have a KIND_OTHER reporter
|
||||
// called "explicit" which is not part of the "explicit" tree.
|
||||
aTreeName += "/";
|
||||
return this._path.slice(0, aTreeName.length) === aTreeName;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -36,8 +36,10 @@
|
|||
while (e.hasMoreElements()) {
|
||||
var r = e.getNext().QueryInterface(Ci.nsIMemoryMultiReporter);
|
||||
// Call collectReports, even though we don't use its results, just to
|
||||
// test that the multi-reporter doesn't crash or anything.
|
||||
// test that the multi-reporter doesn't crash or anything. And likewise
|
||||
// for the |explicitNonHeap| field.
|
||||
r.collectReports(function(){}, null);
|
||||
dummy += r.explicitNonHeap;
|
||||
mgr.unregisterMultiReporter(r);
|
||||
realMultiReporters.push(r);
|
||||
}
|
||||
|
@ -78,8 +80,6 @@
|
|||
f("", "explicit/b/b", HEAP, 75 * MB),
|
||||
f("", "explicit/b/c/a", HEAP, 70 * MB),
|
||||
f("", "explicit/b/c/b", HEAP, 2 * MB), // omitted
|
||||
f("", "explicit/c", NONHEAP, 100 * MB),
|
||||
f("", "explicit/c/d", NONHEAP, 13 * MB), // subsumed by parent
|
||||
f("", "explicit/g", HEAP, 1 * MB), // internal, dup: merge
|
||||
f("", "explicit/g/a", HEAP, 6 * MB),
|
||||
f("", "explicit/g/b", HEAP, 5 * MB),
|
||||
|
@ -89,13 +89,16 @@
|
|||
var fakeMultiReporters = [
|
||||
{ collectReports: function(cbObj, closure) {
|
||||
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
||||
f("explicit/c", NONHEAP, BYTES, 100 * MB),
|
||||
f("explicit/c/d", NONHEAP, BYTES, 13 * MB), // subsumed by parent
|
||||
f("explicit/c/d", NONHEAP, BYTES, 10 * MB), // dup, subsumed by parent
|
||||
f("explicit/cc", NONHEAP, BYTES, 13 * MB);
|
||||
f("explicit/cc", NONHEAP, BYTES, 10 * MB); // dup
|
||||
f("explicit/d", NONHEAP, BYTES, 499 * KB); // omitted
|
||||
f("explicit/e", NONHEAP, BYTES, 100 * KB); // omitted
|
||||
f("explicit/f/g/h/i", HEAP, BYTES, 20 * MB);
|
||||
}
|
||||
},
|
||||
explicitNonHeap: (100 + 13 + 10)*MB + (499 + 100)*KB
|
||||
},
|
||||
{ collectReports: function(cbObj, closure) {
|
||||
function f(p, k, u, a) { cbObj.callback("", p, k, u, a, "(desc)", closure); }
|
||||
|
@ -104,7 +107,8 @@
|
|||
f("other2", OTHER, BYTES, 222 * MB);
|
||||
f("perc2", OTHER, PERCENTAGE, 10000);
|
||||
f("perc1", OTHER, PERCENTAGE, 4567);
|
||||
}
|
||||
},
|
||||
explicitNonHeap: 0
|
||||
},
|
||||
{ collectReports: function(cbObj, closure) {
|
||||
// The amounts are given in pages, so multiply here by 4kb.
|
||||
|
@ -115,7 +119,8 @@
|
|||
f("map/vsize/a", 19);
|
||||
f("map/swap/b/c", 10);
|
||||
f("map/resident/a", 42);
|
||||
}
|
||||
},
|
||||
explicitNonHeap: 0
|
||||
}
|
||||
];
|
||||
for (var i = 0; i < fakeReporters.length; i++) {
|
||||
|
|
|
@ -34,12 +34,18 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
do_get_profile();
|
||||
|
||||
do_register_cleanup(function() {
|
||||
Services.obs.notifyObservers(null, "quit-application", null);
|
||||
});
|
||||
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
|
||||
getService(Ci.nsIProperties);
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ const MEM_HISTOGRAMS = {
|
|||
"js-gc-heap": "MEMORY_JS_GC_HEAP",
|
||||
"js-compartments-system": "MEMORY_JS_COMPARTMENTS_SYSTEM",
|
||||
"js-compartments-user": "MEMORY_JS_COMPARTMENTS_USER",
|
||||
"explicit": "MEMORY_EXPLICIT",
|
||||
"resident": "MEMORY_RESIDENT",
|
||||
"explicit/storage/sqlite": "MEMORY_STORAGE_SQLITE",
|
||||
"explicit/images/content/used/uncompressed":
|
||||
|
@ -263,33 +264,36 @@ TelemetryPing.prototype = {
|
|||
while (e.hasMoreElements()) {
|
||||
let mr = e.getNext().QueryInterface(Ci.nsIMemoryReporter);
|
||||
let id = MEM_HISTOGRAMS[mr.path];
|
||||
if (!id || mr.amount == -1) {
|
||||
if (!id) {
|
||||
continue;
|
||||
}
|
||||
// mr.amount is expensive to read in some cases, so get it only once.
|
||||
let amount = mr.amount;
|
||||
if (amount == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let val;
|
||||
if (mr.units == Ci.nsIMemoryReporter.UNITS_BYTES) {
|
||||
val = Math.floor(mr.amount / 1024);
|
||||
val = Math.floor(amount / 1024);
|
||||
}
|
||||
else if (mr.units == Ci.nsIMemoryReporter.UNITS_COUNT) {
|
||||
val = mr.amount;
|
||||
val = amount;
|
||||
}
|
||||
else if (mr.units == Ci.nsIMemoryReporter.UNITS_COUNT_CUMULATIVE) {
|
||||
// If the reporter gives us a cumulative count, we'll report the
|
||||
// difference in its value between now and our previous ping.
|
||||
|
||||
// Read mr.amount just once so our arithmetic is consistent.
|
||||
let curVal = mr.amount;
|
||||
if (!(mr.path in this._prevValues)) {
|
||||
// If this is the first time we're reading this reporter, store its
|
||||
// current value but don't report it in the telemetry ping, so we
|
||||
// ignore the effect startup had on the reporter.
|
||||
this._prevValues[mr.path] = curVal;
|
||||
this._prevValues[mr.path] = amount;
|
||||
continue;
|
||||
}
|
||||
|
||||
val = curVal - this._prevValues[mr.path];
|
||||
this._prevValues[mr.path] = curVal;
|
||||
val = amount - this._prevValues[mr.path];
|
||||
this._prevValues[mr.path] = amount;
|
||||
}
|
||||
else {
|
||||
NS_ASSERT(false, "Can't handle memory reporter with units " + mr.units);
|
||||
|
@ -297,11 +301,6 @@ TelemetryPing.prototype = {
|
|||
}
|
||||
this.addValue(mr.path, id, val);
|
||||
}
|
||||
// "explicit" is found differently.
|
||||
let explicit = mgr.explicit; // Get it only once, it's reasonably expensive
|
||||
if (explicit != -1) {
|
||||
this.addValue("explicit", "MEMORY_EXPLICIT", Math.floor(explicit / 1024));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -38,9 +38,11 @@
|
|||
var EXPORTED_SYMBOLS = [ "InlineSpellChecker" ];
|
||||
var gLanguageBundle;
|
||||
var gRegionBundle;
|
||||
const MAX_UNDO_STACK_DEPTH = 1;
|
||||
|
||||
function InlineSpellChecker(aEditor) {
|
||||
this.init(aEditor);
|
||||
this.mAddedWordStack = []; // We init this here to preserve it between init/uninit calls
|
||||
}
|
||||
|
||||
InlineSpellChecker.prototype = {
|
||||
|
@ -284,8 +286,27 @@ InlineSpellChecker.prototype = {
|
|||
// callback for adding the current misspelling to the user-defined dictionary
|
||||
addToDictionary: function()
|
||||
{
|
||||
// Prevent the undo stack from growing over the max depth
|
||||
if (this.mAddedWordStack.length == MAX_UNDO_STACK_DEPTH)
|
||||
this.mAddedWordStack.shift();
|
||||
|
||||
this.mAddedWordStack.push(this.mMisspelling);
|
||||
this.mInlineSpellChecker.addWordToDictionary(this.mMisspelling);
|
||||
},
|
||||
// callback for removing the last added word to the dictionary LIFO fashion
|
||||
undoAddToDictionary: function()
|
||||
{
|
||||
if (this.mAddedWordStack.length > 0)
|
||||
{
|
||||
var word = this.mAddedWordStack.pop();
|
||||
this.mInlineSpellChecker.removeWordFromDictionary(word);
|
||||
}
|
||||
},
|
||||
canUndo : function()
|
||||
{
|
||||
// Return true if we have words on the stack
|
||||
return (this.mAddedWordStack.length > 0);
|
||||
},
|
||||
ignoreWord: function()
|
||||
{
|
||||
this.mInlineSpellChecker.ignoreWord(this.mMisspelling);
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче