mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Merge last green changeset from mozilla-inbound to mozilla-central
This commit is contained in:
commit
913f8215a0
@ -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"],
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -55,6 +55,7 @@ _TEST_FILES = \
|
||||
test_location.html \
|
||||
test_innerWidthHeight_script.html \
|
||||
innerWidthHeight_script.html \
|
||||
test_location_setters.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_TEST_FILES)
|
||||
|
78
dom/tests/mochitest/dom-level0/test_location_setters.html
Normal file
78
dom/tests/mochitest/dom-level0/test_location_setters.html
Normal 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>
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
889
js/src/jsgc.cpp
889
js/src/jsgc.cpp
File diff suppressed because it is too large
Load Diff
447
js/src/jsgc.h
447
js/src/jsgc.h
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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]);
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
]]>
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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"/>
|
||||
|
@ -103,6 +103,7 @@ var PreferencesView = {
|
||||
this._loadHomePage();
|
||||
|
||||
MasterPasswordUI.updatePreference();
|
||||
WeaveGlue.init();
|
||||
},
|
||||
|
||||
_loadLocales: function _loadLocales() {
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 });
|
||||
},
|
||||
|
||||
|
@ -10,3 +10,4 @@ cancel=Cancel
|
||||
continue=Continue
|
||||
installing=Installing %S
|
||||
installerror=Error installing language
|
||||
loading=Loading…
|
||||
|
@ -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@;
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -570,6 +570,10 @@ arrowbox {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.panel-arrow {
|
||||
min-height: 18px;
|
||||
}
|
||||
|
||||
.arrowbox-dark .panel-arrowcontent {
|
||||
padding: @padding_normal@; /* core spacing */
|
||||
}
|
||||
|
@ -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@;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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*)®s[i+1]) - sizeof(float)) = s->val.f;
|
||||
else
|
||||
*(float*)d++ = s->val.f;
|
||||
break;
|
||||
case nsXPTType::T_DOUBLE:
|
||||
if (i < N_ARG_REGS)
|
||||
*(double*)®s[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);
|
||||
}
|
@ -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
|
@ -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
|
Loading…
Reference in New Issue
Block a user