This commit is contained in:
Ms2ger 2011-12-30 12:17:22 +01:00
Родитель d150cdcfbe f5076064af
Коммит 9839c9abbf
127 изменённых файлов: 2811 добавлений и 1080 удалений

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

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

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

@ -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, &regexp, &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, &regexp, &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);

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

@ -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 &regions,
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 &regions,
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,
&regexpCode,
&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);

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