Merge last green changeset from mozilla-inbound to mozilla-central

This commit is contained in:
Marco Bonardo 2011-09-03 11:49:40 +02:00
commit 913f8215a0
74 changed files with 1424 additions and 1778 deletions

View File

@ -811,9 +811,22 @@ toolbar[mode="icons"] #zoom-in-button {
background-clip: padding-box;
}
#urlbar:-moz-window-inactive,
.searchbar-textbox:-moz-window-inactive {
border-color: @toolbarbuttonInactiveBorderColor@;
@media (-moz-mac-lion-theme) {
#urlbar,
.searchbar-textbox {
background-image: -moz-linear-gradient(hsl(0,0%,97%), hsl(0,0%,100%));
border-color: hsla(0,0%,0%,.35) hsla(0,0%,0%,.25) hsla(0,0%,0%,.15);
box-shadow: 0 1px 0 hsla(0,0%,100%,.2),
inset 0 0 1px hsla(0,0%,0%,.05),
inset 0 1px 2px hsla(0,0%,0%,.1);
}
}
@media not all and (-moz-mac-lion-theme) {
#urlbar:-moz-window-inactive,
.searchbar-textbox:-moz-window-inactive {
border-color: @toolbarbuttonInactiveBorderColor@;
}
}
#urlbar[focused="true"],

View File

@ -38,51 +38,6 @@ function testCancelInPhase4() {
xhr2.addEventListener("load", function() {
is(xhr2.responseText, "0", "Received fresh value for second request");
testCancelBeforePhase4();
}, false);
xhr2.open("GET", url);
xhr2.setRequestHeader("X-Request", "1", false);
try { xhr2.send(); }
catch(e) {
is(xhr2.status, "200", "Exception!");
}
}, 0);
}, false);
xhr.abort();
}
}, false);
xhr.open("GET", url, true);
xhr.setRequestHeader("X-Request", "0", false);
try { xhr.send(); }
catch(e) {
is("Nothing", "Exception", "Boom: " + e);
}
}
// Tests that response is NOT cached if the request is cancelled
// before it has reached state 4
function testCancelBeforePhase4() {
clearCache();
// First request - should be loaded from server
var xhr = new XMLHttpRequest();
xhr.addEventListener("readystatechange", function(e) {
if (xhr.readyState == 3) {
xhr.addEventListener("abort", function() {
setTimeout(function() {
// This request was cancelled, so the responseText should be empty string
is(xhr.responseText, "", "Expected empty response to cancelled request");
// Second request - should be found in cache
var xhr2 = new XMLHttpRequest();
xhr2.addEventListener("load", function() {
is(xhr2.responseText, "1", "Received cached value for second request");
SimpleTest.finish();
}, false);

View File

@ -48,6 +48,7 @@
#include "AccessCheck.h"
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "nscore.h"
#include "nsDOMClassInfo.h"
@ -516,7 +517,6 @@ static const char kDOMStringBundleURL[] =
#define WINDOW_SCRIPTABLE_FLAGS \
(nsIXPCScriptable::WANT_GETPROPERTY | \
nsIXPCScriptable::WANT_SETPROPERTY | \
nsIXPCScriptable::WANT_PRECREATE | \
nsIXPCScriptable::WANT_FINALIZE | \
nsIXPCScriptable::WANT_EQUALITY | \
@ -5269,39 +5269,6 @@ nsWindowSH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
return NS_OK;
}
NS_IMETHODIMP
nsWindowSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval)
{
if (id == sLocation_id) {
JSAutoRequest ar(cx);
JSString *val = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMWindow> window = do_QueryWrappedNative(wrapper);
NS_ENSURE_TRUE(window, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMLocation> location;
nsresult rv = window->GetLocation(getter_AddRefs(location));
NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && location, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
vp, getter_AddRefs(holder));
NS_ENSURE_SUCCESS(rv, rv);
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
rv = location->SetHref(depStr);
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
return NS_OK;
}
NS_IMETHODIMP
nsWindowSH::Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRBool *_retval)
@ -6392,6 +6359,68 @@ static JSNewResolveOp sOtherResolveFuncs[] = {
mozilla::dom::workers::ResolveWorkerClasses
};
template<class Interface>
static nsresult
LocationSetterGuts(JSContext *cx, JSObject *obj, jsval *vp)
{
// This function duplicates some of the logic in XPC_WN_HelperSetProperty
XPCWrappedNative *wrapper =
XPCWrappedNative::GetWrappedNativeOfJSObject(cx, obj);
// The error checks duplicate code in THROW_AND_RETURN_IF_BAD_WRAPPER
NS_ENSURE_TRUE(wrapper, NS_ERROR_XPC_BAD_OP_ON_WN_PROTO);
NS_ENSURE_TRUE(wrapper->IsValid(), NS_ERROR_XPC_HAS_BEEN_SHUTDOWN);
nsCOMPtr<Interface> xpcomObj = do_QueryWrappedNative(wrapper);
NS_ENSURE_TRUE(xpcomObj, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMLocation> location;
nsresult rv = xpcomObj->GetLocation(getter_AddRefs(location));
NS_ENSURE_SUCCESS(rv, rv);
JSString *val = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
rv = location->SetHref(depStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
return WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
&NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
getter_AddRefs(holder));
}
template<class Interface>
static JSBool
LocationSetter(JSContext *cx, JSObject *obj, jsid id, JSBool strict,
jsval *vp)
{
nsresult rv = LocationSetterGuts<Interface>(cx, obj, vp);
if (NS_FAILED(rv)) {
if (!::JS_IsExceptionPending(cx)) {
nsDOMClassInfo::ThrowJSException(cx, rv);
}
return JS_FALSE;
}
return JS_TRUE;
}
static JSBool
LocationSetterUnwrapper(JSContext *cx, JSObject *obj, jsid id, JSBool strict,
jsval *vp)
{
JSObject *wrapped = XPCWrapper::UnsafeUnwrapSecurityWrapper(obj);
if (wrapped) {
obj = wrapped;
}
return LocationSetter<nsIDOMWindow>(cx, obj, id, strict, vp);
}
NS_IMETHODIMP
nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, PRUint32 flags,
@ -6544,7 +6573,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
NS_ENSURE_SUCCESS(rv, rv);
JSBool ok = JS_WrapValue(cx, &v) &&
JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull,
JS_DefinePropertyById(cx, obj, id, v, nsnull,
LocationSetterUnwrapper,
JSPROP_PERMANENT | JSPROP_ENUMERATE);
if (!ok) {
@ -8177,7 +8207,8 @@ nsDocumentSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSAutoRequest ar(cx);
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull,
JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull,
LocationSetter<nsIDOMDocument>,
JSPROP_PERMANENT | JSPROP_ENUMERATE);
if (!ok) {
@ -8222,34 +8253,6 @@ NS_IMETHODIMP
nsDocumentSH::SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval)
{
if (id == sLocation_id) {
nsCOMPtr<nsIDOMDocument> doc = do_QueryWrappedNative(wrapper);
NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIDOMLocation> location;
nsresult rv = doc->GetLocation(getter_AddRefs(location));
NS_ENSURE_SUCCESS(rv, rv);
if (location) {
JSAutoRequest ar(cx);
JSString *val = ::JS_ValueToString(cx, *vp);
NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
nsDependentJSString depStr;
NS_ENSURE_TRUE(depStr.init(cx, val), NS_ERROR_UNEXPECTED);
rv = location->SetHref(depStr);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
&NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
getter_AddRefs(holder));
return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
}
}
if (id == sDocumentURIObject_id && IsPrivilegedScript()) {
// We don't want privileged script that can read this property to set it,
// but _do_ want to allow everyone else to set a value they can then read.

View File

@ -407,8 +407,6 @@ public:
#endif
NS_IMETHOD GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD SetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, jsid id, jsval *vp, PRBool *_retval);
NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
JSObject *obj, PRBool *_retval);
NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,

View File

@ -55,7 +55,7 @@
typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(IRIX) || defined(HPUX)
#elif defined(_AIX) || defined(__sun) || defined(__osf__) || defined(HPUX)
/*
* AIX and SunOS ship a inttypes.h header that defines [u]int32_t,
* but not bool for C.

View File

@ -55,6 +55,7 @@ _TEST_FILES = \
test_location.html \
test_innerWidthHeight_script.html \
innerWidthHeight_script.html \
test_location_setters.html \
$(NULL)
libs:: $(_TEST_FILES)

View File

@ -0,0 +1,78 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=639720
-->
<head>
<title>Test for Bug 639720</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=639720">Mozilla Bug 639720</a>
<p id="display">
<iframe id="f"></iframe>
</p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 639720 **/
SimpleTest.waitForExplicitFinish();
var tests = [
{ url: "data:text/plain,1" },
{ url: "data:text/plain,2",
useDocument: true },
{ prepURL: "http://www.example.com",
url: "data:text/plain,3" }
];
var currentTest = 0;
function checkTest() {
is($("f").contentWindow.location.href, tests[currentTest].url,
"href of content window's location should match url of current test");
++currentTest;
runNextTest();
}
function runCurrentTest() {
var test = tests[currentTest];
$("f").onload = checkTest;
if (test.useDocument) {
$("f").contentDocument.location = test.url;
} else {
$("f").contentWindow.location = test.url;
}
is(typeof($("f").contentWindow.location), "object",
"Location should not have become string");
}
function prepComplete() {
runCurrentTest();
}
function runNextTest() {
if (currentTest == tests.length) {
SimpleTest.finish();
return;
}
var test = tests[currentTest];
if ("prepURL" in test) {
$("f").onload = prepComplete;
$("f").src = test.prepURL;
return;
}
runCurrentTest();
}
addLoadEvent(runNextTest);
</script>
</pre>
</body>
</html>

View File

@ -4047,11 +4047,26 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
NS_ENSURE_SUCCESS(res, res);
continue;
}
// is it a block with a 'margin' property?
if (useCSS && IsBlockNode(curNode))
{
nsIAtom* marginProperty = MarginPropertyAtomForIndent(mHTMLEditor->mHTMLCSSUtils, curNode);
nsAutoString value;
mHTMLEditor->mHTMLCSSUtils->GetSpecifiedProperty(curNode, marginProperty, value);
float f;
nsCOMPtr<nsIAtom> unit;
mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
if (f > 0)
{
RelativeChangeIndentationOfElementNode(curNode, -1);
continue;
}
}
// is it a list item?
if (nsHTMLEditUtils::IsListItem(curNode))
{
// if it is a list item, that means we are not outdenting whole list.
// So we need to finish up dealng with any curBlockQuote, and then
// So we need to finish up dealing with any curBlockQuote, and then
// pop this list item.
if (curBlockQuote)
{
@ -4123,7 +4138,7 @@ nsHTMLEditRules::WillOutdent(nsISelection *aSelection, PRBool *aCancel, PRBool *
float f;
nsCOMPtr<nsIAtom> unit;
mHTMLEditor->mHTMLCSSUtils->ParseLength(value, &f, getter_AddRefs(unit));
if (f > 0)
if (f > 0 && !(nsHTMLEditUtils::IsList(curParent) && nsHTMLEditUtils::IsList(curNode)))
{
curBlockQuote = n;
firstBQChild = curNode;

View File

@ -40,7 +40,7 @@ addLoadEvent(function() {
var twoindent = '<p></p><ul style="margin-left: 80px;"><li>Item 1</li><li>Item 2</li></ul><p></p>';
is(editor.innerHTML, twoindent, "a twice indented bulleted list");
document.execCommand("outdent", false, false);
todo_is(editor.innerHTML, oneindent, "outdenting a twice indented bulleted list");
is(editor.innerHTML, oneindent, "outdenting a twice indented bulleted list");
// done
SimpleTest.finish();

View File

@ -38,7 +38,7 @@ addLoadEvent(function() {
var expected = '<ul style="margin-left: 40px;"><li>Item 1</li><ul><li>Item 2</li><li>Item 3</li></ul><li>Item 4</li></ul>';
is(editor.innerHTML, expected, "indenting part of an already indented bulleted list");
document.execCommand("outdent", false, false);
todo_is(editor.innerHTML, original, "outdenting the partially indented part of an already indented bulleted list");
is(editor.innerHTML, original, "outdenting the partially indented part of an already indented bulleted list");
// done
SimpleTest.finish();

View File

@ -110,13 +110,14 @@ SFX B e able [^aeiou]e
SFX L Y 1
SFX L 0 ment .
REP 88
REP 89
REP a ei
REP ei a
REP a ey
REP ey a
REP ai ie
REP ie ai
REP alot a_lot
REP are air
REP are ear
REP are eir

View File

@ -697,10 +697,11 @@ gfxFT2Font::InitTextRun(gfxContext *aContext,
}
if (!ok) {
aTextRun->AdjustAdvancesForSyntheticBold(aRunStart, aRunLength);
AddRange(aTextRun, aString, aRunStart, aRunLength);
}
aTextRun->AdjustAdvancesForSyntheticBold(aContext, aRunStart, aRunLength);
return PR_TRUE;
}
@ -809,9 +810,7 @@ gfxFT2Font::gfxFT2Font(cairo_scaled_font_t *aCairoFont,
: gfxFT2FontBase(aCairoFont, aFontEntry, aFontStyle)
{
NS_ASSERTION(mFontEntry, "Unable to find font entry for font. Something is whack.");
if (aNeedsBold) {
mSyntheticBoldOffset = 1.0;
}
mApplySyntheticBold = aNeedsBold;
mCharGlyphCache.Init(64);
}

View File

@ -1035,10 +1035,10 @@ gfxFont::RunMetrics::CombineWith(const RunMetrics& aOther, PRBool aOtherIsOnLeft
gfxFont::gfxFont(gfxFontEntry *aFontEntry, const gfxFontStyle *aFontStyle,
AntialiasOption anAAOption) :
mFontEntry(aFontEntry), mIsValid(PR_TRUE),
mApplySyntheticBold(PR_FALSE),
mStyle(*aFontStyle),
mAdjustedSize(0.0),
mFUnitsConvFactor(0.0f),
mSyntheticBoldOffset(0),
mAntialiasOption(anAAOption),
mPlatformShaper(nsnull),
mHarfBuzzShaper(nsnull)
@ -1115,6 +1115,33 @@ struct GlyphBuffer {
#undef GLYPH_BUFFER_SIZE
};
// Bug 674909. When synthetic bolding text by drawing twice, need to
// render using a pixel offset in device pixels, otherwise text
// doesn't appear bolded, it appears as if a bad text shadow exists
// when a non-identity transform exists. Use an offset factor so that
// the second draw occurs at a constant offset in device pixels.
static double
CalcXScale(gfxContext *aContext)
{
// determine magnitude of a 1px x offset in device space
gfxSize t = aContext->UserToDevice(gfxSize(1.0, 0.0));
if (t.width == 1.0 && t.height == 0.0) {
// short-circuit the most common case to avoid sqrt() and division
return 1.0;
}
double m = sqrt(t.width * t.width + t.height * t.height);
NS_ASSERTION(m != 0.0, "degenerate transform while synthetic bolding");
if (m == 0.0) {
return 0.0; // effectively disables offset
}
// scale factor so that offsets are 1px in device pixels
return 1.0 / m;
}
void
gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
gfxContext *aContext, PRBool aDrawToPath, gfxPoint *aPt,
@ -1128,9 +1155,18 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
const double devUnitsPerAppUnit = 1.0/double(appUnitsPerDevUnit);
PRBool isRTL = aTextRun->IsRightToLeft();
double direction = aTextRun->GetDirection();
// double-strike in direction of run
double synBoldDevUnitOffsetAppUnits =
direction * (double) mSyntheticBoldOffset * appUnitsPerDevUnit;
// synthetic-bold strikes are each offset one device pixel in run direction
// (these values are only needed if IsSyntheticBold() is true)
double synBoldOnePixelOffset;
PRInt32 strikes;
if (IsSyntheticBold()) {
double xscale = CalcXScale(aContext);
synBoldOnePixelOffset = direction * xscale;
// use as many strikes as needed for the the increased advance
strikes = NS_lroundf(GetSyntheticBoldOffset() / xscale);
}
PRUint32 i;
// Current position in appunits
double x = aPt->x;
@ -1169,15 +1205,21 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y, devUnitsPerAppUnit);
// synthetic bolding by drawing with a one-pixel offset
if (mSyntheticBoldOffset) {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + synBoldDevUnitOffsetAppUnits,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
// synthetic bolding by multi-striking with 1-pixel offsets
// at least once, more if there's room (large font sizes)
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
PRInt32 strikeCount = strikes;
do {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + strikeOffset * appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
} while (--strikeCount > 0);
}
glyphs.Flush(cr, aDrawToPath, isRTL);
@ -1216,15 +1258,20 @@ gfxFont::Draw(gfxTextRun *aTextRun, PRUint32 aStart, PRUint32 aEnd,
glyph->x = ToDeviceUnits(glyphX, devUnitsPerAppUnit);
glyph->y = ToDeviceUnits(y + details->mYOffset, devUnitsPerAppUnit);
// synthetic bolding by drawing with a one-pixel offset
if (mSyntheticBoldOffset) {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + synBoldDevUnitOffsetAppUnits,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
if (IsSyntheticBold()) {
double strikeOffset = synBoldOnePixelOffset;
PRInt32 strikeCount = strikes;
do {
cairo_glyph_t *doubleglyph;
doubleglyph = glyphs.AppendGlyph();
doubleglyph->index = glyph->index;
doubleglyph->x =
ToDeviceUnits(glyphX + strikeOffset *
appUnitsPerDevUnit,
devUnitsPerAppUnit);
doubleglyph->y = glyph->y;
strikeOffset += synBoldOnePixelOffset;
} while (--strikeCount > 0);
}
glyphs.Flush(cr, aDrawToPath, isRTL);
@ -3492,7 +3539,9 @@ struct BufferAlphaColor {
};
void
gfxTextRun::AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength)
gfxTextRun::AdjustAdvancesForSyntheticBold(gfxContext *aContext,
PRUint32 aStart,
PRUint32 aLength)
{
const PRUint32 appUnitsPerDevUnit = GetAppUnitsPerDevUnit();
PRBool isRTL = IsRightToLeft();
@ -3501,7 +3550,9 @@ gfxTextRun::AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength)
while (iter.NextRun()) {
gfxFont *font = iter.GetGlyphRun()->mFont;
if (font->IsSyntheticBold()) {
PRUint32 synAppUnitOffset = font->GetSyntheticBoldOffset() * appUnitsPerDevUnit;
PRUint32 synAppUnitOffset =
font->GetSyntheticBoldOffset() *
appUnitsPerDevUnit * CalcXScale(aContext);
PRUint32 start = iter.GetStringStart();
PRUint32 end = iter.GetStringEnd();
PRUint32 i;

View File

@ -1193,8 +1193,12 @@ public:
// This is called by the default Draw() implementation above.
virtual PRBool SetupCairoFont(gfxContext *aContext) = 0;
PRBool IsSyntheticBold() { return mSyntheticBoldOffset != 0; }
PRUint32 GetSyntheticBoldOffset() { return mSyntheticBoldOffset; }
PRBool IsSyntheticBold() { return mApplySyntheticBold; }
// Amount by which synthetic bold "fattens" the glyphs: 1/16 of the em-size
gfxFloat GetSyntheticBoldOffset() {
return GetAdjustedSize() * (1.0 / 16.0);
}
gfxFontEntry *GetFontEntry() { return mFontEntry.get(); }
PRBool HasCharacter(PRUint32 ch) {
@ -1224,6 +1228,11 @@ protected:
nsRefPtr<gfxFontEntry> mFontEntry;
PRPackedBool mIsValid;
// use synthetic bolding for environments where this is not supported
// by the platform
PRPackedBool mApplySyntheticBold;
nsExpirationState mExpirationState;
gfxFontStyle mStyle;
nsAutoTArray<gfxGlyphExtents*,1> mGlyphExtentsArray;
@ -1232,9 +1241,6 @@ protected:
float mFUnitsConvFactor; // conversion factor from font units to dev units
// synthetic bolding for environments where this is not supported by the platform
PRUint32 mSyntheticBoldOffset; // number of devunit pixels to offset double-strike, 0 ==> no bolding
// the AA setting requested for this font - may affect glyph bounds
AntialiasOption mAntialiasOption;
@ -2043,7 +2049,9 @@ public:
#endif
// post-process glyph advances to deal with synthetic bolding
void AdjustAdvancesForSyntheticBold(PRUint32 aStart, PRUint32 aLength);
void AdjustAdvancesForSyntheticBold(gfxContext *aContext,
PRUint32 aStart,
PRUint32 aLength);
protected:
/**

View File

@ -57,9 +57,7 @@ gfxMacFont::gfxMacFont(MacOSFontEntry *aFontEntry, const gfxFontStyle *aFontStyl
mFontFace(nsnull),
mScaledFont(nsnull)
{
if (aNeedsBold) {
mSyntheticBoldOffset = 1; // devunit offset when double-striking text to fake boldness
}
mApplySyntheticBold = aNeedsBold;
mCGFont = aFontEntry->GetFontRef();
if (!mCGFont) {
@ -167,7 +165,7 @@ gfxMacFont::InitTextRun(gfxContext *aContext,
aRunStart, aRunLength, aRunScript,
static_cast<MacOSFontEntry*>(GetFontEntry())->RequiresAATLayout());
aTextRun->AdjustAdvancesForSyntheticBold(aRunStart, aRunLength);
aTextRun->AdjustAdvancesForSyntheticBold(aContext, aRunStart, aRunLength);
return ok;
}
@ -320,8 +318,10 @@ gfxMacFont::InitMetrics()
mMetrics.aveCharWidth = mMetrics.maxAdvance;
}
}
mMetrics.aveCharWidth += mSyntheticBoldOffset;
mMetrics.maxAdvance += mSyntheticBoldOffset;
if (IsSyntheticBold()) {
mMetrics.aveCharWidth += GetSyntheticBoldOffset();
mMetrics.maxAdvance += GetSyntheticBoldOffset();
}
mMetrics.spaceWidth = GetCharWidth(cmap, ' ', &glyphID, cgConvFactor);
if (glyphID == 0) {

View File

@ -76,7 +76,7 @@ ToUTF8(const nsACString &aString, const char *aCharset, nsACString &aResult)
rv = unicodeDecoder->Convert(inStr.get(), &srcLen, ustr, &dstLen);
if (NS_SUCCEEDED(rv)){
// Tru64 Cxx and IRIX MIPSpro 7.3 need an explicit get()
// Tru64 Cxx needs an explicit get()
CopyUTF16toUTF8(Substring(ustr.get(), ustr + dstLen), aResult);
}
return rv;

View File

@ -1068,7 +1068,7 @@ JSObject::makeDenseArraySlow(JSContext *cx)
js::Shape *oldMap = lastProp;
/* Create a native scope. */
js::gc::FinalizeKind kind = js::gc::FinalizeKind(arenaHeader()->getThingKind());
gc::AllocKind kind = getAllocKind();
if (!InitScopeForObject(cx, this, &js_SlowArrayClass, getProto()->getNewType(cx), kind))
return false;
@ -3256,7 +3256,7 @@ NewArray(JSContext *cx, jsuint length, JSObject *proto)
{
JS_ASSERT_IF(proto, proto->isArray());
gc::FinalizeKind kind = GuessObjectGCKind(length, true);
gc::AllocKind kind = GuessObjectGCKind(length, true);
JSObject *obj = detail::NewObject<WithProto::Class, false>(cx, &js_ArrayClass, proto, NULL, kind);
if (!obj)
return NULL;

View File

@ -50,6 +50,37 @@ namespace gc {
struct ArenaHeader;
struct Chunk;
/* The GC allocation kinds. */
enum AllocKind {
FINALIZE_OBJECT0,
FINALIZE_OBJECT0_BACKGROUND,
FINALIZE_OBJECT2,
FINALIZE_OBJECT2_BACKGROUND,
FINALIZE_OBJECT4,
FINALIZE_OBJECT4_BACKGROUND,
FINALIZE_OBJECT8,
FINALIZE_OBJECT8_BACKGROUND,
FINALIZE_OBJECT12,
FINALIZE_OBJECT12_BACKGROUND,
FINALIZE_OBJECT16,
FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_FUNCTION,
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
FINALIZE_SCRIPT,
FINALIZE_SHAPE,
FINALIZE_TYPE_OBJECT,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
#endif
FINALIZE_SHORT_STRING,
FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING,
FINALIZE_LAST = FINALIZE_EXTERNAL_STRING
};
const size_t FINALIZE_LIMIT = FINALIZE_LAST + 1;
/*
* Live objects are marked black. How many other additional colors are available
* depends on the size of the GCThing.
@ -67,6 +98,7 @@ struct Cell {
inline uintptr_t address() const;
inline ArenaHeader *arenaHeader() const;
inline Chunk *chunk() const;
inline AllocKind getAllocKind() const;
JS_ALWAYS_INLINE bool isMarked(uint32 color = BLACK) const;
JS_ALWAYS_INLINE bool markIfUnmarked(uint32 color = BLACK) const;

View File

@ -427,7 +427,7 @@ struct JSRuntime {
int64 gcNextFullGCTime;
int64 gcJitReleaseTime;
JSGCMode gcMode;
volatile bool gcIsNeeded;
volatile jsuword gcIsNeeded;
js::WeakMapBase *gcWeakMapList;
/* Pre-allocated space for the GC mark stacks. Pointer type ensures alignment. */
@ -1794,17 +1794,33 @@ class AutoXMLRooter : private AutoGCRooter {
class AutoLockGC {
public:
explicit AutoLockGC(JSRuntime *rt
explicit AutoLockGC(JSRuntime *rt = NULL
JS_GUARD_OBJECT_NOTIFIER_PARAM)
: rt(rt)
: runtime(rt)
{
JS_GUARD_OBJECT_NOTIFIER_INIT;
if (rt)
JS_LOCK_GC(rt);
}
bool locked() const {
return !!runtime;
}
void lock(JSRuntime *rt) {
JS_ASSERT(rt);
JS_ASSERT(!runtime);
runtime = rt;
JS_LOCK_GC(rt);
}
~AutoLockGC() { JS_UNLOCK_GC(rt); }
~AutoLockGC() {
if (runtime)
JS_UNLOCK_GC(runtime);
}
private:
JSRuntime *rt;
JSRuntime *runtime;
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
};

View File

@ -129,9 +129,6 @@ JSCompartment::~JSCompartment()
bool
JSCompartment::init(JSContext *cx)
{
for (unsigned i = 0; i < FINALIZE_LIMIT; i++)
arenas[i].init();
activeAnalysis = activeInference = false;
types.init(cx);
@ -140,7 +137,6 @@ JSCompartment::init(JSContext *cx)
JS_InitArenaPool(&pool, "analysis", 4096 - ARENA_HEADER_SIZE_HACK, 8);
freeLists.init();
if (!crossCompartmentWrappers.init())
return false;
@ -188,16 +184,6 @@ JSCompartment::getMjitCodeStats(size_t& method, size_t& regexp, size_t& unused)
}
#endif
bool
JSCompartment::arenaListsAreEmpty()
{
for (unsigned i = 0; i < FINALIZE_LIMIT; i++) {
if (!arenas[i].isEmpty())
return false;
}
return true;
}
static bool
IsCrossCompartmentWrapper(JSObject *wrapper)
{
@ -505,10 +491,10 @@ JSCompartment::markTypes(JSTracer *trc)
MarkScript(trc, script, "mark_types_script");
}
for (unsigned thingKind = FINALIZE_OBJECT0;
for (size_t thingKind = FINALIZE_OBJECT0;
thingKind <= FINALIZE_FUNCTION_AND_OBJECT_LAST;
thingKind++) {
for (CellIterUnderGC i(this, FinalizeKind(thingKind)); !i.done(); i.next()) {
for (CellIterUnderGC i(this, AllocKind(thingKind)); !i.done(); i.next()) {
JSObject *object = i.get<JSObject>();
if (!object->isNewborn() && object->hasSingletonType())
MarkObject(trc, *object, "mark_types_singleton");
@ -652,7 +638,7 @@ JSCompartment::sweep(JSContext *cx, uint32 releaseInterval)
void
JSCompartment::purge(JSContext *cx)
{
freeLists.purge();
arenas.purge();
dtoaCache.purge();
/*

View File

@ -394,8 +394,7 @@ struct JS_FRIEND_API(JSCompartment) {
JSRuntime *rt;
JSPrincipals *principals;
js::gc::ArenaList arenas[js::gc::FINALIZE_LIMIT];
js::gc::FreeLists freeLists;
js::gc::ArenaLists arenas;
uint32 gcBytes;
uint32 gcTriggerBytes;
@ -535,12 +534,6 @@ struct JS_FRIEND_API(JSCompartment) {
void markTypes(JSTracer *trc);
void sweep(JSContext *cx, uint32 releaseInterval);
void purge(JSContext *cx);
void finishArenaLists();
void finalizeObjectArenaLists(JSContext *cx);
void finalizeStringArenaLists(JSContext *cx);
void finalizeShapeArenaLists(JSContext *cx);
void finalizeScriptArenaLists(JSContext *cx);
bool arenaListsAreEmpty();
void setGCLastBytes(size_t lastBytes, JSGCInvocationKind gckind);
void reduceGCTriggerBytes(uint32 amount);

View File

@ -4891,7 +4891,7 @@ JSParseNode::getConstantValue(JSContext *cx, bool strictChecks, Value *vp)
case TOK_RC: {
JS_ASSERT((pn_op == JSOP_NEWINIT) && !(pn_xflags & PNX_NONCONST));
gc::FinalizeKind kind = GuessObjectGCKind(pn_count, false);
gc::AllocKind kind = GuessObjectGCKind(pn_count, false);
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
return false;
@ -7084,7 +7084,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
*/
JSObject *obj = NULL;
if (!cg->hasSharps() && cg->compileAndGo()) {
gc::FinalizeKind kind = GuessObjectGCKind(pn->pn_count, false);
gc::AllocKind kind = GuessObjectGCKind(pn->pn_count, false);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
return JS_FALSE;

View File

@ -773,7 +773,7 @@ NewCallObject(JSContext *cx, JSScript *script, JSObject &scopeChain, JSObject *c
Bindings &bindings = script->bindings;
size_t argsVars = bindings.countArgsAndVars();
size_t slots = JSObject::CALL_RESERVED_SLOTS + argsVars;
gc::FinalizeKind kind = gc::GetGCObjectKind(slots);
gc::AllocKind kind = gc::GetGCObjectKind(slots);
JSObject *callobj = js_NewGCObject(cx, kind);
if (!callobj)

File diff suppressed because it is too large Load Diff

View File

@ -80,43 +80,12 @@ namespace gc {
struct Arena;
struct MarkingDelay;
/* The kind of GC thing with a finalizer. */
enum FinalizeKind {
FINALIZE_OBJECT0,
FINALIZE_OBJECT0_BACKGROUND,
FINALIZE_OBJECT2,
FINALIZE_OBJECT2_BACKGROUND,
FINALIZE_OBJECT4,
FINALIZE_OBJECT4_BACKGROUND,
FINALIZE_OBJECT8,
FINALIZE_OBJECT8_BACKGROUND,
FINALIZE_OBJECT12,
FINALIZE_OBJECT12_BACKGROUND,
FINALIZE_OBJECT16,
FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_OBJECT_LAST = FINALIZE_OBJECT16_BACKGROUND,
FINALIZE_FUNCTION,
FINALIZE_FUNCTION_AND_OBJECT_LAST = FINALIZE_FUNCTION,
FINALIZE_SCRIPT,
FINALIZE_SHAPE,
FINALIZE_TYPE_OBJECT,
#if JS_HAS_XML_SUPPORT
FINALIZE_XML,
#endif
FINALIZE_SHORT_STRING,
FINALIZE_STRING,
FINALIZE_EXTERNAL_STRING,
FINALIZE_LIMIT
};
/*
* This must be an upper bound, but we do not need the least upper bound, so
* we just exclude non-background objects.
*/
const size_t MAX_BACKGROUND_FINALIZE_KINDS = FINALIZE_LIMIT - (FINALIZE_OBJECT_LAST + 1) / 2;
extern JS_FRIEND_DATA(const uint8) GCThingSizeMap[];
const size_t ArenaShift = 12;
const size_t ArenaSize = size_t(1) << ArenaShift;
const size_t ArenaMask = ArenaSize - 1;
@ -174,7 +143,7 @@ struct FreeSpan {
* To minimize the size of the arena header the first span is encoded
* there as offsets from the arena start.
*/
static size_t encodeOffsets(size_t firstOffset, size_t lastOffset = ArenaSize - 1) {
static size_t encodeOffsets(size_t firstOffset, size_t lastOffset) {
/* Check that we can pack the offsets into uint16. */
JS_STATIC_ASSERT(ArenaShift < 16);
JS_ASSERT(firstOffset <= ArenaSize);
@ -183,7 +152,11 @@ struct FreeSpan {
return firstOffset | (lastOffset << 16);
}
static const size_t EmptyOffsets = ArenaSize | ((ArenaSize - 1) << 16);
/*
* Encoded offsets for a full arena when its first span is the last one
* and empty.
*/
static const size_t FullArenaOffsets = ArenaSize | ((ArenaSize - 1) << 16);
static FreeSpan decodeOffsets(uintptr_t arenaAddr, size_t offsets) {
JS_ASSERT(!(arenaAddr & ArenaMask));
@ -287,6 +260,37 @@ struct FreeSpan {
return reinterpret_cast<void *>(thing);
}
/* A version of allocate when we know that the span is not empty. */
JS_ALWAYS_INLINE void *infallibleAllocate(size_t thingSize) {
JS_ASSERT(thingSize % Cell::CellSize == 0);
checkSpan();
uintptr_t thing = first;
if (thing < last) {
first = thing + thingSize;
} else {
JS_ASSERT(thing == last);
*this = *reinterpret_cast<FreeSpan *>(thing);
}
checkSpan();
return reinterpret_cast<void *>(thing);
}
/*
* Allocate from a newly allocated arena. We do not move the free list
* from the arena. Rather we set the arena up as fully used during the
* initialization so to allocate we simply return the first thing in the
* arena and set the free list to point to the second.
*/
JS_ALWAYS_INLINE void *allocateFromNewArena(uintptr_t arenaAddr, size_t firstThingOffset,
size_t thingSize) {
JS_ASSERT(!(arenaAddr & ArenaMask));
uintptr_t thing = arenaAddr | firstThingOffset;
first = thing + thingSize;
last = arenaAddr | ArenaMask;
checkSpan();
return reinterpret_cast<void *>(thing);
}
void checkSpan() const {
#ifdef DEBUG
/* We do not allow spans at the end of the address space. */
@ -365,13 +369,13 @@ struct ArenaHeader {
size_t firstFreeSpanOffsets;
/*
* One of FinalizeKind constants or FINALIZE_LIMIT when the arena does not
* One of AllocKind constants or FINALIZE_LIMIT when the arena does not
* contain any GC things and is on the list of empty arenas in the GC
* chunk. The later allows to quickly check if the arena is allocated
* chunk. The latter allows to quickly check if the arena is allocated
* during the conservative GC scanning without searching the arena in the
* list.
*/
unsigned thingKind;
unsigned allocKind;
friend struct FreeLists;
@ -380,14 +384,15 @@ struct ArenaHeader {
inline Chunk *chunk() const;
void setAsNotAllocated() {
thingKind = FINALIZE_LIMIT;
allocKind = FINALIZE_LIMIT;
}
bool allocated() const {
return thingKind < FINALIZE_LIMIT;
JS_ASSERT(allocKind <= FINALIZE_LIMIT);
return allocKind < FINALIZE_LIMIT;
}
inline void init(JSCompartment *comp, unsigned thingKind, size_t thingSize);
inline void init(JSCompartment *comp, AllocKind kind);
uintptr_t arenaAddress() const {
return address();
@ -397,17 +402,21 @@ struct ArenaHeader {
return reinterpret_cast<Arena *>(arenaAddress());
}
unsigned getThingKind() const {
AllocKind getAllocKind() const {
JS_ASSERT(allocated());
return thingKind;
return AllocKind(allocKind);
}
inline size_t getThingSize() const;
bool hasFreeThings() const {
return firstFreeSpanOffsets != FreeSpan::EmptyOffsets;
return firstFreeSpanOffsets != FreeSpan::FullArenaOffsets;
}
inline bool isEmpty() const;
void setAsFullyUsed() {
firstFreeSpanOffsets = FreeSpan::EmptyOffsets;
firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
}
FreeSpan getFirstFreeSpan() const {
@ -424,10 +433,6 @@ struct ArenaHeader {
inline MarkingDelay *getMarkingDelay() const;
size_t getThingSize() const {
return GCThingSizeMap[getThingKind()];
}
#ifdef DEBUG
void checkSynchronizedWithFreeList() const;
#endif
@ -446,13 +451,24 @@ struct Arena {
* +-------------+-----+----+----+-----+----+
*
* <----------------------------------------> = ArenaSize bytes
* <-------------------> = thingsStartOffset
* <-------------------> = first thing offset
*/
ArenaHeader aheader;
uint8_t data[ArenaSize - sizeof(ArenaHeader)];
static void staticAsserts() {
JS_STATIC_ASSERT(sizeof(Arena) == ArenaSize);
private:
static JS_FRIEND_DATA(const uint32) ThingSizes[];
static JS_FRIEND_DATA(const uint32) FirstThingOffsets[];
public:
static void staticAsserts();
static size_t thingSize(AllocKind kind) {
return ThingSizes[kind];
}
static size_t firstThingOffset(AllocKind kind) {
return FirstThingOffsets[kind];
}
static size_t thingsPerArena(size_t thingSize) {
@ -461,9 +477,6 @@ struct Arena {
/* We should be able to fit FreeSpan in any GC thing. */
JS_ASSERT(thingSize >= sizeof(FreeSpan));
/* GCThingSizeMap assumes that any thing fits uint8. */
JS_ASSERT(thingSize < 256);
return (ArenaSize - sizeof(ArenaHeader)) / thingSize;
}
@ -471,10 +484,6 @@ struct Arena {
return thingsPerArena(thingSize) * thingSize;
}
static size_t thingsStartOffset(size_t thingSize) {
return ArenaSize - thingsSpan(thingSize);
}
static bool isAligned(uintptr_t thing, size_t thingSize) {
/* Things ends at the arena end. */
uintptr_t tailOffset = (ArenaSize - thing) & ArenaMask;
@ -485,8 +494,8 @@ struct Arena {
return aheader.address();
}
uintptr_t thingsStart(size_t thingSize) {
return address() | thingsStartOffset(thingSize);
uintptr_t thingsStart(AllocKind thingKind) {
return address() | firstThingOffset(thingKind);
}
uintptr_t thingsEnd() {
@ -494,7 +503,7 @@ struct Arena {
}
template <typename T>
bool finalize(JSContext *cx);
bool finalize(JSContext *cx, AllocKind thingKind, size_t thingSize);
};
/*
@ -641,8 +650,7 @@ struct Chunk {
inline void addToAvailableList(JSCompartment *compartment);
inline void removeFromAvailableList();
template <size_t thingSize>
ArenaHeader *allocateArena(JSContext *cx, unsigned thingKind);
ArenaHeader *allocateArena(JSContext *cx, AllocKind kind);
void releaseArena(ArenaHeader *aheader);
};
@ -676,6 +684,12 @@ Cell::chunk() const
return reinterpret_cast<Chunk *>(addr);
}
AllocKind
Cell::getAllocKind() const
{
return arenaHeader()->getAllocKind();
}
#ifdef DEBUG
inline bool
Cell::isAligned() const
@ -685,13 +699,15 @@ Cell::isAligned() const
#endif
inline void
ArenaHeader::init(JSCompartment *comp, unsigned kind, size_t thingSize)
ArenaHeader::init(JSCompartment *comp, AllocKind kind)
{
JS_ASSERT(!allocated());
JS_ASSERT(!getMarkingDelay()->link);
compartment = comp;
thingKind = kind;
firstFreeSpanOffsets = FreeSpan::encodeOffsets(Arena::thingsStartOffset(thingSize));
allocKind = kind;
/* See comments in FreeSpan::allocateFromNewArena. */
firstFreeSpanOffsets = FreeSpan::FullArenaOffsets;
}
inline uintptr_t
@ -709,6 +725,22 @@ ArenaHeader::chunk() const
return Chunk::fromAddress(address());
}
inline bool
ArenaHeader::isEmpty() const
{
/* Arena is empty if its first span covers the whole arena. */
JS_ASSERT(allocated());
size_t firstThingOffset = Arena::firstThingOffset(getAllocKind());
return firstFreeSpanOffsets == FreeSpan::encodeOffsets(firstThingOffset, ArenaMask);
}
inline size_t
ArenaHeader::getThingSize() const
{
JS_ASSERT(allocated());
return Arena::thingSize(getAllocKind());
}
JS_ALWAYS_INLINE void
ChunkBitmap::getMarkWordAndMask(const Cell *cell, uint32 color,
uintptr_t **wordp, uintptr_t *maskp)
@ -779,7 +811,7 @@ const float GC_HEAP_GROWTH_FACTOR = 3.0f;
static const int64 GC_IDLE_FULL_SPAN = 20 * 1000 * 1000;
static inline JSGCTraceKind
GetFinalizableTraceKind(size_t thingKind)
MapAllocToTraceKind(AllocKind thingKind)
{
static const JSGCTraceKind map[FINALIZE_LIMIT] = {
JSTRACE_OBJECT, /* FINALIZE_OBJECT0 */
@ -805,8 +837,6 @@ GetFinalizableTraceKind(size_t thingKind)
JSTRACE_STRING, /* FINALIZE_STRING */
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING */
};
JS_ASSERT(thingKind < FINALIZE_LIMIT);
return map[thingKind];
}
@ -819,11 +849,46 @@ GetGCThingRuntime(void *thing)
return reinterpret_cast<Cell *>(thing)->chunk()->info.runtime;
}
/* The arenas in a list have uniform kind. */
class ArenaList {
struct ArenaLists {
/*
* ArenaList::head points to the start of the list. Normally cursor points
* to the first arena in the list with some free things and all arenas
* before cursor are fully allocated. However, as the arena currently being
* allocated from is considered full while its list of free spans is moved
* into the freeList, during the GC or cell enumeration, when an
* unallocated freeList is moved back to the arena, we can see an arena
* with some free cells before the cursor. The cursor is an indirect
* pointer to allow for efficient list insertion at the cursor point and
* other list manipulations.
*/
struct ArenaList {
ArenaHeader *head;
ArenaHeader **cursor;
ArenaList() {
clear();
}
void clear() {
head = NULL;
cursor = &head;
}
};
private:
ArenaHeader *head; /* list start */
ArenaHeader **cursor; /* arena with free things */
/*
* For each arena kind its free list is represented as the first span with
* free things. Initially all the spans are initialized as empty. After we
* find a new arena with available things we move its first free span into
* the list and set the arena as fully allocated. way we do not need to
* update the arena header after the initial allocation. When starting the
* GC we only move the head of the of the list of spans back to the arena
* only for the arena that was not fully allocated.
*/
FreeSpan freeLists[FINALIZE_LIMIT];
ArenaList arenaLists[FINALIZE_LIMIT];
#ifdef JS_THREADSAFE
/*
@ -848,116 +913,95 @@ class ArenaList {
BFS_JUST_FINISHED
};
volatile BackgroundFinalizeState backgroundFinalizeState;
volatile uintptr_t backgroundFinalizeState[FINALIZE_LIMIT];
#endif
public:
void init() {
head = NULL;
cursor = &head;
ArenaLists() {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
freeLists[i].initAsEmpty();
#ifdef JS_THREADSAFE
backgroundFinalizeState = BFS_DONE;
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
backgroundFinalizeState[i] = BFS_DONE;
#endif
}
ArenaHeader *getHead() { return head; }
inline ArenaHeader *searchForFreeArena();
template <size_t thingSize>
inline ArenaHeader *getArenaWithFreeList(JSContext *cx, unsigned thingKind);
template<typename T>
void finalizeNow(JSContext *cx);
~ArenaLists() {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
#ifdef JS_THREADSAFE
template<typename T>
inline void finalizeLater(JSContext *cx);
static void backgroundFinalize(JSContext *cx, ArenaHeader *listHead);
bool willBeFinalizedLater() const {
return backgroundFinalizeState == BFS_RUN;
}
bool doneBackgroundFinalize() const {
return backgroundFinalizeState == BFS_DONE;
}
/*
* We can only call this during the shutdown after the last GC when
* the background finalization is disabled.
*/
JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE);
#endif
ArenaHeader **headp = &arenaLists[i].head;
while (ArenaHeader *aheader = *headp) {
*headp = aheader->next;
aheader->chunk()->releaseArena(aheader);
}
}
}
const FreeSpan *getFreeList(AllocKind thingKind) const {
return &freeLists[thingKind];
}
ArenaHeader *getFirstArena(AllocKind thingKind) const {
return arenaLists[thingKind].head;
}
bool arenaListsAreEmpty() const {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
#ifdef JS_THREADSAFE
/*
* The arena cannot be empty if the background finalization is not yet
* done.
*/
if (backgroundFinalizeState[i] != BFS_DONE)
return false;
#endif
if (arenaLists[i].head)
return false;
}
return true;
}
#ifdef DEBUG
bool markedThingsInArenaList() {
bool checkArenaListAllUnmarked() const {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
# ifdef JS_THREADSAFE
/* The background finalization must have stopped at this point. */
JS_ASSERT(backgroundFinalizeState == BFS_DONE ||
backgroundFinalizeState == BFS_JUST_FINISHED);
/* The background finalization must have stopped at this point. */
JS_ASSERT(backgroundFinalizeState[i] == BFS_DONE ||
backgroundFinalizeState[i] == BFS_JUST_FINISHED);
# endif
for (ArenaHeader *aheader = head; aheader; aheader = aheader->next) {
if (!aheader->chunk()->bitmap.noBitsSet(aheader))
return true;
for (ArenaHeader *aheader = arenaLists[i].head; aheader; aheader = aheader->next) {
if (!aheader->chunk()->bitmap.noBitsSet(aheader))
return false;
}
}
return false;
return true;
}
#endif /* DEBUG */
void releaseAll(unsigned thingKind) {
# ifdef JS_THREADSAFE
/*
* We can only call this during the shutdown after the last GC when
* the background finalization is disabled.
*/
JS_ASSERT(backgroundFinalizeState == BFS_DONE);
# endif
while (ArenaHeader *aheader = head) {
head = aheader->next;
aheader->chunk()->releaseArena(aheader);
}
cursor = &head;
}
bool isEmpty() const {
#ifdef JS_THREADSAFE
/*
* The arena cannot be empty if the background finalization is not yet
* done.
*/
if (backgroundFinalizeState != BFS_DONE)
return false;
#endif
return !head;
}
};
struct FreeLists {
/*
* For each arena kind its free list is represented as the first span with
* free things. Initially all the spans are zeroed to be treated as empty
* spans by the allocation code. After we find a new arena with available
* things we copy its first free span into the list and set the arena as
* if it has no free things. This way we do not need to update the arena
* header after the initial allocation. When starting the GC We only move
* the head of the of the list of spans back to the arena only for the
* arena that was not fully allocated.
*/
FreeSpan lists[FINALIZE_LIMIT];
void init() {
for (size_t i = 0; i != JS_ARRAY_LENGTH(lists); ++i)
lists[i].initAsEmpty();
#ifdef JS_THREADSAFE
bool doneBackgroundFinalize(AllocKind kind) const {
return backgroundFinalizeState[kind] == BFS_DONE;
}
#endif
/*
* Return the free list back to the arena so the GC finalization will not
* run the finalizers over unitialized bytes from free things.
*/
void purge() {
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i) {
FreeSpan *list = &lists[i];
if (!list->isEmpty()) {
ArenaHeader *aheader = list->arenaHeader();
for (size_t i = 0; i != FINALIZE_LIMIT; ++i) {
FreeSpan *headSpan = &freeLists[i];
if (!headSpan->isEmpty()) {
ArenaHeader *aheader = headSpan->arenaHeader();
JS_ASSERT(!aheader->hasFreeThings());
aheader->setFirstFreeSpan(list);
list->initAsEmpty();
aheader->setFirstFreeSpan(headSpan);
headSpan->initAsEmpty();
}
}
}
@ -967,17 +1011,17 @@ struct FreeLists {
* the proper value in ArenaHeader::freeList when accessing the latter
* outside the GC.
*/
void copyToArenas() {
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i)
copyToArena(FinalizeKind(i));
void copyFreeListsToArenas() {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
copyFreeListToArena(AllocKind(i));
}
void copyToArena(FinalizeKind thingKind) {
FreeSpan *list = &lists[thingKind];
if (!list->isEmpty()) {
ArenaHeader *aheader = list->arenaHeader();
void copyFreeListToArena(AllocKind thingKind) {
FreeSpan *headSpan = &freeLists[thingKind];
if (!headSpan->isEmpty()) {
ArenaHeader *aheader = headSpan->arenaHeader();
JS_ASSERT(!aheader->hasFreeThings());
aheader->setFirstFreeSpan(list);
aheader->setFirstFreeSpan(headSpan);
}
}
@ -985,17 +1029,17 @@ struct FreeLists {
* Clear the free lists in arenas that were temporarily set there using
* copyToArenas.
*/
void clearInArenas() {
for (size_t i = 0; i != size_t(FINALIZE_LIMIT); ++i)
clearInArena(FinalizeKind(i));
void clearFreeListsInArenas() {
for (size_t i = 0; i != FINALIZE_LIMIT; ++i)
clearFreeListInArena(AllocKind(i));
}
void clearInArena(FinalizeKind thingKind) {
FreeSpan *list = &lists[thingKind];
if (!list->isEmpty()) {
ArenaHeader *aheader = list->arenaHeader();
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
void clearFreeListInArena(AllocKind kind) {
FreeSpan *headSpan = &freeLists[kind];
if (!headSpan->isEmpty()) {
ArenaHeader *aheader = headSpan->arenaHeader();
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
aheader->setAsFullyUsed();
}
}
@ -1004,45 +1048,54 @@ struct FreeLists {
* Check that the free list is either empty or were synchronized with the
* arena using copyToArena().
*/
bool isSynchronizedWithArena(FinalizeKind thingKind) {
FreeSpan *list = &lists[thingKind];
if (list->isEmpty())
bool isSynchronizedFreeList(AllocKind kind) {
FreeSpan *headSpan = &freeLists[kind];
if (headSpan->isEmpty())
return true;
ArenaHeader *aheader = list->arenaHeader();
ArenaHeader *aheader = headSpan->arenaHeader();
if (aheader->hasFreeThings()) {
/*
* If the arena has a free list, it must be the same as one in
* lists.
*/
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(list));
*/
JS_ASSERT(aheader->getFirstFreeSpan().isSameNonEmptySpan(headSpan));
return true;
}
return false;
}
JS_ALWAYS_INLINE void *getNext(unsigned thingKind, size_t thingSize) {
return lists[thingKind].allocate(thingSize);
JS_ALWAYS_INLINE void *allocateFromFreeList(AllocKind thingKind, size_t thingSize) {
return freeLists[thingKind].allocate(thingSize);
}
void *populate(ArenaHeader *aheader, unsigned thingKind, size_t thingSize) {
FreeSpan *list = &lists[thingKind];
*list = aheader->getFirstFreeSpan();
aheader->setAsFullyUsed();
void *t = list->allocate(thingSize);
JS_ASSERT(t);
return t;
}
static void *refillFreeList(JSContext *cx, AllocKind thingKind);
void checkEmpty() {
void checkEmptyFreeLists() {
#ifdef DEBUG
for (size_t i = 0; i != JS_ARRAY_LENGTH(lists); ++i)
JS_ASSERT(lists[i].isEmpty());
for (size_t i = 0; i != JS_ARRAY_LENGTH(freeLists); ++i)
JS_ASSERT(freeLists[i].isEmpty());
#endif
}
};
extern void *
RefillFinalizableFreeList(JSContext *cx, unsigned thingKind);
void checkEmptyFreeList(AllocKind kind) {
JS_ASSERT(freeLists[kind].isEmpty());
}
void finalizeObjects(JSContext *cx);
void finalizeStrings(JSContext *cx);
void finalizeShapes(JSContext *cx);
void finalizeScripts(JSContext *cx);
#ifdef JS_THREADSAFE
static void backgroundFinalize(JSContext *cx, ArenaHeader *listHead);
private:
inline void finalizeNow(JSContext *cx, AllocKind thingKind);
inline void finalizeLater(JSContext *cx, AllocKind thingKind);
inline void *allocateFromArena(JSContext *cx, AllocKind thingKind);
#endif
};
/*
* Initial allocation size for data structures holding chunks is set to hold
@ -1254,7 +1307,7 @@ class GCHelperThread {
Vector<js::gc::ArenaHeader *, 64, js::SystemAllocPolicy> finalizeVector;
friend class js::gc::ArenaList;
friend struct js::gc::ArenaLists;
JS_FRIEND_API(void)
replenishAndFreeLater(void *ptr);
@ -1520,7 +1573,7 @@ IterateCompartmentsArenasCells(JSContext *cx, void *data,
* the given compartment or for all compartments if it is null.
*/
extern JS_FRIEND_API(void)
IterateCells(JSContext *cx, JSCompartment *compartment, gc::FinalizeKind thingKind,
IterateCells(JSContext *cx, JSCompartment *compartment, gc::AllocKind thingKind,
void *data, IterateCellCallback cellCallback);
} /* namespace js */

View File

@ -119,17 +119,17 @@ GetGCThingTraceKind(const void *thing)
if (JSAtom::isStatic(thing))
return JSTRACE_STRING;
const Cell *cell = reinterpret_cast<const Cell *>(thing);
return GetFinalizableTraceKind(cell->arenaHeader()->getThingKind());
return MapAllocToTraceKind(cell->getAllocKind());
}
/* Capacity for slotsToThingKind */
const size_t SLOTS_TO_THING_KIND_LIMIT = 17;
/* Get the best kind to use when making an object with the given slot count. */
static inline FinalizeKind
static inline AllocKind
GetGCObjectKind(size_t numSlots, bool isArray = false)
{
extern FinalizeKind slotsToThingKind[];
extern AllocKind slotsToThingKind[];
if (numSlots >= SLOTS_TO_THING_KIND_LIMIT) {
/*
@ -144,37 +144,36 @@ GetGCObjectKind(size_t numSlots, bool isArray = false)
}
static inline bool
IsBackgroundFinalizeKind(FinalizeKind kind)
IsBackgroundAllocKind(AllocKind kind)
{
JS_ASSERT(kind <= FINALIZE_OBJECT_LAST);
return kind % 2 == 1;
}
static inline FinalizeKind
GetBackgroundFinalizeKind(FinalizeKind kind)
static inline AllocKind
GetBackgroundAllocKind(AllocKind kind)
{
JS_ASSERT(!IsBackgroundFinalizeKind(kind));
return (FinalizeKind) (kind + 1);
JS_ASSERT(!IsBackgroundAllocKind(kind));
return (AllocKind) (kind + 1);
}
/*
* Try to get the next larger size for an object, keeping BACKGROUND
* consistent.
*/
static inline bool
CanBumpFinalizeKind(FinalizeKind kind)
TryIncrementAllocKind(AllocKind *kindp)
{
JS_ASSERT(kind <= FINALIZE_OBJECT_LAST);
return (kind + 2) <= FINALIZE_OBJECT_LAST;
}
/* Get the next larger size for an object, keeping BACKGROUND consistent. */
static inline FinalizeKind
BumpFinalizeKind(FinalizeKind kind)
{
JS_ASSERT(CanBumpFinalizeKind(kind));
return (FinalizeKind) (kind + 2);
size_t next = size_t(*kindp) + 2;
if (next > size_t(FINALIZE_OBJECT_LAST))
return false;
*kindp = AllocKind(next);
return true;
}
/* Get the number of fixed slots and initial capacity associated with a kind. */
static inline size_t
GetGCKindSlots(FinalizeKind thingKind)
GetGCKindSlots(AllocKind thingKind)
{
/* Using a switch in hopes that thingKind will usually be a compile-time constant. */
switch (thingKind) {
@ -229,11 +228,11 @@ GCPoke(JSContext *cx, Value oldval)
*/
template <class ArenaOp, class CellOp>
void
ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind,
ForEachArenaAndCell(JSCompartment *compartment, AllocKind thingKind,
ArenaOp arenaOp, CellOp cellOp)
{
size_t thingSize = GCThingSizeMap[thingKind];
ArenaHeader *aheader = compartment->arenas[thingKind].getHead();
size_t thingSize = Arena::thingSize(thingKind);
ArenaHeader *aheader = compartment->arenas.getFirstArena(thingKind);
for (; aheader; aheader = aheader->next) {
Arena *arena = aheader->getArena();
@ -241,7 +240,7 @@ ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind,
FreeSpan firstSpan(aheader->getFirstFreeSpan());
const FreeSpan *span = &firstSpan;
for (uintptr_t thing = arena->thingsStart(thingSize); ; thing += thingSize) {
for (uintptr_t thing = arena->thingsStart(thingKind); ; thing += thingSize) {
JS_ASSERT(thing <= arena->thingsEnd());
if (thing == span->first) {
if (!span->hasNext())
@ -258,6 +257,7 @@ ForEachArenaAndCell(JSCompartment *compartment, FinalizeKind thingKind,
class CellIterImpl
{
size_t firstThingOffset;
size_t thingSize;
ArenaHeader *aheader;
FreeSpan firstSpan;
@ -269,9 +269,10 @@ class CellIterImpl
CellIterImpl() {
}
void init(JSCompartment *comp, FinalizeKind thingKind) {
thingSize = GCThingSizeMap[thingKind];
aheader = comp->arenas[thingKind].getHead();
void init(JSCompartment *comp, AllocKind kind) {
firstThingOffset = Arena::firstThingOffset(kind);
thingSize = Arena::thingSize(kind);
aheader = comp->arenas.getFirstArena(kind);
firstSpan.initAsEmpty();
span = &firstSpan;
thing = span->first;
@ -308,7 +309,7 @@ class CellIterImpl
}
firstSpan = aheader->getFirstFreeSpan();
span = &firstSpan;
thing = aheader->getArena()->thingsStart(thingSize);
thing = aheader->arenaAddress() | firstThingOffset;
aheader = aheader->next;
}
cell = reinterpret_cast<Cell *>(thing);
@ -319,10 +320,10 @@ class CellIterImpl
class CellIterUnderGC : public CellIterImpl {
public:
CellIterUnderGC(JSCompartment *comp, FinalizeKind thingKind) {
CellIterUnderGC(JSCompartment *comp, AllocKind kind) {
JS_ASSERT(comp->rt->gcRunning);
JS_ASSERT(comp->freeLists.lists[thingKind].isEmpty());
init(comp, thingKind);
comp->arenas.checkEmptyFreeList(kind);
init(comp, kind);
}
};
@ -333,29 +334,29 @@ class CellIterUnderGC : public CellIterImpl {
*/
class CellIter: public CellIterImpl
{
FreeLists *lists;
FinalizeKind thingKind;
ArenaLists *lists;
AllocKind kind;
#ifdef DEBUG
size_t *counter;
#endif
public:
CellIter(JSContext *cx, JSCompartment *comp, FinalizeKind thingKind)
: lists(&comp->freeLists),
thingKind(thingKind) {
CellIter(JSContext *cx, JSCompartment *comp, AllocKind kind)
: lists(&comp->arenas),
kind(kind) {
#ifdef JS_THREADSAFE
JS_ASSERT(comp->arenas[thingKind].doneBackgroundFinalize());
JS_ASSERT(comp->arenas.doneBackgroundFinalize(kind));
#endif
if (lists->isSynchronizedWithArena(thingKind)) {
if (lists->isSynchronizedFreeList(kind)) {
lists = NULL;
} else {
JS_ASSERT(!comp->rt->gcRunning);
lists->copyToArena(thingKind);
lists->copyFreeListToArena(kind);
}
#ifdef DEBUG
counter = &JS_THREAD_DATA(cx)->noGCOrAllocationCheck;
++*counter;
#endif
init(comp, thingKind);
init(comp, kind);
}
~CellIter() {
@ -364,7 +365,7 @@ class CellIter: public CellIterImpl
--*counter;
#endif
if (lists)
lists->clearInArena(thingKind);
lists->clearFreeListInArena(kind);
}
};
@ -385,14 +386,12 @@ inline void EmptyCellOp(Cell *t) {}
template <typename T>
inline T *
NewGCThing(JSContext *cx, unsigned thingKind, size_t thingSize)
NewGCThing(JSContext *cx, js::gc::AllocKind kind, size_t thingSize)
{
JS_ASSERT(thingKind < js::gc::FINALIZE_LIMIT);
JS_ASSERT(thingSize == js::gc::GCThingSizeMap[thingKind]);
JS_ASSERT(thingSize == js::gc::Arena::thingSize(kind));
#ifdef JS_THREADSAFE
JS_ASSERT_IF((cx->compartment == cx->runtime->atomsCompartment),
(thingKind == js::gc::FINALIZE_STRING) ||
(thingKind == js::gc::FINALIZE_SHORT_STRING));
kind == js::gc::FINALIZE_STRING || kind == js::gc::FINALIZE_SHORT_STRING);
#endif
JS_ASSERT(!cx->runtime->gcRunning);
JS_ASSERT(!JS_THREAD_DATA(cx)->noGCOrAllocationCheck);
@ -402,15 +401,15 @@ NewGCThing(JSContext *cx, unsigned thingKind, size_t thingSize)
js::gc::RunDebugGC(cx);
#endif
void *t = cx->compartment->freeLists.getNext(thingKind, thingSize);
return static_cast<T *>(t ? t : js::gc::RefillFinalizableFreeList(cx, thingKind));
void *t = cx->compartment->arenas.allocateFromFreeList(kind, thingSize);
return static_cast<T *>(t ? t : js::gc::ArenaLists::refillFreeList(cx, kind));
}
inline JSObject *
js_NewGCObject(JSContext *cx, js::gc::FinalizeKind kind)
js_NewGCObject(JSContext *cx, js::gc::AllocKind kind)
{
JS_ASSERT(kind >= js::gc::FINALIZE_OBJECT0 && kind <= js::gc::FINALIZE_OBJECT_LAST);
JSObject *obj = NewGCThing<JSObject>(cx, kind, js::gc::GCThingSizeMap[kind]);
JSObject *obj = NewGCThing<JSObject>(cx, kind, js::gc::Arena::thingSize(kind));
if (obj)
obj->earlyInit(js::gc::GetGCKindSlots(kind));
return obj;

View File

@ -71,7 +71,6 @@ ConservativeGCStats::dump(FILE *fp)
fprintf(fp, " not withing a chunk: %lu\n", ULSTAT(counter[CGCT_NOTCHUNK]));
fprintf(fp, " not within arena range: %lu\n", ULSTAT(counter[CGCT_NOTARENA]));
fprintf(fp, " points to free arena: %lu\n", ULSTAT(counter[CGCT_FREEARENA]));
fprintf(fp, " excluded, wrong tag: %lu\n", ULSTAT(counter[CGCT_WRONGTAG]));
fprintf(fp, " excluded, not live: %lu\n", ULSTAT(counter[CGCT_NOTLIVE]));
fprintf(fp, " valid GC things: %lu\n", ULSTAT(counter[CGCT_VALID]));
fprintf(fp, " valid but not aligned: %lu\n", ULSTAT(unaligned));
@ -204,7 +203,7 @@ GCMarker::dumpConservativeRoots()
volatile GCTimer::JSGCReason gcReason = GCTimer::NOREASON;
const char *gcReasons[] = {" API", "Maybe", "LastC", "DestC", "Compa", "LastD",
"Malloc", "Alloc", "Chunk", "Shape", " None"};
"Malloc", "Refill", "Chunk", "Shape", " None"};
jsrefcount newChunkCount = 0;
jsrefcount destroyChunkCount = 0;

View File

@ -99,7 +99,6 @@ enum ConservativeGCTest
CGCT_NOTARENA, /* not within arena range in a chunk */
CGCT_NOTCHUNK, /* not within a valid chunk */
CGCT_FREEARENA, /* within arena containing only free things */
CGCT_WRONGTAG, /* tagged pointer but wrong type */
CGCT_NOTLIVE, /* gcthing is not allocated */
CGCT_END
};
@ -162,7 +161,7 @@ struct GCTimer
LASTDITCH,
TOOMUCHMALLOC,
ALLOCTRIGGER,
CHUNK,
REFILL,
SHAPE,
NOREASON
};

View File

@ -2042,9 +2042,9 @@ TypeCompartment::nukeTypes(JSContext *cx)
*/
#ifdef JS_THREADSAFE
Maybe<AutoLockGC> maybeLock;
AutoLockGC maybeLock;
if (!cx->runtime->gcMarkAndSweep)
maybeLock.construct(cx->runtime);
maybeLock.lock(cx->runtime);
#endif
inferenceEnabled = false;
@ -4411,7 +4411,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script)
return;
}
gc::FinalizeKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
gc::AllocKind kind = gc::GetGCObjectKind(baseobj->slotSpan());
/* We should not have overflowed the maximum number of fixed slots for an object. */
JS_ASSERT(gc::GetGCKindSlots(kind) >= baseobj->slotSpan());
@ -4441,7 +4441,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSScript *script)
}
type->newScript->script = script;
type->newScript->finalizeKind = unsigned(kind);
type->newScript->allocKind = kind;
type->newScript->shape = baseobj->lastProperty();
type->newScript->initializerList = (TypeNewScript::Initializer *)
@ -5480,7 +5480,7 @@ TypeCompartment::sweep(JSContext *cx)
const AllocationSiteKey &key = e.front().key;
TypeObject *object = e.front().value;
if (key.script->isAboutToBeFinalized(cx) || !object->isMarked())
if (IsAboutToBeFinalized(cx, key.script) || !object->isMarked())
e.removeFront();
}
}
@ -5520,7 +5520,7 @@ TypeScript::Sweep(JSContext *cx, JSScript *script)
unsigned num = NumTypeSets(script);
TypeSet *typeArray = script->types->typeArray();
if (script->isAboutToBeFinalized(cx)) {
if (IsAboutToBeFinalized(cx, script)) {
/* Release all memory associated with the persistent type sets. */
for (unsigned i = 0; i < num; i++)
typeArray[i].clearObjects();

View File

@ -646,8 +646,8 @@ struct TypeNewScript
{
JSScript *script;
/* Finalize kind to use for newly constructed objects. */
/* gc::FinalizeKind */ unsigned finalizeKind;
/* Allocation kind to use for newly constructed objects. */
gc::AllocKind allocKind;
/*
* Shape to use for newly constructed objects. Reflects all definite
@ -806,8 +806,7 @@ struct TypeObject : gc::Cell
* used as the scope of a new object whose prototype is |proto|.
*/
inline bool canProvideEmptyShape(js::Class *clasp);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp,
/* gc::FinalizeKind */ unsigned kind);
inline js::EmptyShape *getEmptyShape(JSContext *cx, js::Class *aclasp, gc::AllocKind kind);
/*
* Get or create a property of this object. Only call this for properties which

View File

@ -1218,14 +1218,6 @@ TypeObject::setFlagsFromKey(JSContext *cx, JSProtoKey key)
} } /* namespace js::types */
inline bool
JSScript::isAboutToBeFinalized(JSContext *cx)
{
return isCachedEval ||
(u.object && IsAboutToBeFinalized(cx, u.object)) ||
(hasFunction && IsAboutToBeFinalized(cx, function()));
}
inline bool
JSScript::ensureHasTypes(JSContext *cx)
{

View File

@ -5238,7 +5238,7 @@ BEGIN_CASE(JSOP_NEWINIT)
if (i == JSProto_Array) {
obj = NewDenseEmptyArray(cx);
} else {
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
gc::AllocKind kind = GuessObjectGCKind(0, false);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
}

View File

@ -2913,7 +2913,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
if (!obj) {
/* Make an object whether this was called with 'new' or not. */
JS_ASSERT(!argc || vp[2].isNull() || vp[2].isUndefined());
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
return JS_FALSE;
@ -2928,7 +2928,7 @@ js_Object(JSContext *cx, uintN argc, Value *vp)
JSObject *
js::NewReshapedObject(JSContext *cx, TypeObject *type, JSObject *parent,
gc::FinalizeKind kind, const Shape *shape)
gc::AllocKind kind, const Shape *shape)
{
JSObject *res = NewObjectWithType(cx, type, parent, kind);
if (!res)
@ -2979,7 +2979,7 @@ js_CreateThis(JSContext *cx, JSObject *callee)
JSObject *proto = protov.isObjectOrNull() ? protov.toObjectOrNull() : NULL;
JSObject *parent = callee->getParent();
gc::FinalizeKind kind = NewObjectGCKind(cx, newclasp);
gc::AllocKind kind = NewObjectGCKind(cx, newclasp);
JSObject *obj = NewObject<WithProto::Class>(cx, newclasp, proto, parent, kind);
if (obj)
obj->syncSpecialEquality();
@ -2995,14 +2995,14 @@ CreateThisForFunctionWithType(JSContext *cx, types::TypeObject *type, JSObject *
* which reflects any properties that will definitely be added to the
* object before it is read from.
*/
gc::FinalizeKind kind = gc::FinalizeKind(type->newScript->finalizeKind);
gc::AllocKind kind = type->newScript->allocKind;
JSObject *res = NewObjectWithType(cx, type, parent, kind);
if (res)
res->setMap((Shape *) type->newScript->shape);
return res;
}
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
return NewObjectWithType(cx, type, parent, kind);
}
@ -3018,7 +3018,7 @@ js_CreateThisForFunctionWithProto(JSContext *cx, JSObject *callee, JSObject *pro
return NULL;
res = CreateThisForFunctionWithType(cx, type, callee->getParent());
} else {
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
res = NewNonFunction<WithProto::Class>(cx, &js_ObjectClass, proto, callee->getParent(), kind);
}
@ -3077,7 +3077,7 @@ JSObject* FASTCALL
js_InitializerObject(JSContext* cx, JSObject *proto, JSObject *baseobj)
{
if (!baseobj) {
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
gc::AllocKind kind = GuessObjectGCKind(0, false);
return NewObjectWithClassProto(cx, &js_ObjectClass, proto, kind);
}
@ -3129,7 +3129,7 @@ js_CreateThisFromTrace(JSContext *cx, JSObject *ctor, uintN protoSlot)
return NULL;
}
gc::FinalizeKind kind = NewObjectGCKind(cx, &js_ObjectClass);
gc::AllocKind kind = NewObjectGCKind(cx, &js_ObjectClass);
return NewNativeClassInstance(cx, &js_ObjectClass, proto, parent, kind);
}
JS_DEFINE_CALLINFO_3(extern, CONSTRUCTOR_RETRY, js_CreateThisFromTrace, CONTEXT, OBJECT, UINTN, 0,
@ -3405,7 +3405,7 @@ js_CloneBlockObject(JSContext *cx, JSObject *proto, StackFrame *fp)
JS_ASSERT(proto->isStaticBlock());
size_t count = OBJ_BLOCK_COUNT(cx, proto);
gc::FinalizeKind kind = gc::GetGCObjectKind(count + 1);
gc::AllocKind kind = gc::GetGCObjectKind(count + 1);
TypeObject *type = proto->getNewType(cx);
if (!type)
@ -3615,9 +3615,7 @@ JSObject::clone(JSContext *cx, JSObject *proto, JSObject *parent)
return NULL;
}
}
JSObject *clone = NewObject<WithProto::Given>(cx, getClass(),
proto, parent,
gc::FinalizeKind(finalizeKind()));
JSObject *clone = NewObject<WithProto::Given>(cx, getClass(), proto, parent, getAllocKind());
if (!clone)
return NULL;
if (isNative()) {
@ -4364,16 +4362,15 @@ JSObject::allocSlots(JSContext *cx, size_t newcap)
* objects are constructed.
*/
if (!hasLazyType() && type()->newScript) {
gc::FinalizeKind kind = gc::FinalizeKind(type()->newScript->finalizeKind);
gc::AllocKind kind = type()->newScript->allocKind;
unsigned newScriptSlots = gc::GetGCKindSlots(kind);
if (newScriptSlots == numFixedSlots() && gc::CanBumpFinalizeKind(kind)) {
kind = gc::BumpFinalizeKind(kind);
if (newScriptSlots == numFixedSlots() && gc::TryIncrementAllocKind(&kind)) {
JSObject *obj = NewReshapedObject(cx, type(), getParent(), kind,
type()->newScript->shape);
if (!obj)
return false;
type()->newScript->finalizeKind = kind;
type()->newScript->allocKind = kind;
type()->newScript->shape = obj->lastProperty();
type()->markStateChange(cx);
}

View File

@ -664,8 +664,6 @@ struct JSObject : js::gc::Cell {
inline bool hasPropertyTable() const;
/* gc::FinalizeKind */ unsigned finalizeKind() const;
uint32 numSlots() const { return uint32(capacity); }
inline size_t structSize() const;
@ -1279,7 +1277,7 @@ struct JSObject : js::gc::Cell {
js::types::TypeObject *type,
JSObject *parent,
void *priv,
/* gc::FinalizeKind */ unsigned kind);
js::gc::AllocKind kind);
inline bool hasProperty(JSContext *cx, jsid id, bool *foundp, uintN flags = 0);

View File

@ -402,12 +402,6 @@ JSObject::setPrimitiveThis(const js::Value &pthis)
setFixedSlot(JSSLOT_PRIMITIVE_THIS, pthis);
}
inline /* gc::FinalizeKind */ unsigned
JSObject::finalizeKind() const
{
return js::gc::FinalizeKind(arenaHeader()->getThingKind());
}
inline bool
JSObject::hasSlotsArray() const
{
@ -964,7 +958,7 @@ JSObject::initSharingEmptyShape(JSContext *cx,
js::types::TypeObject *type,
JSObject *parent,
void *privateValue,
/* js::gc::FinalizeKind */ unsigned kind)
js::gc::AllocKind kind)
{
init(cx, aclasp, type, parent, privateValue, false);
@ -1245,7 +1239,7 @@ class AutoPropertyDescriptorRooter : private AutoGCRooter, public PropertyDescri
static inline bool
InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::TypeObject *type,
gc::FinalizeKind kind)
gc::AllocKind kind)
{
JS_ASSERT(clasp->isNative());
@ -1273,7 +1267,7 @@ InitScopeForObject(JSContext* cx, JSObject* obj, js::Class *clasp, js::types::Ty
}
static inline bool
CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp)
CanBeFinalizedInBackground(gc::AllocKind kind, Class *clasp)
{
#ifdef JS_THREADSAFE
JS_ASSERT(kind <= gc::FINALIZE_OBJECT_LAST);
@ -1281,10 +1275,10 @@ CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp)
* a different thread, we change the finalize kind. For example,
* FINALIZE_OBJECT0 calls the finalizer on the main thread,
* FINALIZE_OBJECT0_BACKGROUND calls the finalizer on the gcHelperThread.
* IsBackgroundFinalizeKind is called to prevent recursively incrementing
* IsBackgroundAllocKind is called to prevent recursively incrementing
* the finalize kind; kind may already be a background finalize kind.
*/
if (!gc::IsBackgroundFinalizeKind(kind) &&
if (!gc::IsBackgroundAllocKind(kind) &&
(!clasp->finalize || clasp->flags & JSCLASS_CONCURRENT_FINALIZER)) {
return true;
}
@ -1300,7 +1294,7 @@ CanBeFinalizedInBackground(gc::FinalizeKind kind, Class *clasp)
*/
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
JSObject *parent, gc::FinalizeKind kind)
JSObject *parent, gc::AllocKind kind)
{
JS_ASSERT(proto);
JS_ASSERT(parent);
@ -1316,7 +1310,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
*/
if (CanBeFinalizedInBackground(kind, clasp))
kind = GetBackgroundFinalizeKind(kind);
kind = GetBackgroundAllocKind(kind);
JSObject* obj = js_NewGCObject(cx, kind);
@ -1343,7 +1337,7 @@ NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto,
static inline JSObject *
NewNativeClassInstance(JSContext *cx, Class *clasp, JSObject *proto, JSObject *parent)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewNativeClassInstance(cx, clasp, proto, parent, kind);
}
@ -1358,7 +1352,7 @@ FindClassPrototype(JSContext *cx, JSObject *scope, JSProtoKey protoKey, JSObject
* right default proto and parent for clasp in cx.
*/
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::AllocKind kind)
{
VOUCH_DOES_NOT_REQUIRE_STACK();
@ -1392,7 +1386,7 @@ NewBuiltinClassInstance(JSContext *cx, Class *clasp, gc::FinalizeKind kind)
static inline JSObject *
NewBuiltinClassInstance(JSContext *cx, Class *clasp)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewBuiltinClassInstance(cx, clasp, kind);
}
@ -1457,7 +1451,7 @@ namespace detail
template <bool withProto, bool isFunction>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
gc::AllocKind kind)
{
/* Bootstrap the ur-object, and make it the default prototype object. */
if (withProto == WithProto::Class && !proto) {
@ -1478,7 +1472,7 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
*/
if (!isFunction && CanBeFinalizedInBackground(kind, clasp))
kind = GetBackgroundFinalizeKind(kind);
kind = GetBackgroundAllocKind(kind);
JSObject* obj = isFunction ? js_NewGCFunction(cx) : js_NewGCObject(cx, kind);
if (!obj)
@ -1530,7 +1524,7 @@ NewFunction(JSContext *cx, JSObject *parent)
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
gc::AllocKind kind)
{
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
@ -1539,14 +1533,14 @@ template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewNonFunction(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return detail::NewObject<withProto, false>(cx, clasp, proto, parent, kind);
}
template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent,
gc::FinalizeKind kind)
gc::AllocKind kind)
{
if (clasp == &js_FunctionClass)
return detail::NewObject<withProto, true>(cx, clasp, proto, parent, kind);
@ -1557,7 +1551,7 @@ template <WithProto::e withProto>
static JS_ALWAYS_INLINE JSObject *
NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
{
gc::FinalizeKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
gc::AllocKind kind = gc::GetGCObjectKind(JSCLASS_RESERVED_SLOTS(clasp));
return NewObject<withProto>(cx, clasp, proto, parent, kind);
}
@ -1566,12 +1560,12 @@ NewObject(JSContext *cx, js::Class *clasp, JSObject *proto, JSObject *parent)
* avoid losing creation site information for objects made by scripted 'new'.
*/
static JS_ALWAYS_INLINE JSObject *
NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::FinalizeKind kind)
NewObjectWithType(JSContext *cx, types::TypeObject *type, JSObject *parent, gc::AllocKind kind)
{
JS_ASSERT(type == type->proto->newType);
if (CanBeFinalizedInBackground(kind, &js_ObjectClass))
kind = GetBackgroundFinalizeKind(kind);
kind = GetBackgroundAllocKind(kind);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
@ -1597,14 +1591,14 @@ out:
extern JSObject *
NewReshapedObject(JSContext *cx, js::types::TypeObject *type, JSObject *parent,
gc::FinalizeKind kind, const Shape *shape);
gc::AllocKind kind, const Shape *shape);
/*
* As for gc::GetGCObjectKind, where numSlots is a guess at the final size of
* the object, zero if the final size is unknown. This should only be used for
* objects that do not require any fixed slots.
*/
static inline gc::FinalizeKind
static inline gc::AllocKind
GuessObjectGCKind(size_t numSlots, bool isArray)
{
if (numSlots)
@ -1616,7 +1610,7 @@ GuessObjectGCKind(size_t numSlots, bool isArray)
* Get the GC kind to use for scripted 'new' on the given class.
* FIXME bug 547327: estimate the size from the allocation site.
*/
static inline gc::FinalizeKind
static inline gc::AllocKind
NewObjectGCKind(JSContext *cx, js::Class *clasp)
{
if (clasp == &js_ArrayClass || clasp == &js_SlowArrayClass)
@ -1628,17 +1622,16 @@ NewObjectGCKind(JSContext *cx, js::Class *clasp)
static JS_ALWAYS_INLINE JSObject*
NewObjectWithClassProto(JSContext *cx, Class *clasp, JSObject *proto,
/*gc::FinalizeKind*/ unsigned _kind)
gc::AllocKind kind)
{
JS_ASSERT(clasp->isNative());
gc::FinalizeKind kind = gc::FinalizeKind(_kind);
types::TypeObject *type = proto->getNewType(cx);
if (!type)
return NULL;
if (CanBeFinalizedInBackground(kind, clasp))
kind = GetBackgroundFinalizeKind(kind);
kind = GetBackgroundAllocKind(kind);
JSObject* obj = js_NewGCObject(cx, kind);
if (!obj)
@ -1656,8 +1649,7 @@ CopyInitializerObject(JSContext *cx, JSObject *baseobj, types::TypeObject *type)
JS_ASSERT(baseobj->getClass() == &js_ObjectClass);
JS_ASSERT(!baseobj->inDictionaryMode());
gc::FinalizeKind kind = gc::FinalizeKind(baseobj->finalizeKind());
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, baseobj->getAllocKind());
if (!obj || !obj->ensureSlots(cx, baseobj->numSlots()))
return NULL;

View File

@ -1421,7 +1421,7 @@ FixProxy(JSContext *cx, JSObject *proxy, JSBool *bp)
* Make a blank object from the recipe fix provided to us. This must have
* number of fixed slots as the proxy so that we can swap their contents.
*/
gc::FinalizeKind kind = gc::FinalizeKind(proxy->arenaHeader()->getThingKind());
gc::AllocKind kind = proxy->getAllocKind();
JSObject *newborn = NewNonFunction<WithProto::Given>(cx, clasp, proto, parent, kind);
if (!newborn)
return false;

View File

@ -68,7 +68,7 @@ js::Shape::freeTable(JSContext *cx)
inline js::EmptyShape *
js::types::TypeObject::getEmptyShape(JSContext *cx, js::Class *aclasp,
/* gc::FinalizeKind */ unsigned kind)
gc::AllocKind kind)
{
JS_ASSERT(!singleton);

View File

@ -629,8 +629,6 @@ struct JSScript : public js::gc::Cell {
inline bool hasAnalysis();
inline js::analyze::ScriptAnalysis *analysis();
inline bool isAboutToBeFinalized(JSContext *cx);
private:
bool makeTypes(JSContext *cx);
bool makeAnalysis(JSContext *cx);

View File

@ -1236,10 +1236,10 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
*/
Jump getNewObject(JSContext *cx, RegisterID result, JSObject *templateObject)
{
unsigned thingKind = templateObject->arenaHeader()->getThingKind();
gc::AllocKind allocKind = templateObject->getAllocKind();
JS_ASSERT(thingKind >= gc::FINALIZE_OBJECT0 && thingKind <= gc::FINALIZE_OBJECT_LAST);
size_t thingSize = gc::GCThingSizeMap[thingKind];
JS_ASSERT(allocKind >= gc::FINALIZE_OBJECT0 && allocKind <= gc::FINALIZE_OBJECT_LAST);
size_t thingSize = gc::Arena::thingSize(allocKind);
JS_ASSERT(cx->typeInferenceEnabled());
JS_ASSERT(!templateObject->hasSlotsArray());
@ -1253,7 +1253,8 @@ static const JSC::MacroAssembler::RegisterID JSParamReg_Argc = JSC::SparcRegist
* Inline FreeSpan::allocate. Only the case where the current freelist
* span is not empty is handled.
*/
gc::FreeSpan *list = &cx->compartment->freeLists.lists[thingKind];
gc::FreeSpan *list = const_cast<gc::FreeSpan *>
(cx->compartment->arenas.getFreeList(allocKind));
loadPtr(&list->first, result);
Jump jump = branchPtr(Assembler::BelowOrEqual, AbsoluteAddress(&list->last), result);

View File

@ -1350,7 +1350,7 @@ stubs::NewInitObject(VMFrame &f, JSObject *baseobj)
TypeObject *type = (TypeObject *) f.scratch;
if (!baseobj) {
gc::FinalizeKind kind = GuessObjectGCKind(0, false);
gc::AllocKind kind = GuessObjectGCKind(0, false);
JSObject *obj = NewBuiltinClassInstance(cx, &js_ObjectClass, kind);
if (!obj)
THROW();

View File

@ -5109,7 +5109,7 @@ env_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
ToString valstr(cx, *vp, JS_TRUE);
if (valstr.threw())
return JS_FALSE;
#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX
#if defined XP_WIN || defined HPUX || defined OSF1
{
char *waste = JS_smprintf("%s=%s", idstr.getBytes(), valstr.getBytes());
if (!waste) {

View File

@ -416,10 +416,10 @@ inline void
JSAtom::finalize(JSRuntime *rt)
{
JS_ASSERT(isAtom());
if (arenaHeader()->getThingKind() == js::gc::FINALIZE_STRING)
if (getAllocKind() == js::gc::FINALIZE_STRING)
asFlat().finalize(rt);
else
JS_ASSERT(arenaHeader()->getThingKind() == js::gc::FINALIZE_SHORT_STRING);
JS_ASSERT(getAllocKind() == js::gc::FINALIZE_SHORT_STRING);
}
inline void

View File

@ -1,4 +1,4 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=4 sw=4 et tw=79 ft=cpp:
*
* ***** BEGIN LICENSE BLOCK *****
@ -49,7 +49,7 @@ using namespace js;
bool
JSString::isShort() const
{
bool is_short = arenaHeader()->getThingKind() == gc::FINALIZE_SHORT_STRING;
bool is_short = (getAllocKind() == gc::FINALIZE_SHORT_STRING);
JS_ASSERT_IF(is_short, isFlat());
return is_short;
}
@ -69,7 +69,7 @@ JSString::isInline() const
bool
JSString::isExternal() const
{
bool is_external = arenaHeader()->getThingKind() == gc::FINALIZE_EXTERNAL_STRING;
bool is_external = (getAllocKind() == gc::FINALIZE_EXTERNAL_STRING);
JS_ASSERT_IF(is_external, isFixed());
return is_external;
}

View File

@ -879,8 +879,7 @@ env_setProperty(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
JSAutoByteString value(cx, valstr);
if (!value)
return JS_FALSE;
#if defined XP_WIN || defined HPUX || defined OSF1 || defined IRIX \
|| defined SCO
#if defined XP_WIN || defined HPUX || defined OSF1 || defined SCO
{
char *waste = JS_smprintf("%s=%s", name.ptr(), value.ptr());
if (!waste) {

View File

@ -1324,13 +1324,14 @@ ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
IterateData *data = static_cast<IterateData *>(vdata);
data->currCompartmentStats->gcHeapArenaHeaders +=
sizeof(js::gc::ArenaHeader);
size_t allocationSpace = arena->thingsSpan(thingSize);
data->currCompartmentStats->gcHeapArenaPadding +=
arena->thingsStartOffset(thingSize) - sizeof(js::gc::ArenaHeader);
js::gc::ArenaSize - allocationSpace - sizeof(js::gc::ArenaHeader);
// We don't call the callback on unused things. So we compute the
// unused space like this: arenaUnused = maxArenaUnused - arenaUsed.
// We do this by setting arenaUnused to maxArenaUnused here, and then
// subtracting thingSize for every used cell, in CellCallback().
data->currCompartmentStats->gcHeapArenaUnused += arena->thingsSpan(thingSize);
data->currCompartmentStats->gcHeapArenaUnused += allocationSpace;
}
void

View File

@ -49,7 +49,7 @@ skip-if(!(d2d||cocoaWidget)) random-if(d2d) != subpixel-glyphs-x-2a.html subpixe
== subpixel-glyphs-y-1a.html subpixel-glyphs-y-1b.html
== subpixel-lineheight-1a.html subpixel-lineheight-1b.html
== swash-1.html swash-1-ref.html
fails-if(Android) HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html
HTTP(..) != synthetic-bold-metrics-01.html synthetic-bold-metrics-01-notref.html
== variation-selector-unsupported-1.html variation-selector-unsupported-1-ref.html
== white-space-1a.html white-space-1-ref.html
== white-space-1b.html white-space-1-ref.html

View File

@ -217,6 +217,7 @@ pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCAL
/* preference for the locale picker */
pref("extensions.getLocales.get.url", "");
pref("extensions.compatability.locales.buildid", "0");
/* blocklist preferences */
pref("extensions.blocklist.enabled", true);

View File

@ -50,7 +50,7 @@ var AppMenu = {
item.onclick = function() { child.click(); }
let label = document.createElement("label");
label.setAttribute("value", child.label);
label.textContent = child.label;
item.appendChild(label);
if (item.classList.contains("appmenu-pageaction"))
@ -58,14 +58,8 @@ var AppMenu = {
else
listbox.appendChild(item);
}
this.popup.top = menuButton.getBoundingClientRect().bottom;
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
this.popup.setAttribute(chromeReg.isLocaleRTL("global") ? "left" : "right", this.offset);
this.popup.hidden = false;
this.popup.anchorTo(menuButton);
this.popup.anchorTo(menuButton, "after_end");
BrowserUI.lockToolbar();
BrowserUI.pushPopup(this, [this.popup, menuButton]);

View File

@ -19,20 +19,18 @@ var BookmarkPopup = {
show : function show() {
// Set the box position.
let button = document.getElementById("tool-star");
let anchorPosition = "";
if (getComputedStyle(button).visibility == "visible") {
let [tabsSidebar, controlsSidebar] = [Elements.tabs.getBoundingClientRect(), Elements.controls.getBoundingClientRect()];
this.box.setAttribute(tabsSidebar.left < controlsSidebar.left ? "right" : "left", controlsSidebar.width - this.box.offset);
this.box.top = button.getBoundingClientRect().top - this.box.offset;
} else {
button = document.getElementById("tool-star2");
this.box.top = button.getBoundingClientRect().bottom - this.box.offset;
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
this.box.setAttribute(chromeReg.isLocaleRTL("global") ? "left" : "right", this.box.offset);
anchorPosition = "after_start";
}
this.box.hidden = false;
this.box.anchorTo(button);
this.box.anchorTo(button, anchorPosition);
// include the star button here, so that click-to-dismiss works as expected
BrowserUI.pushPopup(this, [this.box, button]);

View File

@ -707,7 +707,6 @@
</property>
<method name="startEditing">
<parameter name="autoSelect"/>
<body>
<![CDATA[
if (!this.itemId || this.isReadOnly)
@ -727,8 +726,7 @@
this.updateFields();
this._nameField.focus();
if (autoSelect)
this._nameField.select();
this._nameField.select();
]]>
</body>
</method>

View File

@ -149,6 +149,7 @@
<field name="anchorNode">null</field>
<method name="anchorTo">
<parameter name="aAnchorNode"/>
<parameter name="aPosition"/>
<body>
<![CDATA[
if (!aAnchorNode) {
@ -159,13 +160,84 @@
this.anchorNode = aAnchorNode;
let anchorRect = aAnchorNode.getBoundingClientRect();
let popupRect = this.firstChild.getBoundingClientRect();
let popupRect = new Rect(0,0,0,0);
for (let i = 0; i < this.childNodes.length; i++) {
popupRect.expandToContain(Rect.fromRect(this.childNodes[i].getBoundingClientRect()));
}
let offset = this.offset;
let horizPos = 0;
let vertPos = 0;
let horizPos = (Math.round(popupRect.right) <= Math.round(anchorRect.left + offset)) ? -1 :
(Math.round(popupRect.left) >= Math.round(anchorRect.right - offset)) ? 1 : 0;
let vertPos = (Math.round(popupRect.bottom) <= Math.round(anchorRect.top + offset)) ? -1 :
(Math.round(popupRect.top) >= Math.round(anchorRect.bottom - offset)) ? 1 : 0;
if (aPosition) {
let chromeReg = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
let isRtl = chromeReg.isLocaleRTL("global");
let left = 0;
let top = 0;
switch (aPosition) {
case "before_start":
left = isRtl ? anchorRect.right - popupRect.width : anchorRect.left;
top = anchorRect.top + offset - popupRect.height;
vertPos = -1;
break;
case "before_end":
left = isRtl ? anchorRect.left : anchorRect.right - popupRect.width;
top = anchorRect.top + offset - popupRect.height;
vertPos = -1;
break;
case "after_start":
left = isRtl ? anchorRect.right - popupRect.width : anchorRect.left;
top = anchorRect.bottom - offset;
vertPos = 1;
break;
case "after_end":
left = isRtl ? anchorRect.left : anchorRect.right - popupRect.width;
top = anchorRect.bottom - offset;
vertPos = 1;
break;
case "start_before":
left = isRtl ? anchorRect.right : anchorRect.left - popupRect.width - offset;
top = anchorRect.top;
horizPos = -1;
break;
case "start_after":
left = isRtl ? anchorRect.right : anchorRect.left - popupRect.width - offset;
top = anchorRect.bottom - popupRect.height;
horizPos = -1;
break;
case "end_before":
left = isRtl ? anchorRect.left - popupRect.width - offset : anchorRect.right;
top = anchorRect.top;
horizPos = 1;
break;
case "end_after":
left = isRtl ? anchorRect.left - popupRect.width - offset : anchorRect.right;
top = anchorRect.bottom - popupRect.height;
horizPos = 1;
break;
case "overlap":
left = isRtl ? anchorRect.right - popupRect.width + offset : anchorRect.left + offset ;
top = anchorRect.top + offset ;
break;
}
if (top == 0) top = 1;
if (left == 0) left = 1;
if (left + popupRect.width > window.innerWidth)
left = window.innerWidth - popupRect.width;
else if (left < 0)
left = 1;
popupRect.left = left;
this.setAttribute("left", left);
popupRect.top = top;
this.setAttribute("top", top);
} else {
horizPos = (Math.round(popupRect.right) <= Math.round(anchorRect.left + offset)) ? -1 :
(Math.round(popupRect.left) >= Math.round(anchorRect.right - offset)) ? 1 : 0;
vertPos = (Math.round(popupRect.bottom) <= Math.round(anchorRect.top + offset)) ? -1 :
(Math.round(popupRect.top) >= Math.round(anchorRect.bottom - offset)) ? 1 : 0;
}
this._updateArrow(popupRect, anchorRect, horizPos, vertPos);
]]>

View File

@ -87,23 +87,12 @@ var BrowserSearch = {
popup.hidden = false;
popup.top = BrowserUI.toolbarH - popup.offset;
let searchButton = document.getElementById("tool-search");
if (Util.isTablet()) {
let width = list.getBoundingClientRect().width;
let searchButtonRect = searchButton.getBoundingClientRect();
let left = searchButtonRect.left;
if (Util.localeDir > 0) {
if (left + width > window.innerWidth)
left = window.innerWidth - width;
} else {
left = searchButtonRect.right - width;
if (left < 0)
left = 0;
}
popup.left = left;
} else if (popup.hasAttribute("left")) {
let anchorPosition = "";
if (Util.isTablet())
anchorPosition = "after_start";
else if (popup.hasAttribute("left"))
popup.removeAttribute("left");
}
popup.anchorTo(searchButton);
popup.anchorTo(searchButton, anchorPosition);
document.getElementById("urlbar-icons").setAttribute("open", "true");
BrowserUI.pushPopup(this, [popup, this._button]);

View File

@ -430,6 +430,10 @@ var ExtensionsView = {
} else if (aItem.getAttribute("type") == "theme") {
aItem.addon.userDisabled = true;
aItem.setAttribute("isDisabled", true);
} else if (aItem.getAttribute("type") == "locale") {
Services.prefs.clearUserPref("general.useragent.locale");
aItem.addon.userDisabled = true;
aItem.setAttribute("isDisabled", true);
} else {
aItem.addon.userDisabled = true;
opType = this._getOpTypeForOperations(aItem.addon.pendingOperations);

View File

@ -8,15 +8,16 @@ Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource:///modules/LocaleRepository.jsm");
let stringPrefs = [
{ selector: "#continue-in-button", pref: "continueIn", data: ["CURRENT_LANGUAGE"] },
{ selector: "#continue-in-button", pref: "continueIn", data: ["CURRENT_LOCALE"] },
{ selector: "#change-language", pref: "choose", data: null },
{ selector: "#picker-title", pref: "chooseLanguage", data: null },
{ selector: "#continue-button", pref: "continue", data: null },
{ selector: "#cancel-button", pref: "cancel", data: null },
{ selector: "#intalling-message", pref: "installing", data: ["CURRENT_LANGUAGE"] },
{ selector: "#intalling-message", pref: "installing", data: ["CURRENT_LOCALE"] },
{ selector: "#cancel-install-button", pref: "cancel", data: null },
{ selector: "#installing-error", pref: "installerror", data: null },
{ selector: "#install-continue", pref: "continue", data: null }
{ selector: "#install-continue", pref: "continue", data: null },
{ selector: "#loading-label", pref: "loading", data: null }
];
let LocaleUI = {
@ -52,6 +53,26 @@ let LocaleUI = {
return this._deck = document.getElementById("language-deck");
},
_availableLocales: null,
get availableLocales() {
if (!this._availableLocales) {
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
chrome.QueryInterface(Ci.nsIToolkitChromeRegistry);
let strings = Services.strings.createBundle("chrome://browser/content/languages.properties");
let availableLocales = chrome.getLocalesForPackage("browser");
this._availableLocales = [];
while (availableLocales.hasMore()) {
let locale = availableLocales.getNext();
let label = locale;
try { label = strings.GetStringFromName(locale); }
catch (e) { }
this._availableLocales.push({ addon: { id: locale, name: label, targetLocale: locale }});
}
}
return this._availableLocales;
},
_currentInstall: null, // used to cancel an install
get selectedPanel() {
@ -75,7 +96,7 @@ let LocaleUI = {
description.appendChild(document.createTextNode(aText));
description.setAttribute('flex', 1);
item.appendChild(description);
item.setAttribute("locale", getTargetLanguage(aLocale.addon));
item.setAttribute("locale", getTargetLocale(aLocale.addon));
if (aLocale) {
item.locale = aLocale.addon;
@ -94,12 +115,12 @@ let LocaleUI = {
let bestMatch = NO_MATCH;
for each (let locale in aLocales) {
let targetLang = getTargetLanguage(locale.addon);
if (document.querySelector('[locale="' + targetLang + '"]'))
let targetLocale = getTargetLocale(locale.addon);
if (document.querySelector('[locale="' + targetLocale + '"]'))
continue;
let item = this._createItem(targetLang, locale.addon.name, locale);
let match = localesMatch(targetLang, this.language);
let item = this._createItem(targetLocale, locale.addon.name, locale);
let match = localesMatch(targetLocale, this.locale);
if (match > bestMatch) {
bestMatch = match;
selectedItem = item;
@ -126,27 +147,27 @@ let LocaleUI = {
closePicker: function() {
if (this._currentInstall) {
Services.prefs.setBoolPref("intl.locale.matchOS", false);
Services.prefs.setCharPref("general.useragent.locale", getTargetLanguage(this._currentInstall));
Services.prefs.setCharPref("general.useragent.locale", getTargetLocale(this._currentInstall));
}
this.selectedPanel = this._mainPage;
},
_language: "",
_locale: "",
set language(aVal) {
if (aVal == this._language)
set locale(aVal) {
if (aVal == this._locale)
return;
Services.prefs.setBoolPref("intl.locale.matchOS", false);
Services.prefs.setCharPref("general.useragent.locale", aVal);
this._language = aVal;
this._locale = aVal;
this.strings = null;
this.updateStrings();
},
get language() {
return this._language;
get locale() {
return this._locale;
},
set installStatus(aVal) {
@ -158,13 +179,13 @@ let LocaleUI = {
this.selectedPanel = this._pickerPage;
},
selectLanguage: function(aEvent) {
selectLocale: function(aEvent) {
let locale = this.list.selectedItem.locale;
if (locale.install) {
LocaleUI.strings = new FakeStringBundle(locale);
this.updateStrings();
} else {
this.language = getTargetLanguage(locale);
this.locale = getTargetLocale(locale);
if (this._currentInstall)
this._currentInstall = null;
}
@ -187,12 +208,14 @@ let LocaleUI = {
if (this._currentInstall)
this._currentInstall = null;
// restore the last known "good" locale
this.language = this.defaultLanguage;
this.locale = this.defaultLocale;
this.updateStrings();
this.closePicker();
},
closeWindow : function() {
var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).platformBuildID;
Services.prefs.setCharPref("extensions.compatability.locales.buildid", buildID);
// Trying to close this window and open a new one results in a corrupt UI.
if (LocaleUI._currentInstall) {
// a new locale was installed, restart the browser
@ -202,7 +225,6 @@ let LocaleUI = {
if (cancelQuit.data == false) {
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eForceQuit);
Services.prefs.setBoolPref("browser.sessionstore.resume_session_once", false);
}
} else {
// selected locale is already installed, just open the window
@ -223,7 +245,7 @@ let LocaleUI = {
catch(ex) { }
LocaleUI._currentInstall = null;
this.language = this.defaultLanguage;
this.locale = this.defaultLocale;
}
},
@ -241,10 +263,10 @@ let LocaleUI = {
}
}
// Gets the target language for a locale addon
// Gets the target locale for an addon
// For now this returns the targetLocale, although if and addon doesn't
// specify a targetLocale we could attempt to guess the locale from the addon's name
function getTargetLanguage(aAddon) {
function getTargetLocale(aAddon) {
return aAddon.targetLocale;
}
@ -256,7 +278,7 @@ function getString(aStringName, aDataSet, aAddon) {
if (aDataSet) {
let databundle = aDataSet.map(function(aData) {
switch (aData) {
case "CURRENT_LANGUAGE" :
case "CURRENT_LOCALE" :
if (aAddon)
return aAddon.name;
try { return LocaleUI.strings.GetStringFromName("name"); }
@ -289,8 +311,8 @@ let installListener = {
},
onInstallStarted: function(install) { },
onInstallEnded: function(install, addon) {
LocaleUI.updateStrings();
LocaleUI.closePicker();
LocaleUI.locale = getTargetLocale(LocaleUI._currentInstall);
LocaleUI.closeWindow();
},
onInstallCancelled: function(install) {
LocaleUI.cancelInstall();
@ -322,25 +344,68 @@ function start() {
// if we have gotten this far, we can assume that we don't have anything matching the system
// locale and we should show the locale picker
LocaleUI._mainPage.setAttribute("mode", "loading");
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
chrome.QueryInterface(Ci.nsIToolkitChromeRegistry);
let availableLocales = chrome.getLocalesForPackage("browser");
let strings = Services.strings.createBundle("chrome://browser/content/languages.properties");
LocaleUI.availableLocales = [];
while (availableLocales.hasMore()) {
let locale = availableLocales.getNext();
let label = locale;
try { label = strings.GetStringFromName(locale); }
catch (e) { }
LocaleUI.availableLocales.push({addon: { id: locale, name: label, targetLocale: locale }});
}
LocaleUI._language = chrome.getSelectedLocale("browser");
LocaleUI._locale = chrome.getSelectedLocale("browser");
LocaleUI.updateStrings();
// if we haven't gotten the list of available locales from AMO within 5 seconds, we give up
// users can try downloading the list again by selecting "Choose another locale"
let timeout = setTimeout(function() {
LocaleUI._mainPage.removeAttribute("mode");
timeout = null;
}, 5000);
// Look on AMO for something that matches the system locale
LocaleRepository.getLocales(function lp_initalDownload(aLocales) {
if (!LocaleUI._mainPage.hasAttribute("mode")) return;
clearTimeout(timeout);
LocaleUI._mainPage.removeAttribute("mode");
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
let currentLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE");
if (Services.prefs.prefHasUserValue("general.useragent.locale")) {
currentLocale = Services.prefs.getCharPref("general.useragent.locale");
}
let match = NO_MATCH;
let matchingLocale = null;
for each (let locale in aLocales) {
let targetLocale = getTargetLocale(locale.addon);
let newMatch = localesMatch(targetLocale, currentLocale);
if (newMatch > match) {
matchingLocale = locale;
match = newMatch;
}
}
if (matchingLocale) {
// if we found something, try to install it automatically
AddonManager.getAddonByID(matchingLocale.addon.id, function (aAddon) {
// if this locale is already installed, but is user disabled,
// bail out of here.
if (aAddon && aAddon.userDisabled) {
Services.prefs.clearUserPref("general.useragent.locale");
LocaleUI.closeWindow();
return;
}
// if we found something, try to install it automatically
LocaleUI.strings = new FakeStringBundle(matchingLocale.addon);
LocaleUI.updateStrings();
LocaleUI._currentInstall = matchingLocale.addon;
LocaleUI.selectedPanel = LocaleUI._installerPage;
matchingLocale.addon.install.addListener(installListener);
matchingLocale.addon.install.install();
});
}
});
// update the page strings and show the correct page
LocaleUI.defaultLanguage = LocaleUI._language;
LocaleUI.defaultLocale = LocaleUI._locale;
window.addEventListener("resize", resizeHandler, false);
}

View File

@ -15,12 +15,13 @@
<vbox id="main-page" class="pane" flex="1">
<spacer flex="1"/>
<button class="continue" id="continue-in-button" onclick="LocaleUI.closeWindow();" crop="center"/>
<label class="loadingLabel" id="loading-label"/>
<description id="change-language" class="link" onclick="LocaleUI.showPicker();" role="button"/>
</vbox>
<vbox id="picker-page" class="pane" flex="1">
<description id="picker-title"/>
<richlistbox id="language-list" onclick="LocaleUI.selectLanguage(event);" flex="1" class="window-width"/>
<richlistbox id="language-list" onclick="LocaleUI.selectLocale(event);" flex="1" class="window-width"/>
<hbox class="footer">
<button id="cancel-button" class="cancel" onclick="LocaleUI.cancelPicker();" crop="center"/>
<button id="continue-button" class="continue" onclick="LocaleUI.installAddon();" crop="center"/>

View File

@ -103,6 +103,7 @@ var PreferencesView = {
this._loadHomePage();
MasterPasswordUI.updatePreference();
WeaveGlue.init();
},
_loadLocales: function _loadLocales() {

View File

@ -39,8 +39,12 @@
let WeaveGlue = {
setupData: null,
jpake: null,
_bundle: null,
init: function init() {
if (this._bundle)
return;
this._bundle = Services.strings.createBundle("chrome://browser/locale/sync.properties");
this._msg = document.getElementById("prefs-messages");

View File

@ -119,18 +119,36 @@ function showPanelWhenReady(aWindow, aPage) {
}
function haveSystemLocale() {
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE");
return isLocaleAvailable(systemLocale);
}
function checkCurrentLocale() {
if (Services.prefs.prefHasUserValue("general.useragent.locale")) {
// if the user has a compatable locale from a different buildid, we need to update
var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).appBuildID;
let localeBuildID = Services.prefs.getCharPref("extensions.compatability.locales.buildid");
if (buildID != localeBuildID)
return false;
let currentLocale = Services.prefs.getCharPref("general.useragent.locale");
return isLocaleAvailable(currentLocale);
}
return true;
}
function isLocaleAvailable(aLocale) {
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
chrome.QueryInterface(Ci.nsIToolkitChromeRegistry);
let availableLocales = chrome.getLocalesForPackage("browser");
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE");
systemLocale = systemLocale.split("-")[0];
let systemLocaleRegEx = new RegExp("^" + systemLocale);
let locale = aLocale.split("-")[0];
let localeRegEx = new RegExp("^" + locale);
while (availableLocales.hasMore()) {
let locale = availableLocales.getNext();
if (systemLocaleRegEx.test(locale))
if (localeRegEx.test(locale))
return true;
}
return false;
@ -227,9 +245,9 @@ BrowserCLH.prototype = {
uris = uris.slice(1);
}
// Show the locale selector if we have a new profile
if (needHomepageOverride() == "new profile" && Services.prefs.getBoolPref("browser.firstrun.show.localepicker") && !haveSystemLocale()) {
// Show the locale selector if we have a new profile, or if the selected locale is no longer compatible
let showLocalePicker = Services.prefs.getBoolPref("browser.firstrun.show.localepicker")
if ((needHomepageOverride() == "new profile" && showLocalePicker && !haveSystemLocale()) || !checkCurrentLocale()) {
browserWin = openWindow(null, "chrome://browser/content/localePicker.xul", "_blank", "chrome,dialog=no,all", defaultURL);
aCmdLine.preventDefault = true;
return;

View File

@ -238,6 +238,9 @@ UpdatePrompt.prototype = {
aLocale.addon.install.install();
}
}, this);
// store the buildid of these locales so that we can disable locales when the
// user updates through a non-updater channel
Services.prefs.setCharPref("extensions.compatability.locales.buildid", aUpdate.buildID);
}).bind(this), { buildID: aUpdate.buildID });
},

View File

@ -10,3 +10,4 @@ cancel=Cancel
continue=Continue
installing=Installing %S
installerror=Error installing language
loading=Loading…

View File

@ -50,6 +50,12 @@
background-position: center center;
}
#main-page:not([mode="loading"]) #loading-label,
#main-page[mode] #continue-in-button,
#main-page[mode] #change-language {
visibility: hidden;
}
#picker-title {
font-weight: bold;
font-size: @font_normal@;

View File

@ -43,6 +43,7 @@
-moz-appearance: none;
-moz-box-align: center;
padding: 0;
background: @color_toolbar_background@;
border: none;
min-height: @touch_button_xlarge@;
}
@ -199,6 +200,7 @@ toolbarbutton.urlbar-button {
#urlbar-edit,
#urlbar-title {
background: @color_toolbar_background@;
padding: @padding_xxxnormal@ 0px @padding_xsmall@ 0px;
margin: 0px !important;
min-height: @urlbar_edit_height@ !important;
@ -311,7 +313,7 @@ toolbarbutton.urlbar-button {
padding: 0;
-moz-border-start: @border_width_large@ solid #262629;
min-width: @sidebar_width_minimum@ !important;
background: @color_background_default@;
background: @color_toolbar_background@;
}
.button-control {
@ -953,7 +955,7 @@ autocompleteresult.noresults > .autocomplete-item-container {
/* Left sidebar (tabs) ---------------------------------------------------- */
#tabs-container {
-moz-border-end: @border_width_large@ solid #262629;
background: @color_background_default@;
background: @color_toolbar_background@;
}
#tabs:-moz-locale-dir(rtl) {

View File

@ -5,6 +5,7 @@
%define color_background_default_window #fff
%define color_background_default rgba(255,255,255,0.95)
%define color_text_default #222222
%define color_toolbar_background #eaeaea
%define color_divider_border #333333
%define color_button_border rgb(207,207,207)
%define color_background_dialog #fff

View File

@ -570,6 +570,10 @@ arrowbox {
border: none;
}
.panel-arrow {
min-height: 18px;
}
.arrowbox-dark .panel-arrowcontent {
padding: @padding_normal@; /* core spacing */
}

View File

@ -50,6 +50,12 @@
background-position: center center;
}
#main-page:not([mode="loading"]) #loading-label,
#main-page[mode] #continue-in-button,
#main-page[mode] #change-language {
visibility: hidden;
}
#picker-title {
font-weight: bold;
font-size: @font_normal@;

View File

@ -90,7 +90,11 @@ NS_IMETHODIMP_(nsrefcnt) HttpChannelChild::Release()
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "HttpChannelChild");
if (mRefCnt == 1 && mKeptAlive && mIPCOpen) {
// Normally we Send_delete in OnStopRequest, but when we need to retain the
// remote channel for security info IPDL itself holds 1 reference, so we
// Send_delete when refCnt==1.
if (mKeptAlive && mRefCnt == 1) {
NS_ASSERTION(mIPCOpen, "mIPCOpen false!");
mKeptAlive = false;
// Send_delete calls NeckoChild::DeallocPHttpChannel, which will release
// again to refcount==0
@ -486,15 +490,14 @@ HttpChannelChild::OnStopRequest(const nsresult& statusCode)
mLoadGroup->RemoveRequest(this, nsnull, mStatus);
}
if (!(mLoadFlags & LOAD_DOCUMENT_URI)) {
if (mLoadFlags & LOAD_DOCUMENT_URI) {
// Keep IPDL channel open, but only for updating security info.
mKeptAlive = true;
SendDocumentChannelCleanup();
} else {
// This calls NeckoChild::DeallocPHttpChannel(), which deletes |this| if IPDL
// holds the last reference. Don't rely on |this| existing after here.
PHttpChannelChild::Send__delete__(this);
} else {
// We need to keep the document loading channel alive for further
// communication, mainly for collecting a security state values.
mKeptAlive = true;
SendDocumentChannelCleanup();
}
}
@ -923,7 +926,7 @@ HttpChannelChild::Cancel(nsresult status)
// is responsible for cleaning up.
mCanceled = true;
mStatus = status;
if (mIPCOpen)
if (RemoteChannelExists())
SendCancel(status);
}
return NS_OK;
@ -932,7 +935,7 @@ HttpChannelChild::Cancel(nsresult status)
NS_IMETHODIMP
HttpChannelChild::Suspend()
{
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
if (!mSuspendCount++) {
SendSuspend();
mEventQ.Suspend();
@ -956,7 +959,7 @@ HttpChannelChild::CompleteResume()
NS_IMETHODIMP
HttpChannelChild::Resume()
{
NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(RemoteChannelExists(), NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
nsresult rv = NS_OK;
@ -1169,7 +1172,7 @@ HttpChannelChild::GetCacheTokenCachedCharset(nsACString &_retval)
NS_IMETHODIMP
HttpChannelChild::SetCacheTokenCachedCharset(const nsACString &aCharset)
{
if (!mCacheEntryAvailable || !mIPCOpen)
if (!mCacheEntryAvailable || !RemoteChannelExists())
return NS_ERROR_NOT_AVAILABLE;
mCachedCharset = aCharset;
@ -1216,7 +1219,7 @@ HttpChannelChild::SetPriority(PRInt32 aPriority)
if (mPriority == newValue)
return NS_OK;
mPriority = newValue;
if (mIPCOpen)
if (RemoteChannelExists())
SendSetPriority(mPriority);
return NS_OK;
}

View File

@ -170,9 +170,12 @@ private:
bool mSendResumeAt;
bool mIPCOpen;
bool mKeptAlive;
bool mKeptAlive; // IPC kept open, but only for security info
ChannelEventQueue mEventQ;
// true after successful AsyncOpen until OnStopRequest completes.
bool RemoteChannelExists() { return mIPCOpen && !mKeptAlive; }
void AssociateApplicationCache(const nsCString &groupID,
const nsCString &clientID);
void OnStartRequest(const nsHttpResponseHead& responseHead,

View File

@ -85,7 +85,8 @@ void
HttpChannelParent::ActorDestroy(ActorDestroyReason why)
{
// We may still have refcount>0 if nsHttpChannel hasn't called OnStopRequest
// yet, but we must not send any more msgs to child.
// yet, but child process has crashed. We must not try to send any more msgs
// to child, or IPDL will kill chrome process, too.
mIPCClosed = true;
}
@ -317,20 +318,12 @@ HttpChannelParent::RecvUpdateAssociatedContentSecurity(const PRInt32& high,
const PRInt32& broken,
const PRInt32& no)
{
nsHttpChannel *chan = static_cast<nsHttpChannel *>(mChannel.get());
nsCOMPtr<nsISupports> secInfo;
chan->GetSecurityInfo(getter_AddRefs(secInfo));
nsCOMPtr<nsIAssociatedContentSecurity> assoc = do_QueryInterface(secInfo);
if (!assoc)
return true;
assoc->SetCountSubRequestsHighSecurity(high);
assoc->SetCountSubRequestsLowSecurity(low);
assoc->SetCountSubRequestsBrokenSecurity(broken);
assoc->SetCountSubRequestsNoSecurity(no);
if (mAssociatedContentSecurity) {
mAssociatedContentSecurity->SetCountSubRequestsHighSecurity(high);
mAssociatedContentSecurity->SetCountSubRequestsLowSecurity(low);
mAssociatedContentSecurity->SetCountSubRequestsBrokenSecurity(broken);
mAssociatedContentSecurity->SetCountSubRequestsNoSecurity(no);
}
return true;
}
@ -359,10 +352,9 @@ HttpChannelParent::RecvRedirect2Verify(const nsresult& result,
bool
HttpChannelParent::RecvDocumentChannelCleanup()
{
// We must clear the cache entry here, else we'll block other channels from
// reading it if we've got it open for writing.
mCacheDescriptor = 0;
// From now on only using mAssociatedContentSecurity. Free everything else.
mChannel = 0; // Reclaim some memory sooner.
mCacheDescriptor = 0; // Else we'll block other channels reading same URI
return true;
}
@ -421,6 +413,7 @@ HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
nsCOMPtr<nsISupports> secInfoSupp;
chan->GetSecurityInfo(getter_AddRefs(secInfoSupp));
if (secInfoSupp) {
mAssociatedContentSecurity = do_QueryInterface(secInfoSupp);
nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
if (secInfoSer)
NS_SerializeToString(secInfoSer, secInfoSerialization);

View File

@ -53,6 +53,7 @@
using namespace mozilla::dom;
class nsICacheEntryDescriptor;
class nsIAssociatedContentSecurity;
namespace mozilla {
namespace net {
@ -120,8 +121,9 @@ protected:
nsCOMPtr<nsITabParent> mTabParent;
private:
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsICacheEntryDescriptor> mCacheDescriptor;
nsCOMPtr<nsIChannel> mChannel;
nsCOMPtr<nsICacheEntryDescriptor> mCacheDescriptor;
nsCOMPtr<nsIAssociatedContentSecurity> mAssociatedContentSecurity;
bool mIPCClosed; // PHttpChannel actor has been Closed()
nsCOMPtr<nsIChannel> mRedirectChannel;

View File

@ -49,8 +49,7 @@
#if defined(__linux)
// Didn't find gettdtablehi() or gettdtablesize() on linux. Using FD_SETSIZE
#define getdtablehi() FD_SETSIZE
#elif !defined(__irix)
// looks like Irix is the only one that has getdtablehi()?
#else
#define getdtablehi() getdtablesize()
// If you find a system doesn't have getdtablesize try #define getdtablesize

View File

@ -1,149 +0,0 @@
#include <sys/regdef.h>
#include <sys/asm.h>
.text
.globl invoke_count_words
.globl invoke_copy_to_stack
LOCALSZ=7 # a0, a1, a2, a3, s0, ra, gp
FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
RAOFF=FRAMESZ-(1*SZREG)
A0OFF=FRAMESZ-(2*SZREG)
A1OFF=FRAMESZ-(3*SZREG)
A2OFF=FRAMESZ-(4*SZREG)
A3OFF=FRAMESZ-(5*SZREG)
S0OFF=FRAMESZ-(6*SZREG)
GPOFF=FRAMESZ-(7*SZREG)
#
# _XPTC_InvokeByIndex(that, methodIndex, paramCount, params)
# a0 a1 a2 a3
NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra)
SETUP_GP
PTR_SUBU sp, FRAMESZ
SETUP_GP64(GPOFF, _XPTC_InvokeByIndex)
SAVE_GP(GPOFF)
REG_S ra, RAOFF(sp)
REG_S a0, A0OFF(sp)
REG_S a1, A1OFF(sp)
REG_S a2, A2OFF(sp)
REG_S a3, A3OFF(sp)
REG_S s0, S0OFF(sp)
REG_S gp, GPOFF(sp)
# invoke_count_words(paramCount, params)
move a0, a2
move a1, a3
jal invoke_count_words
# invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount,
# nsXPTCVariant* s, PRUint32 *reg)
REG_L a1, A2OFF(sp) # a1 - paramCount
REG_L a2, A3OFF(sp) # a2 - params
# save sp before we copy the params to the stack
move t0, sp
# assume full size of 8 bytes per param to be safe
sll v0, 4 # 8 bytes * num params
subu sp, sp, v0 # make room
move a0, sp # a0 - param stack address
# create temporary stack space to write int and fp regs
subu sp, 64 # 64 = 8 regs of 8 bytes
move a3, sp
# save the old sp and save the arg stack
subu sp, sp, 16
REG_S t0, 0(sp)
REG_S a0, 8(sp)
# copy the param into the stack areas
jal invoke_copy_to_stack
REG_L t3, 8(sp) # get previous a0
REG_L sp, 0(sp) # get orig sp back
REG_L a0, A0OFF(sp) # a0 - that
REG_L a1, A1OFF(sp) # a1 - methodIndex
#ifdef __GNUC__
# t1 = methodIndex * 8
# (use shift instead of mult)
sll t1, a1, 3
#else
# t1 = methodIndex * 12
# (use shift and subtract trick instead of mult)
sll t1, a1, 2
subu t1, t1, a1
sll t1, t1, 2
#endif
# calculate the function we need to jump to,
# which must then be saved in t9
lw t9, 0(a0)
addu t9, t9, t1
#ifdef __GNUC__
lw t9, 12(t9) # t9 = *(that+t1+12)
#else
li t2, 20
addu t9, t9, t2
lw t9, 0(t9) # t9 = *(that+t1+20)
#endif
# calculate the proper "this" pointer for the
# function that they asked for
lw t0, 0(a0)
addu t0, t1
#ifdef __GNUC__
lh t0, 8(t0)
#else
lw t0, 12(t0)
#endif
addu a0, a0, t0
# get register save area from invoke_copy_to_stack
subu t1, t3, 64
# a1..a7 and f13..f19 should now be set to what
# invoke_copy_to_stack told us. skip a0 and f12
# because that's the "this" pointer
REG_L a1, 0(t1)
REG_L a2, 8(t1)
REG_L a3, 16(t1)
REG_L a4, 24(t1)
REG_L a5, 32(t1)
REG_L a6, 40(t1)
REG_L a7, 48(t1)
l.d $f13, 0(t1)
l.d $f14, 8(t1)
l.d $f15, 16(t1)
l.d $f16, 24(t1)
l.d $f17, 32(t1)
l.d $f18, 40(t1)
l.d $f19, 48(t1)
# save away our stack pointer and create
# the stack pointer for the function
move s0, sp
move sp, t3
jalr ra, t9
move sp, s0
RESTORE_GP64
REG_L ra, RAOFF(sp)
REG_L s0, S0OFF(sp)
PTR_ADDU sp, FRAMESZ
j ra
.end _XPTC_InvokeByIndex

View File

@ -1,173 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* Platform specific code to invoke XPCOM methods on native objects */
#include "xptcprivate.h"
#if (_MIPS_SIM != _ABIN32)
#error "This code is for IRIX N32 only"
#endif
extern "C" uint32
invoke_count_words(PRUint32 paramCount, nsXPTCVariant* s)
{
return(paramCount*2);
}
extern "C" void
invoke_copy_to_stack(PRUint64* d, PRUint32 paramCount,
nsXPTCVariant* s, PRUint64 *regs)
{
#define N_ARG_REGS 7 /* 8 regs minus 1 for "this" ptr */
for (PRUint32 i = 0; i < paramCount; i++, s++)
{
if (s->IsPtrData()) {
if (i < N_ARG_REGS)
regs[i] = (PRUint64)s->ptr;
else
*d++ = (PRUint64)s->ptr;
continue;
}
switch (s->type) {
//
// signed types first
//
case nsXPTType::T_I8:
if (i < N_ARG_REGS)
((PRInt64*)regs)[i] = s->val.i8;
else
*d++ = s->val.i8;
break;
case nsXPTType::T_I16:
if (i < N_ARG_REGS)
((PRInt64*)regs)[i] = s->val.i16;
else
*d++ = s->val.i16;
break;
case nsXPTType::T_I32:
if (i < N_ARG_REGS)
((PRInt64*)regs)[i] = s->val.i32;
else
*d++ = s->val.i32;
break;
case nsXPTType::T_I64:
if (i < N_ARG_REGS)
((PRInt64*)regs)[i] = s->val.i64;
else
*d++ = s->val.i64;
break;
//
// unsigned types next
//
case nsXPTType::T_U8:
if (i < N_ARG_REGS)
regs[i] = s->val.u8;
else
*d++ = s->val.u8;
break;
case nsXPTType::T_U16:
if (i < N_ARG_REGS)
regs[i] = s->val.u16;
else
*d++ = s->val.u16;
break;
case nsXPTType::T_U32:
if (i < N_ARG_REGS)
regs[i] = s->val.u32;
else
*d++ = s->val.u32;
break;
case nsXPTType::T_U64:
if (i < N_ARG_REGS)
regs[i] = s->val.u64;
else
*d++ = s->val.u64;
break;
case nsXPTType::T_FLOAT:
if (i < N_ARG_REGS)
// Place a float in least significant bytes.
*(float*)(((char*)&regs[i+1]) - sizeof(float)) = s->val.f;
else
*(float*)d++ = s->val.f;
break;
case nsXPTType::T_DOUBLE:
if (i < N_ARG_REGS)
*(double*)&regs[i] = s->val.d;
else
*(double*)d++ = s->val.d;
break;
case nsXPTType::T_BOOL:
if (i < N_ARG_REGS)
regs[i] = s->val.b;
else
*d++ = s->val.b;
break;
case nsXPTType::T_CHAR:
if (i < N_ARG_REGS)
regs[i] = s->val.c;
else
*d++ = s->val.c;
break;
case nsXPTType::T_WCHAR:
if (i < N_ARG_REGS)
regs[i] = s->val.wc;
else
*d++ = s->val.wc;
break;
default:
// all the others are plain pointer types
if (i < N_ARG_REGS)
regs[i] = (PRUint64)s->val.p;
else
*d++ = (PRUint64)s->val.p;
break;
}
}
}
extern "C" nsresult _XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
PRUint32 paramCount, nsXPTCVariant* params);
extern "C"
XPTC_PUBLIC_API(nsresult)
XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
PRUint32 paramCount, nsXPTCVariant* params)
{
return _XPTC_InvokeByIndex(that, methodIndex, paramCount, params);
}

View File

@ -1,97 +0,0 @@
#include <sys/regdef.h>
#include <sys/asm.h>
.text
.globl PrepareAndDispatch
LOCALSZ=16
FRAMESZ=(((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
A1OFF=FRAMESZ-(9*SZREG)
A2OFF=FRAMESZ-(8*SZREG)
A3OFF=FRAMESZ-(7*SZREG)
A4OFF=FRAMESZ-(6*SZREG)
A5OFF=FRAMESZ-(5*SZREG)
A6OFF=FRAMESZ-(4*SZREG)
A7OFF=FRAMESZ-(3*SZREG)
GPOFF=FRAMESZ-(2*SZREG)
RAOFF=FRAMESZ-(1*SZREG)
F13OFF=FRAMESZ-(16*SZREG)
F14OFF=FRAMESZ-(15*SZREG)
F15OFF=FRAMESZ-(14*SZREG)
F16OFF=FRAMESZ-(13*SZREG)
F17OFF=FRAMESZ-(12*SZREG)
F18OFF=FRAMESZ-(11*SZREG)
F19OFF=FRAMESZ-(10*SZREG)
#define SENTINEL_ENTRY(nn) /* defined in cpp file, not here */
#ifdef __GNUC__
#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBase)
#else
#define STUB_ENTRY(nn) MAKE_STUB(nn, Stub/**/nn/**/__14nsXPTCStubBaseGv)
#endif
#define MAKE_STUB(nn, name) \
NESTED(name, FRAMESZ, ra); \
SETUP_GP; \
PTR_SUBU sp, FRAMESZ; \
SETUP_GP64(GPOFF, name); \
SAVE_GP(GPOFF); \
li t0, nn; \
b sharedstub; \
.end name; \
#include "xptcstubsdef.inc"
.globl sharedstub
.ent sharedstub
sharedstub:
REG_S a1, A1OFF(sp)
REG_S a2, A2OFF(sp)
REG_S a3, A3OFF(sp)
REG_S a4, A4OFF(sp)
REG_S a5, A5OFF(sp)
REG_S a6, A6OFF(sp)
REG_S a7, A7OFF(sp)
REG_S ra, RAOFF(sp)
s.d $f13, F13OFF(sp)
s.d $f14, F14OFF(sp)
s.d $f15, F15OFF(sp)
s.d $f16, F16OFF(sp)
s.d $f17, F17OFF(sp)
s.d $f18, F18OFF(sp)
s.d $f19, F19OFF(sp)
# t0 is methodIndex
move a1, t0
# a2 is stack address where extra function params
# are stored that do not fit in registers
move a2, sp
addi a2, FRAMESZ
# a3 is stack address of a1..a7
move a3, sp
addi a3, A1OFF
# a4 is stack address of f13..f19
move a4, sp
addi a4, F13OFF
# PrepareAndDispatch(that, methodIndex, args, gprArgs, fpArgs)
# a0 a1 a2 a3 a4
#
jal PrepareAndDispatch
REG_L ra, RAOFF(sp)
REG_L gp, GPOFF(sp)
PTR_ADDU sp, FRAMESZ
j ra
.end sharedstub

View File

@ -1,226 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "xptcprivate.h"
#if defined(IRIX)
#if (_MIPS_SIM != _ABIN32)
#error "This code is for IRIX N32 only"
#endif
/*
* This is for IRIX N32 ABI
*
* When we're called, the "gp" registers are stored in gprData and
* the "fp" registers are stored in fprData. There are 8 regs
* available which coorespond to the first 7 parameters of the
* function and the "this" pointer. If there are additional parms,
* they are stored on the stack at address "args".
*
*/
extern "C" nsresult
PrepareAndDispatch(nsXPTCStubBase* self, PRUint32 methodIndex, PRUint64* args,
PRUint64 *gprData, double *fprData)
{
#define PARAM_BUFFER_COUNT 16
#define PARAM_GPR_COUNT 7
#define PARAM_FPR_COUNT 7
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = NULL;
nsIInterfaceInfo* iface_info = NULL;
const nsXPTMethodInfo* info;
PRUint8 paramCount;
PRUint8 i;
nsresult result = NS_ERROR_FAILURE;
NS_ASSERTION(self,"no self");
self->GetInterfaceInfo(&iface_info);
NS_ASSERTION(iface_info,"no interface info");
iface_info->GetMethodInfo(PRUint16(methodIndex), &info);
NS_ASSERTION(info,"no interface info");
paramCount = info->GetParamCount();
// setup variant array pointer
if(paramCount > PARAM_BUFFER_COUNT)
dispatchParams = new nsXPTCMiniVariant[paramCount];
else
dispatchParams = paramBuffer;
NS_ASSERTION(dispatchParams,"no place for params");
PRUint64* ap = args;
PRUint32 iCount = 0;
for(i = 0; i < paramCount; i++)
{
const nsXPTParamInfo& param = info->GetParam(i);
const nsXPTType& type = param.GetType();
nsXPTCMiniVariant* dp = &dispatchParams[i];
if(param.IsOut() || !type.IsArithmetic())
{
if (iCount < PARAM_GPR_COUNT)
dp->val.p = (void*)gprData[iCount++];
else
dp->val.p = (void*)*ap++;
continue;
}
// else
switch(type)
{
case nsXPTType::T_I8:
if (iCount < PARAM_GPR_COUNT)
dp->val.i8 = (PRInt8)gprData[iCount++];
else
dp->val.i8 = (PRInt8)*ap++;
break;
case nsXPTType::T_I16:
if (iCount < PARAM_GPR_COUNT)
dp->val.i16 = (PRInt16)gprData[iCount++];
else
dp->val.i16 = (PRInt16)*ap++;
break;
case nsXPTType::T_I32:
if (iCount < PARAM_GPR_COUNT)
dp->val.i32 = (PRInt32)gprData[iCount++];
else
dp->val.i32 = (PRInt32)*ap++;
break;
case nsXPTType::T_I64:
if (iCount < PARAM_GPR_COUNT)
dp->val.i64 = (PRInt64)gprData[iCount++];
else
dp->val.i64 = (PRInt64)*ap++;
break;
case nsXPTType::T_U8:
if (iCount < PARAM_GPR_COUNT)
dp->val.u8 = (PRUint8)gprData[iCount++];
else
dp->val.u8 = (PRUint8)*ap++;
break;
case nsXPTType::T_U16:
if (iCount < PARAM_GPR_COUNT)
dp->val.u16 = (PRUint16)gprData[iCount++];
else
dp->val.u16 = (PRUint16)*ap++;
break;
case nsXPTType::T_U32:
if (iCount < PARAM_GPR_COUNT)
dp->val.u32 = (PRUint32)gprData[iCount++];
else
dp->val.u32 = (PRUint32)*ap++;
break;
case nsXPTType::T_U64:
if (iCount < PARAM_GPR_COUNT)
dp->val.u64 = (PRUint64)gprData[iCount++];
else
dp->val.u64 = (PRUint64)*ap++;
break;
case nsXPTType::T_FLOAT:
if (iCount < PARAM_FPR_COUNT)
dp->val.f = (double)fprData[iCount++];
else
dp->val.f = *((double*)ap++);
break;
case nsXPTType::T_DOUBLE:
if (iCount < PARAM_FPR_COUNT)
dp->val.d = (double)fprData[iCount++];
else
dp->val.d = *((double*)ap++);
break;
case nsXPTType::T_BOOL:
if (iCount < PARAM_GPR_COUNT)
dp->val.b = (PRBool)gprData[iCount++];
else
dp->val.b = (PRBool)*ap++;
break;
case nsXPTType::T_CHAR:
if (iCount < PARAM_GPR_COUNT)
dp->val.c = (char)gprData[iCount++];
else
dp->val.c = (char)*ap++;
break;
case nsXPTType::T_WCHAR:
if (iCount < PARAM_GPR_COUNT)
dp->val.wc = (wchar_t)gprData[iCount++];
else
dp->val.wc = (wchar_t)*ap++;
break;
default:
NS_ERROR("bad type");
break;
}
}
result = self->CallMethod((PRUint16)methodIndex, info, dispatchParams);
NS_RELEASE(iface_info);
if(dispatchParams != paramBuffer)
delete [] dispatchParams;
return result;
}
#define STUB_ENTRY(n) /* defined in the assembly file */
#define SENTINEL_ENTRY(n) \
nsresult nsXPTCStubBase::Sentinel##n() \
{ \
NS_ERROR("nsXPTCStubBase::Sentinel called"); \
return NS_ERROR_NOT_IMPLEMENTED; \
}
#include "xptcstubsdef.inc"
#endif