зеркало из https://github.com/mozilla/gecko-dev.git
merge the last green changeset on m-c to fx-team
This commit is contained in:
Коммит
af2455ebbc
|
@ -40,6 +40,20 @@
|
|||
|
||||
// gSyncUI handles updating the tools menu
|
||||
let gSyncUI = {
|
||||
_obs: ["weave:service:sync:start",
|
||||
"weave:service:sync:finish",
|
||||
"weave:service:sync:error",
|
||||
"weave:service:sync:delayed",
|
||||
"weave:service:quota:remaining",
|
||||
"weave:service:setup-complete",
|
||||
"weave:service:login:start",
|
||||
"weave:service:login:finish",
|
||||
"weave:service:login:error",
|
||||
"weave:service:logout:finish",
|
||||
"weave:service:start-over"],
|
||||
|
||||
_unloaded: false,
|
||||
|
||||
init: function SUI_init() {
|
||||
// Proceed to set up the UI if Sync has already started up.
|
||||
// Otherwise we'll do it when Sync is firing up.
|
||||
|
@ -52,31 +66,26 @@ let gSyncUI = {
|
|||
|
||||
// Remove the observer if the window is closed before the observer
|
||||
// was triggered.
|
||||
window.addEventListener("unload", function() {
|
||||
window.removeEventListener("unload", arguments.callee, false);
|
||||
window.addEventListener("unload", function onUnload() {
|
||||
gSyncUI._unloaded = true;
|
||||
window.removeEventListener("unload", onUnload, false);
|
||||
Services.obs.removeObserver(gSyncUI, "weave:service:ready");
|
||||
|
||||
if (Weave.Status.ready) {
|
||||
gSyncUI._obs.forEach(function(topic) {
|
||||
Services.obs.removeObserver(gSyncUI, topic);
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
},
|
||||
|
||||
initUI: function SUI_initUI() {
|
||||
let obs = ["weave:service:sync:start",
|
||||
"weave:service:sync:finish",
|
||||
"weave:service:sync:error",
|
||||
"weave:service:sync:delayed",
|
||||
"weave:service:quota:remaining",
|
||||
"weave:service:setup-complete",
|
||||
"weave:service:login:start",
|
||||
"weave:service:login:finish",
|
||||
"weave:service:login:error",
|
||||
"weave:service:logout:finish",
|
||||
"weave:service:start-over"];
|
||||
|
||||
// If this is a browser window?
|
||||
if (gBrowser) {
|
||||
obs.push("weave:notification:added");
|
||||
this._obs.push("weave:notification:added");
|
||||
}
|
||||
|
||||
obs.forEach(function(topic) {
|
||||
this._obs.forEach(function(topic) {
|
||||
Services.obs.addObserver(this, topic, true);
|
||||
}, this);
|
||||
|
||||
|
@ -93,7 +102,7 @@ let gSyncUI = {
|
|||
}
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
|
||||
initNotifications: function SUI_initNotifications() {
|
||||
const XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
let notificationbox = document.createElementNS(XULNS, "notificationbox");
|
||||
|
@ -151,7 +160,7 @@ let gSyncUI = {
|
|||
let popup = document.getElementById("alltabs-popup");
|
||||
if (!popup)
|
||||
return;
|
||||
|
||||
|
||||
let menuitem = document.createElement("menuitem");
|
||||
menuitem.setAttribute("id", "sync-tabs-menuitem");
|
||||
menuitem.setAttribute("label", label);
|
||||
|
@ -295,7 +304,7 @@ let gSyncUI = {
|
|||
let win = Services.wm.getMostRecentWindow("Sync:ViewQuota");
|
||||
if (win)
|
||||
win.focus();
|
||||
else
|
||||
else
|
||||
Services.ww.activeWindow.openDialog(
|
||||
"chrome://browser/content/syncQuota.xul", "",
|
||||
"centerscreen,chrome,dialog,modal");
|
||||
|
@ -414,8 +423,13 @@ let gSyncUI = {
|
|||
|
||||
this.updateUI();
|
||||
},
|
||||
|
||||
|
||||
observe: function SUI_observe(subject, topic, data) {
|
||||
if (this._unloaded) {
|
||||
Cu.reportError("SyncUI observer called after unload: " + topic);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (topic) {
|
||||
case "weave:service:sync:start":
|
||||
this.onActivityStart();
|
||||
|
|
|
@ -138,8 +138,7 @@ PlacesController.prototype = {
|
|||
},
|
||||
|
||||
terminate: function PC_terminate() {
|
||||
if (this._cutNodes.length > 0)
|
||||
this._clearClipboard();
|
||||
this._releaseClipboardOwnership();
|
||||
},
|
||||
|
||||
supportsCommand: function PC_supportsCommand(aCommand) {
|
||||
|
@ -1128,14 +1127,20 @@ PlacesController.prototype = {
|
|||
return action;
|
||||
},
|
||||
|
||||
_releaseClipboardOwnership: function PC__releaseClipboardOwnership() {
|
||||
if (this.cutNodes.length > 0) {
|
||||
// This clears the logical clipboard, doesn't remove data.
|
||||
this.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
},
|
||||
|
||||
_clearClipboard: function PC__clearClipboard() {
|
||||
this.clipboard.emptyClipboard(Ci.nsIClipboard.kGlobalClipboard);
|
||||
// Unfortunately just invoking emptyClipboard is not enough, since it
|
||||
// does not act on the native clipboard.
|
||||
let xferable = Cc["@mozilla.org/widget/transferable;1"].
|
||||
createInstance(Ci.nsITransferable);
|
||||
// GTK doesn't like empty transferables, so just add an unknown type.
|
||||
xferable.addDataFlavor("text/x-moz-place-empty");
|
||||
// Empty transferables may cause crashes, so just add an unknown type.
|
||||
const TYPE = "text/x-moz-place-empty";
|
||||
xferable.addDataFlavor(TYPE);
|
||||
xferable.setTransferData(TYPE, PlacesUtils.toISupportsString(""), 0);
|
||||
this.clipboard.setData(xferable, null, Ci.nsIClipboard.kGlobalClipboard);
|
||||
},
|
||||
|
||||
|
@ -1195,11 +1200,15 @@ PlacesController.prototype = {
|
|||
// concurrent instances of the application.
|
||||
addData(PlacesUtils.TYPE_X_MOZ_PLACE_ACTION, aAction + "," + this.profileName);
|
||||
|
||||
if (hasData)
|
||||
this.clipboard.setData(xferable, this, Ci.nsIClipboard.kGlobalClipboard);
|
||||
if (hasData) {
|
||||
this.clipboard.setData(xferable,
|
||||
this.cutNodes.length > 0 ? this : null,
|
||||
Ci.nsIClipboard.kGlobalClipboard);
|
||||
}
|
||||
},
|
||||
|
||||
_cutNodes: [],
|
||||
get cutNodes() this._cutNodes,
|
||||
set cutNodes(aNodes) {
|
||||
let self = this;
|
||||
function updateCutNodes(aValue) {
|
||||
|
|
|
@ -44,7 +44,8 @@ function onLibraryReady() {
|
|||
}
|
||||
|
||||
function onClipboardReady() {
|
||||
tests.pasteToTag();
|
||||
tests.focusTag();
|
||||
PlacesOrganizer._places.controller.paste();
|
||||
tests.historyNode();
|
||||
tests.checkForBookmarkInUI();
|
||||
|
||||
|
@ -56,7 +57,7 @@ function onClipboardReady() {
|
|||
let tags = PlacesUtils.tagging.getTagsForURI(NetUtil.newURI(TEST_URL));
|
||||
is(tags.length, 0, "tags are gone");
|
||||
PlacesUtils.bookmarks.removeFolderChildren(PlacesUtils.unfiledBookmarksFolderId);
|
||||
|
||||
|
||||
waitForClearHistory(finish);
|
||||
}
|
||||
|
||||
|
@ -80,25 +81,19 @@ let tests = {
|
|||
is(tags[0], 'foo', "tag is foo");
|
||||
},
|
||||
|
||||
focusTag: function (paste){
|
||||
focusTag: function (){
|
||||
// focus the new tag
|
||||
PlacesOrganizer.selectLeftPaneQuery("Tags");
|
||||
let tags = PlacesOrganizer._places.selectedNode;
|
||||
tags.containerOpen = true;
|
||||
let fooTag = tags.getChild(0);
|
||||
this.tagNode = fooTag;
|
||||
let tagNode = fooTag;
|
||||
PlacesOrganizer._places.selectNode(fooTag);
|
||||
is(this.tagNode.title, 'foo', "tagNode title is foo");
|
||||
is(tagNode.title, 'foo', "tagNode title is foo");
|
||||
let ip = PlacesOrganizer._places.insertionPoint;
|
||||
ok(ip.isTag, "IP is a tag");
|
||||
if (paste) {
|
||||
ok(true, "About to paste");
|
||||
PlacesOrganizer._places.controller.paste();
|
||||
}
|
||||
},
|
||||
|
||||
histNode: null,
|
||||
|
||||
copyHistNode: function (){
|
||||
// focus the history object
|
||||
PlacesOrganizer.selectLeftPaneQuery("History");
|
||||
|
@ -106,19 +101,14 @@ let tests = {
|
|||
PlacesUtils.asContainer(histContainer);
|
||||
histContainer.containerOpen = true;
|
||||
PlacesOrganizer._places.selectNode(histContainer.getChild(0));
|
||||
this.histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
|
||||
PlacesOrganizer._content.selectNode(this.histNode);
|
||||
is(this.histNode.uri, MOZURISPEC,
|
||||
"historyNode exists: " + this.histNode.uri);
|
||||
let histNode = PlacesOrganizer._content.view.nodeForTreeIndex(0);
|
||||
PlacesOrganizer._content.selectNode(histNode);
|
||||
is(histNode.uri, MOZURISPEC,
|
||||
"historyNode exists: " + histNode.uri);
|
||||
// copy the history node
|
||||
PlacesOrganizer._content.controller.copy();
|
||||
},
|
||||
|
||||
pasteToTag: function (){
|
||||
// paste history node into tag
|
||||
this.focusTag(true);
|
||||
},
|
||||
|
||||
historyNode: function (){
|
||||
// re-focus the history again
|
||||
PlacesOrganizer.selectLeftPaneQuery("History");
|
||||
|
@ -148,8 +138,6 @@ let tests = {
|
|||
ok(unsortedNode, "unsortedNode is not null: " + unsortedNode.uri);
|
||||
is(unsortedNode.uri, MOZURISPEC, "node uri's are the same");
|
||||
},
|
||||
|
||||
tagNode: null,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -46,23 +46,17 @@
|
|||
#
|
||||
topsrcdir=$1
|
||||
|
||||
absolute_path() {
|
||||
if [ -n "${1%%/*}" ]; then
|
||||
echo $topsrcdir/$1
|
||||
else
|
||||
echo $1
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -n "$MOZCONFIG" ]; then
|
||||
MOZCONFIG=`absolute_path "$MOZCONFIG"`
|
||||
if ! [ -f "$MOZCONFIG" ]; then
|
||||
echo "Specified MOZCONFIG \"$MOZCONFIG\" does not exist!"
|
||||
for _config in "$MOZCONFIG" \
|
||||
"$MOZ_MYCONFIG"
|
||||
do
|
||||
if [ -n "$_config" ] && ! [ -f "$_config" ]; then
|
||||
echo "Specified MOZCONFIG \"$_config\" does not exist!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
for _config in "$MOZCONFIG" \
|
||||
"$MOZ_MYCONFIG" \
|
||||
"$topsrcdir/.mozconfig" \
|
||||
"$topsrcdir/mozconfig" \
|
||||
"$topsrcdir/mozconfig.sh" \
|
||||
|
|
|
@ -192,7 +192,7 @@ ifdef CPP_UNIT_TESTS
|
|||
CPPSRCS += $(CPP_UNIT_TESTS)
|
||||
SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
|
||||
INCLUDES += -I$(DIST)/include/testing
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(MOZ_JS_LIBS)
|
||||
|
||||
# ...and run them the usual way
|
||||
check::
|
||||
|
|
|
@ -1874,10 +1874,11 @@ dnl ========================================================
|
|||
dnl callgrind
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(callgrind,
|
||||
[ --enable-callgrind Enable callgrind profiling],
|
||||
[ --enable-callgrind Enable callgrind profiling. Implies --enable-profiling.],
|
||||
MOZ_CALLGRIND=1,
|
||||
MOZ_CALLGRIND= )
|
||||
if test -n "$MOZ_CALLGRIND"; then
|
||||
MOZ_PROFILING=1
|
||||
AC_DEFINE(MOZ_CALLGRIND)
|
||||
fi
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ static fp_except_t oldmask = fpsetmask(~allmask);
|
|||
#include "nsIDOMNode.h"
|
||||
#include "nsAHtml5FragmentParser.h"
|
||||
#include "nsIFragmentContentSink.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
struct nsNativeKeyEvent; // Don't include nsINativeKeyBindings.h here: it will force strange compilation error!
|
||||
|
||||
|
@ -2034,50 +2035,38 @@ public:
|
|||
#define DOUBLE_COMPARE(LVAL, OP, RVAL) ((LVAL) OP (RVAL))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check whether a floating point number is finite (not +/-infinity and not a
|
||||
* NaN value).
|
||||
*/
|
||||
inline NS_HIDDEN_(PRBool) NS_FloatIsFinite(jsdouble f) {
|
||||
#ifdef WIN32
|
||||
return _finite(f);
|
||||
#else
|
||||
return finite(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* In the following helper macros we exploit the fact that the result of a
|
||||
* series of additions will not be finite if any one of the operands in the
|
||||
* series is not finite.
|
||||
*/
|
||||
#define NS_ENSURE_FINITE(f, rv) \
|
||||
if (!NS_FloatIsFinite(f)) { \
|
||||
if (!NS_finite(f)) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define NS_ENSURE_FINITE2(f1, f2, rv) \
|
||||
if (!NS_FloatIsFinite((f1)+(f2))) { \
|
||||
if (!NS_finite((f1)+(f2))) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define NS_ENSURE_FINITE3(f1, f2, f3, rv) \
|
||||
if (!NS_FloatIsFinite((f1)+(f2)+(f3))) { \
|
||||
if (!NS_finite((f1)+(f2)+(f3))) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define NS_ENSURE_FINITE4(f1, f2, f3, f4, rv) \
|
||||
if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4))) { \
|
||||
if (!NS_finite((f1)+(f2)+(f3)+(f4))) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define NS_ENSURE_FINITE5(f1, f2, f3, f4, f5, rv) \
|
||||
if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4)+(f5))) { \
|
||||
if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5))) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
#define NS_ENSURE_FINITE6(f1, f2, f3, f4, f5, f6, rv) \
|
||||
if (!NS_FloatIsFinite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) { \
|
||||
if (!NS_finite((f1)+(f2)+(f3)+(f4)+(f5)+(f6))) { \
|
||||
return (rv); \
|
||||
}
|
||||
|
||||
|
|
|
@ -8401,7 +8401,7 @@ PRInt64
|
|||
nsDocument::SizeOf() const
|
||||
{
|
||||
PRInt64 size = MemoryReporter::GetBasicSize<nsDocument, nsIDocument>(this);
|
||||
size += mAttrStyleSheet ? mAttrStyleSheet->SizeOf() : 0;
|
||||
size += mAttrStyleSheet ? mAttrStyleSheet->DOMSizeOf() : 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
|
|
|
@ -1195,7 +1195,7 @@ nsTreeSanitizer::SanitizeAttributes(mozilla::dom::Element* aElement,
|
|||
rv = NS_OK;
|
||||
const nsAttrName* attrName = aElement->GetAttrNameAt(i);
|
||||
PRInt32 attrNs = attrName->NamespaceID();
|
||||
nsIAtom* attrLocal = attrName->Atom();
|
||||
nsIAtom* attrLocal = attrName->LocalName();
|
||||
|
||||
if (kNameSpaceID_None == attrNs) {
|
||||
if (aAllowStyle && nsGkAtoms::style == attrLocal) {
|
||||
|
|
|
@ -2671,14 +2671,15 @@ nsEventStateManager::ComputeWheelActionFor(nsMouseScrollEvent* aMouseEvent,
|
|||
// Do not scroll pixels when zooming
|
||||
action = -1;
|
||||
}
|
||||
} else if (aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) {
|
||||
if (aUseSystemSettings ||
|
||||
action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE ||
|
||||
(aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum)) {
|
||||
// Don't scroll lines when a pixel scroll event will follow.
|
||||
// Also, don't do history scrolling or zooming for momentum scrolls.
|
||||
action = -1;
|
||||
}
|
||||
} else if (((aMouseEvent->scrollFlags & nsMouseScrollEvent::kHasPixels) &&
|
||||
(aUseSystemSettings ||
|
||||
action == MOUSE_SCROLL_N_LINES || action == MOUSE_SCROLL_PAGE)) ||
|
||||
((aMouseEvent->scrollFlags & nsMouseScrollEvent::kIsMomentum) &&
|
||||
(action == MOUSE_SCROLL_HISTORY || action == MOUSE_SCROLL_ZOOM))) {
|
||||
// Don't scroll lines or page when a pixel scroll event will follow.
|
||||
// Also, don't do history scrolling or zooming for momentum scrolls,
|
||||
// no matter what's going on with pixel scrolling.
|
||||
action = -1;
|
||||
}
|
||||
|
||||
return action;
|
||||
|
|
|
@ -35,7 +35,11 @@ function sendTouchpadScrollMotion(scrollbox, direction, ctrl, momentum) {
|
|||
};
|
||||
// first a line scroll
|
||||
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
|
||||
// Then a line scroll with hasPixels set to false
|
||||
event.hasPixels = false;
|
||||
synthesizeMouseScroll(scrollbox, 10, 10, event, win);
|
||||
// then 5 pixel scrolls
|
||||
event.hasPixels = true;
|
||||
event.delta *= 3;
|
||||
event.type = "MozMousePixelScroll";
|
||||
event.hasPixels = false;
|
||||
|
|
|
@ -2034,6 +2034,11 @@ void nsHTMLMediaElement::PlaybackEnded()
|
|||
// We changed the state of IsPlaybackEnded which can affect AddRemoveSelfReference
|
||||
AddRemoveSelfReference();
|
||||
|
||||
if (mDecoder && mDecoder->IsInfinite()) {
|
||||
LOG(PR_LOG_DEBUG, ("%p, got duration by reaching the end of the stream", this));
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("durationchange"));
|
||||
}
|
||||
|
||||
FireTimeUpdate(PR_FALSE);
|
||||
DispatchAsyncEvent(NS_LITERAL_STRING("ended"));
|
||||
}
|
||||
|
|
|
@ -687,8 +687,9 @@ nsHTMLSelectElement::Add(nsIDOMHTMLElement* aElement,
|
|||
nsresult rv = aBefore->GetDataType(&dataType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// aBefore is omitted or null
|
||||
if (dataType == nsIDataType::VTYPE_EMPTY) {
|
||||
// aBefore is omitted, undefined or null
|
||||
if (dataType == nsIDataType::VTYPE_EMPTY ||
|
||||
dataType == nsIDataType::VTYPE_VOID) {
|
||||
return Add(aElement);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,18 +22,22 @@ var opt1 = new Option();
|
|||
var opt2 = new Option();
|
||||
var opt3 = new Option();
|
||||
var opt4 = new Option();
|
||||
var opt5 = new Option();
|
||||
opt1.value = 1;
|
||||
opt2.value = 2;
|
||||
opt3.value = 3;
|
||||
opt4.value = 4;
|
||||
opt5.value = 5;
|
||||
sel.add(opt1);
|
||||
sel.add(opt2, 0);
|
||||
sel.add(opt3, 1000);
|
||||
sel.options.add(opt4, opt3);
|
||||
sel.add(opt5, undefined);
|
||||
is(sel[0], opt2, "1st item should be 2");
|
||||
is(sel[1], opt1, "2nd item should be 1");
|
||||
is(sel[2], opt4, "3rd item should be 4");
|
||||
is(sel[3], opt3, "4th item should be 3");
|
||||
is(sel[4], opt5, "5th item should be 5");
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -83,12 +83,27 @@ void nsBuiltinDecoder::SetVolume(double aVolume)
|
|||
double nsBuiltinDecoder::GetDuration()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
if (mInfiniteStream) {
|
||||
return std::numeric_limits<double>::infinity();
|
||||
}
|
||||
if (mDuration >= 0) {
|
||||
return static_cast<double>(mDuration) / static_cast<double>(USECS_PER_S);
|
||||
}
|
||||
return std::numeric_limits<double>::quiet_NaN();
|
||||
}
|
||||
|
||||
void nsBuiltinDecoder::SetInfinite(PRBool aInfinite)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
mInfiniteStream = aInfinite;
|
||||
}
|
||||
|
||||
PRBool nsBuiltinDecoder::IsInfinite()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
return mInfiniteStream;
|
||||
}
|
||||
|
||||
nsBuiltinDecoder::nsBuiltinDecoder() :
|
||||
mDecoderPosition(0),
|
||||
mPlaybackPosition(0),
|
||||
|
@ -101,7 +116,8 @@ nsBuiltinDecoder::nsBuiltinDecoder() :
|
|||
mPlayState(PLAY_STATE_PAUSED),
|
||||
mNextState(PLAY_STATE_PAUSED),
|
||||
mResourceLoaded(PR_FALSE),
|
||||
mIgnoreProgressData(PR_FALSE)
|
||||
mIgnoreProgressData(PR_FALSE),
|
||||
mInfiniteStream(PR_FALSE)
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsBuiltinDecoder);
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
|
||||
|
@ -342,6 +358,10 @@ void nsBuiltinDecoder::MetadataLoaded(PRUint32 aChannels,
|
|||
notifyElement = mNextState != PLAY_STATE_SEEKING;
|
||||
}
|
||||
|
||||
if (mDuration == -1) {
|
||||
SetInfinite(PR_TRUE);
|
||||
}
|
||||
|
||||
if (mElement && notifyElement) {
|
||||
// Make sure the element and the frame (if any) are told about
|
||||
// our new size.
|
||||
|
@ -461,6 +481,12 @@ void nsBuiltinDecoder::PlaybackEnded()
|
|||
UpdateReadyStateForData();
|
||||
mElement->PlaybackEnded();
|
||||
}
|
||||
|
||||
// This must be called after |mElement->PlaybackEnded()| call above, in order
|
||||
// to fire the required durationchange.
|
||||
if (IsInfinite()) {
|
||||
SetInfinite(PR_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsBuiltinDecoder::Observe(nsISupports *aSubjet,
|
||||
|
@ -791,7 +817,7 @@ void nsBuiltinDecoder::DurationChanged()
|
|||
// Duration has changed so we should recompute playback rate
|
||||
UpdatePlaybackRate();
|
||||
|
||||
if (mElement && oldDuration != mDuration) {
|
||||
if (mElement && oldDuration != mDuration && !IsInfinite()) {
|
||||
LOG(PR_LOG_DEBUG, ("%p duration changed to %lld", this, mDuration));
|
||||
mElement->DispatchEvent(NS_LITERAL_STRING("durationchange"));
|
||||
}
|
||||
|
|
|
@ -395,6 +395,9 @@ class nsBuiltinDecoder : public nsMediaDecoder
|
|||
virtual void SetVolume(double aVolume);
|
||||
virtual double GetDuration();
|
||||
|
||||
virtual void SetInfinite(PRBool aInfinite);
|
||||
virtual PRBool IsInfinite();
|
||||
|
||||
virtual nsMediaStream* GetCurrentStream();
|
||||
virtual already_AddRefed<nsIPrincipal> GetCurrentPrincipal();
|
||||
|
||||
|
@ -688,6 +691,9 @@ public:
|
|||
// from jumping around. Read/Write from any thread. Must have decode monitor
|
||||
// locked before accessing.
|
||||
PRPackedBool mIgnoreProgressData;
|
||||
|
||||
// PR_TRUE if the stream is infinite (e.g. a webradio).
|
||||
PRPackedBool mInfiniteStream;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -476,6 +476,9 @@ public:
|
|||
|
||||
virtual void* operator()(void* anObject) {
|
||||
const VideoData* v = static_cast<const VideoData*>(anObject);
|
||||
if (!v->mImage) {
|
||||
return nsnull;
|
||||
}
|
||||
NS_ASSERTION(v->mImage->GetFormat() == mozilla::layers::Image::PLANAR_YCBCR,
|
||||
"Wrong format?");
|
||||
mozilla::layers::PlanarYCbCrImage* vi = static_cast<mozilla::layers::PlanarYCbCrImage*>(v->mImage.get());
|
||||
|
|
|
@ -112,6 +112,19 @@ public:
|
|||
// Return the duration of the video in seconds.
|
||||
virtual double GetDuration() = 0;
|
||||
|
||||
// A media stream is assumed to be infinite if the metadata doesn't
|
||||
// contain the duration, and range requests are not supported, and
|
||||
// no headers give a hint of a possible duration (Content-Length,
|
||||
// Content-Duration, and variants), and we cannot seek in the media
|
||||
// stream to determine the duration.
|
||||
//
|
||||
// When the media stream ends, we can know the duration, thus the stream is
|
||||
// no longer considered to be infinite.
|
||||
virtual void SetInfinite(PRBool aInfinite) = 0;
|
||||
|
||||
// Return true if the stream is infinite (see SetInfinite).
|
||||
virtual PRBool IsInfinite() = 0;
|
||||
|
||||
// Pause video playback.
|
||||
virtual void Pause() = 0;
|
||||
|
||||
|
|
|
@ -225,6 +225,8 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
|||
if (ec == NS_OK && duration >= 0) {
|
||||
mDecoder->SetDuration(duration);
|
||||
}
|
||||
} else {
|
||||
mDecoder->SetInfinite(PR_TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,6 +258,10 @@ nsMediaChannelStream::OnStartRequest(nsIRequest* aRequest)
|
|||
// support seeking.
|
||||
seekable =
|
||||
responseStatus == HTTP_PARTIAL_RESPONSE_CODE || acceptsRanges;
|
||||
|
||||
if (seekable) {
|
||||
mDecoder->SetInfinite(PR_FALSE);
|
||||
}
|
||||
}
|
||||
mDecoder->SetSeekable(seekable);
|
||||
mCacheStream.SetSeekable(seekable);
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
function on_metadataloaded() {
|
||||
var v = document.getElementById('v');
|
||||
var d = Math.round(v.duration*1000);
|
||||
ok(d.toString() == "NaN", "Checking duration: " + d);
|
||||
ok(d.toString() == "Infinity", "Checking duration: " + d);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
function on_metadataloaded() {
|
||||
var v = document.getElementById('v');
|
||||
var d = Math.round(v.duration*1000);
|
||||
ok(d.toString() == "NaN", "Checking duration: " + d);
|
||||
ok(d.toString() == "Infinity", "Checking duration: " + d);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
function on_metadataloaded() {
|
||||
var v = document.getElementById('v');
|
||||
var d = Math.round(v.duration*1000);
|
||||
ok(d.toString() == "NaN", "Checking duration: " + d);
|
||||
ok(d.toString() == "Infinity", "Checking duration: " + d);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
function on_metadataloaded() {
|
||||
var v = document.getElementById('v');
|
||||
var d = Math.round(v.duration*1000);
|
||||
ok(d.toString() == "NaN", "Checking duration: " + d);
|
||||
ok(d.toString() == "Infinity", "Checking duration: " + d);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "nsSVGElement.h"
|
||||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
// See the architecture comment in DOMSVGAnimatedLengthList.h.
|
||||
|
||||
|
@ -129,7 +130,7 @@ DOMSVGLength::GetValue(float* aValue)
|
|||
#endif
|
||||
if (HasOwner()) {
|
||||
*aValue = InternalItem().GetValueInUserUnits(Element(), Axis());
|
||||
if (NS_FloatIsFinite(*aValue)) {
|
||||
if (NS_finite(*aValue)) {
|
||||
return NS_OK;
|
||||
}
|
||||
} else if (mUnit == nsIDOMSVGLength::SVG_LENGTHTYPE_NUMBER ||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "gfxPoint.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
|
@ -128,7 +129,7 @@ public:
|
|||
{
|
||||
mPt.mX = float(aPt.x);
|
||||
mPt.mY = float(aPt.y);
|
||||
NS_ASSERTION(NS_FloatIsFinite(mPt.mX) && NS_FloatIsFinite(mPt.mX),
|
||||
NS_ASSERTION(NS_finite(mPt.mX) && NS_finite(mPt.mX),
|
||||
"DOMSVGPoint coords are not finite");
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@
|
|||
#include "nsSVGSVGElement.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include <limits>
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -78,7 +78,7 @@ SVGLength::SetValueFromString(const nsAString &aValue)
|
|||
}
|
||||
char *unit;
|
||||
tmpValue = float(PR_strtod(str, &unit));
|
||||
if (unit != str && NS_FloatIsFinite(tmpValue)) {
|
||||
if (unit != str && NS_finite(tmpValue)) {
|
||||
char *theRest = unit;
|
||||
if (*unit != '\0' && !IsSVGWhitespace(*unit)) {
|
||||
while (*theRest != '\0' && !IsSVGWhitespace(*theRest)) {
|
||||
|
@ -172,17 +172,17 @@ SVGLength::GetValueInSpecifiedUnit(PRUint8 aUnit,
|
|||
SVGLength(0.0f, aUnit).GetUserUnitsPerUnit(aElement, aAxis);
|
||||
|
||||
NS_ASSERTION(userUnitsPerCurrentUnit >= 0 ||
|
||||
!NS_FloatIsFinite(userUnitsPerCurrentUnit),
|
||||
!NS_finite(userUnitsPerCurrentUnit),
|
||||
"bad userUnitsPerCurrentUnit");
|
||||
NS_ASSERTION(userUnitsPerNewUnit >= 0 ||
|
||||
!NS_FloatIsFinite(userUnitsPerNewUnit),
|
||||
!NS_finite(userUnitsPerNewUnit),
|
||||
"bad userUnitsPerNewUnit");
|
||||
|
||||
float value = mValue * userUnitsPerCurrentUnit / userUnitsPerNewUnit;
|
||||
|
||||
// userUnitsPerCurrentUnit could be infinity, or userUnitsPerNewUnit could
|
||||
// be zero.
|
||||
if (NS_FloatIsFinite(value)) {
|
||||
if (NS_finite(value)) {
|
||||
return value;
|
||||
}
|
||||
return std::numeric_limits<float>::quiet_NaN();
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
#include "nsIDOMSVGLength.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsAString.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
class nsSVGElement;
|
||||
|
||||
|
@ -152,7 +152,7 @@ public:
|
|||
PRUint8 aAxis) {
|
||||
float uuPerUnit = GetUserUnitsPerUnit(aElement, aAxis);
|
||||
float value = aUserUnitValue / uuPerUnit;
|
||||
if (uuPerUnit > 0 && NS_FloatIsFinite(value)) {
|
||||
if (uuPerUnit > 0 && NS_finite(value)) {
|
||||
mValue = value;
|
||||
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
|
||||
return PR_TRUE;
|
||||
|
@ -179,7 +179,7 @@ public:
|
|||
*/
|
||||
PRBool ConvertToUnit(PRUint32 aUnit, nsSVGElement *aElement, PRUint8 aAxis) {
|
||||
float val = GetValueInSpecifiedUnit(aUnit, aElement, aAxis);
|
||||
if (NS_FloatIsFinite(val)) {
|
||||
if (NS_finite(val)) {
|
||||
mValue = val;
|
||||
mUnit = aUnit;
|
||||
NS_ASSERTION(IsValid(), "Set invalid SVGLength");
|
||||
|
@ -201,7 +201,7 @@ private:
|
|||
|
||||
#ifdef DEBUG
|
||||
PRBool IsValid() const {
|
||||
return NS_FloatIsFinite(mValue) && IsValidUnitType(mUnit);
|
||||
return NS_finite(mValue) && IsValidUnitType(mUnit);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "SVGLengthListSMILType.h"
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGLengthList.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -252,7 +253,7 @@ SVGLengthListSMILType::ComputeDistance(const nsSMILValue& aFrom,
|
|||
}
|
||||
|
||||
float distance = sqrt(total);
|
||||
if (!NS_FloatIsFinite(distance)) {
|
||||
if (!NS_finite(distance)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aDistance = distance;
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
#include "nsSVGElement.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "string.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -98,7 +98,7 @@ SVGNumberList::SetValueFromString(const nsAString& aValue)
|
|||
}
|
||||
char *end;
|
||||
float num = float(PR_strtod(token, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(num)) {
|
||||
if (*end != '\0' || !NS_finite(num)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
temp.AppendItem(num);
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include "SVGNumberListSMILType.h"
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGNumberList.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include <math.h>
|
||||
|
||||
/* The "identity" number list for a given number list attribute (the effective
|
||||
|
@ -185,7 +186,7 @@ SVGNumberListSMILType::ComputeDistance(const nsSMILValue& aFrom,
|
|||
total += delta * delta;
|
||||
}
|
||||
double distance = sqrt(total);
|
||||
if (!NS_FloatIsFinite(distance)) {
|
||||
if (!NS_finite(distance)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aDistance = distance;
|
||||
|
|
|
@ -38,8 +38,8 @@
|
|||
#define MOZILLA_SVGPOINT_H__
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "gfxPoint.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -93,7 +93,7 @@ public:
|
|||
|
||||
#ifdef DEBUG
|
||||
PRBool IsValid() const {
|
||||
return NS_FloatIsFinite(mX) && NS_FloatIsFinite(mY);
|
||||
return NS_finite(mX) && NS_finite(mY);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
#include "nsSVGElement.h"
|
||||
#include "nsISVGValueUtils.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "string.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -113,7 +113,7 @@ SVGPointList::SetValueFromString(const nsAString& aValue)
|
|||
}
|
||||
char *end;
|
||||
float x = float(PR_strtod(token1, &end));
|
||||
if (end == token1 || !NS_FloatIsFinite(x)) {
|
||||
if (end == token1 || !NS_finite(x)) {
|
||||
rv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
break;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ SVGPointList::SetValueFromString(const nsAString& aValue)
|
|||
}
|
||||
|
||||
float y = float(PR_strtod(token2, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(y)) {
|
||||
if (*end != '\0' || !NS_finite(y)) {
|
||||
rv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -170,7 +170,7 @@ SVGPointListSMILType::ComputeDistance(const nsSMILValue& aFrom,
|
|||
total += dx * dx + dy * dy;
|
||||
}
|
||||
double distance = sqrt(total);
|
||||
if (!NS_FloatIsFinite(distance)) {
|
||||
if (!NS_finite(distance)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
aDistance = distance;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsTextFormatter.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsSVGMarkerElement.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGOrientSMILType.h"
|
||||
|
@ -225,7 +226,7 @@ GetValueFromString(const nsAString &aValueAsString,
|
|||
|
||||
char *rest;
|
||||
*aValue = float(PR_strtod(str, &rest));
|
||||
if (rest != str && NS_FloatIsFinite(*aValue)) {
|
||||
if (rest != str && NS_finite(*aValue)) {
|
||||
*aUnitType = GetUnitTypeForString(rest);
|
||||
if (IsValidUnitType(*aUnitType)) {
|
||||
return NS_OK;
|
||||
|
|
|
@ -49,9 +49,9 @@
|
|||
|
||||
|
||||
#include "nsSVGDataParser.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsSVGUtils.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
|
@ -145,7 +145,7 @@ nsresult nsSVGDataParser::MatchNonNegativeNumber(float* aX)
|
|||
|
||||
char* end;
|
||||
*aX = float(PR_strtod(pos, &end));
|
||||
if (pos != end && NS_FloatIsFinite(*aX)) {
|
||||
if (pos != end && NS_finite(*aX)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -181,7 +181,7 @@ nsresult nsSVGDataParser::MatchNumber(float* aX)
|
|||
* nsCSSScanner::ParseNumber() instead of PR_strtod. See bug 516396 for some
|
||||
* additional info. */
|
||||
*aX = float(PR_strtod(pos, &end));
|
||||
if (pos != end && NS_FloatIsFinite(*aX)) {
|
||||
if (pos != end && NS_finite(*aX)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsSVGUtils.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGIntegerPairSMILType.h"
|
||||
|
@ -81,7 +82,7 @@ ParseIntegerOptionalInteger(const nsAString& aValue,
|
|||
|
||||
char *end;
|
||||
aValues[i] = strtol(token, &end, 10);
|
||||
if (*end != '\0' || !NS_FloatIsFinite(aValues[i])) {
|
||||
if (*end != '\0' || !NS_finite(aValues[i])) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR; // parse error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "nsIFrame.h"
|
||||
#include "nsSVGIntegrationUtils.h"
|
||||
#include "nsSVGAttrTearoffTable.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "nsSMILFloatType.h"
|
||||
|
@ -175,7 +176,7 @@ GetValueFromString(const nsAString &aValueAsString,
|
|||
|
||||
char *rest;
|
||||
*aValue = float(PR_strtod(str, &rest));
|
||||
if (rest != str && NS_FloatIsFinite(*aValue)) {
|
||||
if (rest != str && NS_finite(*aValue)) {
|
||||
*aUnitType = GetUnitTypeForString(rest);
|
||||
if (IsValidUnitType(*aUnitType)) {
|
||||
return NS_OK;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "nsSVGUtils.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "nsSMILFloatType.h"
|
||||
|
@ -99,7 +100,7 @@ GetValueFromString(const nsAString &aValueAsString,
|
|||
|
||||
char *rest;
|
||||
*aValue = float(PR_strtod(str, &rest));
|
||||
if (rest == str || !NS_FloatIsFinite(*aValue)) {
|
||||
if (rest == str || !NS_finite(*aValue)) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
if (*rest == '%' && aPercentagesAllowed) {
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "prdtoa.h"
|
||||
#include "nsDOMError.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGNumberPairSMILType.h"
|
||||
|
@ -82,7 +83,7 @@ ParseNumberOptionalNumber(const nsAString& aValue,
|
|||
|
||||
char *end;
|
||||
aValues[i] = float(PR_strtod(token, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(aValues[i])) {
|
||||
if (*end != '\0' || !NS_finite(aValues[i])) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR; // parse error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nsISVGValue.h"
|
||||
#include "prdtoa.h"
|
||||
#include "prlog.h"
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
nsresult
|
||||
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
|
||||
|
@ -235,7 +236,7 @@ nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
|
|||
char const *arg = start.get();
|
||||
char *argend;
|
||||
float f = float(PR_strtod(arg, &argend));
|
||||
if (arg == argend || argend > end.get() || !NS_FloatIsFinite(f))
|
||||
if (arg == argend || argend > end.get() || !NS_finite(f))
|
||||
return -1;
|
||||
|
||||
if (numArgsFound < aNVars) {
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "prdtoa.h"
|
||||
#include "nsTextFormatter.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "nsMathUtils.h"
|
||||
#ifdef MOZ_SMIL
|
||||
#include "nsSMILValue.h"
|
||||
#include "SVGViewBoxSMILType.h"
|
||||
|
@ -156,7 +157,7 @@ ToSVGViewBoxRect(const nsAString& aStr, nsSVGViewBoxRect *aViewBox)
|
|||
|
||||
char *end;
|
||||
vals[i] = float(PR_strtod(token, &end));
|
||||
if (*end != '\0' || !NS_FloatIsFinite(vals[i])) {
|
||||
if (*end != '\0' || !NS_finite(vals[i])) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR; // parse error
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9351,12 +9351,14 @@ nsDocShell::ScrollToAnchor(nsACString & aCurHash, nsACString & aNewHash,
|
|||
// position will be restored by the caller, based on positions
|
||||
// stored in session history.
|
||||
if (aLoadType == LOAD_HISTORY || aLoadType == LOAD_RELOAD_NORMAL)
|
||||
return rv;
|
||||
//An empty anchor. Scroll to the top of the page.
|
||||
rv = SetCurScrollPosEx(0, 0);
|
||||
return NS_OK;
|
||||
// An empty anchor. Scroll to the top of the page. Ignore the
|
||||
// return value; failure to scroll here (e.g. if there is no
|
||||
// root scrollframe) is not grounds for canceling the load!
|
||||
SetCurScrollPosEx(0, 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -118,6 +118,7 @@ _TEST_FILES = \
|
|||
bug668513_redirect.html^headers^ \
|
||||
test_bug669671.html \
|
||||
file_bug669671.sjs \
|
||||
test_bug675587.html \
|
||||
$(NULL)
|
||||
|
||||
ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=675587
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 675587</title>
|
||||
<script type="application/javascript" src="/MochiKit/packed.js"></script>
|
||||
<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=675587">Mozilla Bug 675587</a>
|
||||
<p id="display">
|
||||
<iframe src="data:text/html,<script>location.hash='';</script>#hash"></iframe>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 675587 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
addLoadEvent(function() {
|
||||
is(window.frames[0].location.href,
|
||||
"data:text/html,<script>location.hash='';</" + "script>#",
|
||||
"Should have the right href");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -198,7 +198,6 @@
|
|||
#include "nsIPresShell.h"
|
||||
#include "nsIDOMElement.h"
|
||||
#include "nsIDOMCSSStyleDeclaration.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsMemory.h"
|
||||
|
|
|
@ -242,10 +242,7 @@ private:
|
|||
class CreateIndexHelper : public AsyncConnectionHelper
|
||||
{
|
||||
public:
|
||||
CreateIndexHelper(IDBTransaction* aTransaction,
|
||||
IDBIndex* aIndex)
|
||||
: AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
|
||||
{ }
|
||||
CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex);
|
||||
|
||||
nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
|
||||
|
||||
|
@ -268,10 +265,17 @@ public:
|
|||
private:
|
||||
nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
|
||||
|
||||
static void DestroyTLSEntry(void* aPtr);
|
||||
|
||||
static PRUintn sTLSIndex;
|
||||
|
||||
// In-params.
|
||||
nsRefPtr<IDBIndex> mIndex;
|
||||
};
|
||||
|
||||
static const PRUintn BAD_TLS_INDEX = (PRUint32)-1;
|
||||
PRUintn CreateIndexHelper::sTLSIndex = BAD_TLS_INDEX;
|
||||
|
||||
class DeleteIndexHelper : public AsyncConnectionHelper
|
||||
{
|
||||
public:
|
||||
|
@ -591,7 +595,7 @@ nsresult
|
|||
IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
||||
PRUint32 aDataLength,
|
||||
const nsAString& aKeyPath,
|
||||
JSContext** aCx,
|
||||
JSContext* aCx,
|
||||
Key& aValue)
|
||||
{
|
||||
NS_ASSERTION(aData, "Null pointer!");
|
||||
|
@ -599,18 +603,10 @@ IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
|||
NS_ASSERTION(!aKeyPath.IsEmpty(), "Empty keyPath!");
|
||||
NS_ASSERTION(aCx, "Null pointer!");
|
||||
|
||||
nsresult rv;
|
||||
|
||||
if (!*aCx) {
|
||||
rv = nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(aCx);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
}
|
||||
JSContext*& cx = *aCx;
|
||||
|
||||
JSAutoRequest ar(cx);
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
jsval clone;
|
||||
if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(aData),
|
||||
if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
|
||||
aDataLength, JS_STRUCTURED_CLONE_VERSION,
|
||||
&clone, NULL, NULL)) {
|
||||
return NS_ERROR_DOM_DATA_CLONE_ERR;
|
||||
|
@ -629,10 +625,10 @@ IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
|||
const size_t keyPathLen = aKeyPath.Length();
|
||||
|
||||
jsval keyVal;
|
||||
JSBool ok = JS_GetUCProperty(cx, obj, keyPathChars, keyPathLen, &keyVal);
|
||||
JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen, &keyVal);
|
||||
NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
rv = GetKeyFromJSVal(keyVal, *aCx, aValue);
|
||||
nsresult rv = GetKeyFromJSVal(keyVal, aCx, aValue);
|
||||
if (NS_FAILED(rv)) {
|
||||
// If the object doesn't have a value that we can use for our index then we
|
||||
// leave it unset.
|
||||
|
@ -2204,6 +2200,93 @@ OpenCursorHelper::GetSuccessResult(JSContext* aCx,
|
|||
return WrapNative(aCx, cursor, aVal);
|
||||
}
|
||||
|
||||
class ThreadLocalJSRuntime
|
||||
{
|
||||
JSRuntime* mRuntime;
|
||||
JSContext* mContext;
|
||||
JSObject* mGlobal;
|
||||
|
||||
static JSClass sGlobalClass;
|
||||
static const unsigned sRuntimeHeapSize = 64 * 1024; // should be enough for anyone
|
||||
|
||||
ThreadLocalJSRuntime()
|
||||
: mRuntime(NULL), mContext(NULL), mGlobal(NULL)
|
||||
{
|
||||
MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
|
||||
}
|
||||
|
||||
nsresult Init()
|
||||
{
|
||||
mRuntime = JS_NewRuntime(sRuntimeHeapSize);
|
||||
NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
mContext = JS_NewContext(mRuntime, 0);
|
||||
NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JSAutoRequest ar(mContext);
|
||||
|
||||
mGlobal = JS_NewCompartmentAndGlobalObject(mContext, &sGlobalClass, NULL);
|
||||
NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
||||
JS_SetGlobalObject(mContext, mGlobal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
public:
|
||||
static ThreadLocalJSRuntime *Create()
|
||||
{
|
||||
ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
|
||||
NS_ENSURE_TRUE(entry, nsnull);
|
||||
|
||||
if (NS_FAILED(entry->Init())) {
|
||||
delete entry;
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
JSContext *Context() const
|
||||
{
|
||||
return mContext;
|
||||
}
|
||||
|
||||
~ThreadLocalJSRuntime()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
|
||||
|
||||
if (mContext) {
|
||||
JS_DestroyContext(mContext);
|
||||
}
|
||||
|
||||
if (mRuntime) {
|
||||
JS_DestroyRuntime(mRuntime);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
JSClass ThreadLocalJSRuntime::sGlobalClass = {
|
||||
"IndexedDBTransactionThreadGlobal",
|
||||
JSCLASS_GLOBAL_FLAGS,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
||||
};
|
||||
|
||||
CreateIndexHelper::CreateIndexHelper(IDBTransaction* aTransaction,
|
||||
IDBIndex* aIndex)
|
||||
: AsyncConnectionHelper(aTransaction, nsnull), mIndex(aIndex)
|
||||
{
|
||||
if (sTLSIndex == BAD_TLS_INDEX) {
|
||||
PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CreateIndexHelper::DestroyTLSEntry(void* aPtr)
|
||||
{
|
||||
delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
|
||||
{
|
||||
|
@ -2334,11 +2417,22 @@ CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
|
|||
rv = stmt->GetSharedBlob(1, &dataLength, &data);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
ThreadLocalJSRuntime* tlsEntry =
|
||||
reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
|
||||
|
||||
if (!tlsEntry) {
|
||||
tlsEntry = ThreadLocalJSRuntime::Create();
|
||||
NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
|
||||
|
||||
PR_SetThreadPrivate(sTLSIndex, tlsEntry);
|
||||
}
|
||||
|
||||
Key key;
|
||||
JSContext* cx = nsnull;
|
||||
rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
|
||||
mIndex->KeyPath(),
|
||||
&cx, key);
|
||||
tlsEntry->Context(), key);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (key.IsUnset()) {
|
||||
|
|
|
@ -90,7 +90,7 @@ public:
|
|||
GetKeyPathValueFromStructuredData(const PRUint8* aData,
|
||||
PRUint32 aDataLength,
|
||||
const nsAString& aKeyPath,
|
||||
JSContext** aCx,
|
||||
JSContext* aCx,
|
||||
Key& aValue);
|
||||
|
||||
static nsresult
|
||||
|
|
|
@ -1067,7 +1067,6 @@ nsPluginHost::InstantiateEmbeddedPlugin(const char *aMimeType, nsIURI* aURL,
|
|||
return rv;
|
||||
|
||||
if (instance) {
|
||||
instance->Start();
|
||||
aOwner->CreateWidget();
|
||||
|
||||
// If we've got a native window, the let the plugin know about it.
|
||||
|
@ -1126,7 +1125,6 @@ nsresult nsPluginHost::InstantiateFullPagePlugin(const char *aMimeType,
|
|||
aOwner->GetWindow(win);
|
||||
|
||||
if (win && instance) {
|
||||
instance->Start();
|
||||
aOwner->CreateWidget();
|
||||
|
||||
// If we've got a native window, the let the plugin know about it.
|
||||
|
|
|
@ -658,7 +658,6 @@ nsPluginStreamListenerPeer::OnStartRequest(nsIRequest *request,
|
|||
mOwner->GetInstance(getter_AddRefs(pluginInstRefPtr));
|
||||
mPluginInstance = pluginInstRefPtr.get();
|
||||
if (mPluginInstance) {
|
||||
mPluginInstance->Start();
|
||||
mOwner->CreateWidget();
|
||||
// If we've got a native window, the let the plugin know about it.
|
||||
mOwner->SetWindow();
|
||||
|
|
|
@ -1289,10 +1289,6 @@ PluginInstanceChild::PluginWindowProcInternal(HWND hWnd,
|
|||
if ((InSendMessageEx(NULL)&(ISMEX_REPLIED|ISMEX_SEND)) == ISMEX_SEND) {
|
||||
switch(message) {
|
||||
case WM_KILLFOCUS:
|
||||
case WM_MOUSEHWHEEL:
|
||||
case WM_MOUSEWHEEL:
|
||||
case WM_HSCROLL:
|
||||
case WM_VSCROLL:
|
||||
ReplyMessage(0);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1088,7 +1088,7 @@ class ItemCounterState
|
|||
}
|
||||
|
||||
PRBool mIsCallerSecure;
|
||||
PRBool mCount;
|
||||
PRUint32 mCount;
|
||||
private:
|
||||
ItemCounterState(); // Not to be implemented
|
||||
};
|
||||
|
|
|
@ -44,11 +44,13 @@
|
|||
#include "nsIObserverService.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsIJSContextStack.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsISupportsPriority.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#include "jsprf.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsDOMJSUtils.h"
|
||||
|
@ -58,6 +60,7 @@
|
|||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
#include "Events.h"
|
||||
#include "EventTarget.h"
|
||||
|
@ -69,6 +72,7 @@ USING_WORKERS_NAMESPACE
|
|||
using mozilla::MutexAutoLock;
|
||||
using mozilla::MutexAutoUnlock;
|
||||
using mozilla::Preferences;
|
||||
using namespace mozilla::xpconnect::memory;
|
||||
|
||||
// The size of the worker runtime heaps in bytes.
|
||||
#define WORKER_RUNTIME_HEAPSIZE 32 * 1024 * 1024
|
||||
|
@ -285,6 +289,70 @@ CreateJSContextForWorker(WorkerPrivate* aWorkerPrivate)
|
|||
return workerCx;
|
||||
}
|
||||
|
||||
class WorkerMemoryReporter : public nsIMemoryMultiReporter
|
||||
{
|
||||
JSRuntime* mRuntime;
|
||||
nsCString mPathPrefix;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
WorkerMemoryReporter(WorkerPrivate* aWorkerPrivate, JSRuntime* aRuntime)
|
||||
: mRuntime(aRuntime)
|
||||
{
|
||||
NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCString escapedDomain(aWorkerPrivate->Domain());
|
||||
escapedDomain.ReplaceChar('/', '\\');
|
||||
|
||||
NS_ConvertUTF16toUTF8 escapedURL(aWorkerPrivate->ScriptURL());
|
||||
escapedURL.ReplaceChar('/', '\\');
|
||||
|
||||
// 64bit address plus '0x' plus null terminator.
|
||||
char address[21];
|
||||
JSUint32 addressSize =
|
||||
JS_snprintf(address, sizeof(address), "0x%llx", aWorkerPrivate);
|
||||
if (addressSize == JSUint32(-1)) {
|
||||
NS_WARNING("JS_snprintf failed!");
|
||||
address[0] = '\0';
|
||||
addressSize = 0;
|
||||
}
|
||||
|
||||
mPathPrefix = NS_LITERAL_CSTRING("explicit/dom/workers(") +
|
||||
escapedDomain + NS_LITERAL_CSTRING(")/worker(") +
|
||||
escapedURL + NS_LITERAL_CSTRING(", ") +
|
||||
nsDependentCString(address, addressSize) +
|
||||
NS_LITERAL_CSTRING(")/");
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
CollectReports(nsIMemoryMultiReporterCallback* aCallback,
|
||||
nsISupports* aClosure)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
JS_TriggerAllOperationCallbacks(mRuntime);
|
||||
|
||||
IterateData data;
|
||||
if (!CollectCompartmentStatsForRuntime(mRuntime, &data)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
for (CompartmentStats *stats = data.compartmentStatsVector.begin();
|
||||
stats != data.compartmentStatsVector.end();
|
||||
++stats)
|
||||
{
|
||||
ReportCompartmentStats(*stats, mPathPrefix, aCallback, aClosure);
|
||||
}
|
||||
|
||||
ReportJSStackSizeForRuntime(mRuntime, mPathPrefix, aCallback, aClosure);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(WorkerMemoryReporter, nsIMemoryMultiReporter)
|
||||
|
||||
class WorkerThreadRunnable : public nsRunnable
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
@ -311,12 +379,23 @@ public:
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
workerPrivate->DoRunLoop(cx);
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
|
||||
nsRefPtr<WorkerMemoryReporter> reporter =
|
||||
new WorkerMemoryReporter(workerPrivate, rt);
|
||||
if (NS_FAILED(NS_RegisterMemoryMultiReporter(reporter))) {
|
||||
NS_WARNING("Failed to register memory reporter!");
|
||||
reporter = nsnull;
|
||||
}
|
||||
|
||||
JSRuntime* rt = JS_GetRuntime(cx);
|
||||
workerPrivate->DoRunLoop(cx);
|
||||
|
||||
if (reporter) {
|
||||
if (NS_FAILED(NS_UnregisterMemoryMultiReporter(reporter))) {
|
||||
NS_WARNING("Failed to unregister memory reporter!");
|
||||
}
|
||||
reporter = nsnull;
|
||||
}
|
||||
|
||||
// XXX Bug 666963 - CTypes can create another JSContext for use with
|
||||
// closures, and then it holds that context in a reserved slot on the CType
|
||||
|
|
|
@ -2042,6 +2042,8 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
|
|||
{
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
#ifdef EXTRA_GC
|
||||
// Find GC bugs...
|
||||
JS_GC(aCx);
|
||||
|
@ -2054,6 +2056,8 @@ WorkerPrivate::DoRunLoop(JSContext* aCx)
|
|||
currentStatus = mStatus;
|
||||
}
|
||||
|
||||
JSAutoRequest ar(aCx);
|
||||
|
||||
#ifdef EXTRA_GC
|
||||
// Find GC bugs...
|
||||
JS_GC(aCx);
|
||||
|
@ -2093,6 +2097,8 @@ WorkerPrivate::OperationCallback(JSContext* aCx)
|
|||
{
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
JS_YieldRequest(aCx);
|
||||
|
||||
bool mayContinue = true;
|
||||
|
||||
for (;;) {
|
||||
|
@ -2126,6 +2132,8 @@ WorkerPrivate::OperationCallback(JSContext* aCx)
|
|||
if (!mControlQueue.IsEmpty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
JSAutoSuspendRequest asr(aCx);
|
||||
mCondVar.Wait(PR_MillisecondsToInterval(RemainingRunTimeMS()));
|
||||
}
|
||||
}
|
||||
|
@ -2480,6 +2488,7 @@ WorkerPrivate::RunSyncLoop(JSContext* aCx, PRUint32 aSyncLoopKey)
|
|||
MutexAutoLock lock(mMutex);
|
||||
|
||||
while (!mControlQueue.Pop(event) && !syncQueue->mQueue.Pop(event)) {
|
||||
JSAutoSuspendRequest asr(aCx);
|
||||
mCondVar.Wait();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef nsIURIRefObject_h__
|
||||
#define nsIURIRefObject_h__
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "domstubs.idl"
|
||||
|
||||
|
@ -76,6 +73,3 @@ interface nsIURIRefObject : nsISupports
|
|||
void RewriteAllURIs(in DOMString aOldPat, in DOMString aNewPat,
|
||||
in boolean aMakeRel);
|
||||
};
|
||||
|
||||
#endif /* nsIURIRefObject_h__ */
|
||||
|
||||
|
|
|
@ -393,14 +393,17 @@ abstract public class GeckoApp
|
|||
// etc., and generally mark the profile as 'clean', and then
|
||||
// dirty it again if we get an onResume.
|
||||
|
||||
|
||||
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_STOPPING));
|
||||
super.onStop();
|
||||
GeckoAppShell.putChildInBackground();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestart()
|
||||
{
|
||||
Log.i("GeckoApp", "restart");
|
||||
GeckoAppShell.putChildInForeground();
|
||||
super.onRestart();
|
||||
}
|
||||
|
||||
|
@ -668,7 +671,7 @@ abstract public class GeckoApp
|
|||
intent.setType(aMimeType);
|
||||
GeckoApp.this.
|
||||
startActivityForResult(
|
||||
Intent.createChooser(intent,"choose a file"),
|
||||
Intent.createChooser(intent, getString(R.string.choose_file)),
|
||||
FILE_PICKER_REQUEST);
|
||||
String filePickerResult = "";
|
||||
try {
|
||||
|
|
|
@ -1165,6 +1165,52 @@ public class GeckoAppShell
|
|||
return result;
|
||||
}
|
||||
|
||||
public static void putChildInBackground() {
|
||||
try {
|
||||
File cgroupFile = new File("/proc" + android.os.Process.myPid() + "/cgroup");
|
||||
BufferedReader br = new BufferedReader(new FileReader(cgroupFile));
|
||||
String[] cpuLine = br.readLine().split("/");
|
||||
br.close();
|
||||
final String backgroundGroup = cpuLine.length == 2 ? cpuLine[1] : "";
|
||||
GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
|
||||
public boolean callback(int pid) {
|
||||
if (pid != android.os.Process.myPid()) {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(
|
||||
new File("/dev/cpuctl/" + backgroundGroup +"/tasks"));
|
||||
fos.write(new Integer(pid).toString().getBytes());
|
||||
fos.close();
|
||||
} catch(Exception e) {
|
||||
Log.e("GeckoAppShell", "error putting child in the background", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
EnumerateGeckoProcesses(visitor);
|
||||
} catch (Exception e) {
|
||||
Log.e("GeckoInputStream", "error reading cgroup", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void putChildInForeground() {
|
||||
GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
|
||||
public boolean callback(int pid) {
|
||||
if (pid != android.os.Process.myPid()) {
|
||||
try {
|
||||
FileOutputStream fos = new FileOutputStream(new File("/dev/cpuctl/tasks"));
|
||||
fos.write(new Integer(pid).toString().getBytes());
|
||||
fos.close();
|
||||
} catch(Exception e) {
|
||||
Log.e("GeckoAppShell", "error putting child in the foreground", e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
EnumerateGeckoProcesses(visitor);
|
||||
}
|
||||
|
||||
public static void killAnyZombies() {
|
||||
GeckoProcessesVisitor visitor = new GeckoProcessesVisitor() {
|
||||
public boolean callback(int pid) {
|
||||
|
|
|
@ -19,3 +19,5 @@
|
|||
|
||||
<!ENTITY launcher_shortcuts_title "&brandShortName; Web Apps">
|
||||
<!ENTITY launcher_shortcuts_empty "No web apps were found">
|
||||
|
||||
<!ENTITY choose_file "Choose File">
|
||||
|
|
|
@ -24,4 +24,6 @@
|
|||
|
||||
<string name="launcher_shortcuts_title">&launcher_shortcuts_title;</string>
|
||||
<string name="launcher_shortcuts_empty">&launcher_shortcuts_empty;</string>
|
||||
|
||||
<string name="choose_file">&choose_file;</string>
|
||||
</resources>
|
||||
|
|
|
@ -10,6 +10,8 @@ In this order:
|
|||
angle-intrinsic-msvc2005.patch - work around a MSVC 2005 compile error
|
||||
angle-amap-arev-fix.patch - plain bug fix, this is ANGLE r699
|
||||
angle-r702.patch - this is ANGLE r702
|
||||
angle-limit-identifiers-to-250-chars.patch - see bug 675625
|
||||
angle-r712.patch - this is ANGLE r712
|
||||
|
||||
In addition to these patches, the Makefile.in files are ours, they're not present in upsteam ANGLE.
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
diff --git a/gfx/angle/src/compiler/preprocessor/scanner.h b/gfx/angle/src/compiler/preprocessor/scanner.h
|
||||
--- a/gfx/angle/src/compiler/preprocessor/scanner.h
|
||||
+++ b/gfx/angle/src/compiler/preprocessor/scanner.h
|
||||
@@ -44,17 +44,19 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILI
|
||||
//
|
||||
// scanner.h
|
||||
//
|
||||
|
||||
#if !defined(__SCANNER_H)
|
||||
#define __SCANNER_H 1
|
||||
|
||||
// These lengths do not include the NULL terminator.
|
||||
-#define MAX_SYMBOL_NAME_LEN 256
|
||||
+// see bug 675625: NVIDIA driver crash with lengths >= 253
|
||||
+// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
|
||||
+#define MAX_SYMBOL_NAME_LEN 250
|
||||
#define MAX_STRING_LEN 511
|
||||
|
||||
#include "compiler/preprocessor/parser.h"
|
||||
|
||||
// Not really atom table stuff but needed first...
|
||||
|
||||
typedef struct SourceLoc_Rec {
|
||||
unsigned short file, line;
|
|
@ -0,0 +1,42 @@
|
|||
# HG changeset patch
|
||||
# Parent 88a5c8710f5cffd568bc21226118cb567850ce28
|
||||
diff --git a/gfx/angle/src/libGLESv2/VertexDataManager.cpp b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
|
||||
--- a/gfx/angle/src/libGLESv2/VertexDataManager.cpp
|
||||
+++ b/gfx/angle/src/libGLESv2/VertexDataManager.cpp
|
||||
@@ -134,34 +134,34 @@ GLenum VertexDataManager::prepareVertexD
|
||||
if (staticBuffer->size() == 0)
|
||||
{
|
||||
int totalCount = buffer->size() / attribs[i].stride();
|
||||
staticBuffer->addRequiredSpace(spaceRequired(attribs[i], totalCount));
|
||||
}
|
||||
else if (staticBuffer->lookupAttribute(attribs[i]) == -1)
|
||||
{
|
||||
// This static buffer doesn't have matching attributes, so fall back to using the streaming buffer
|
||||
- buffer->invalidateStaticData();
|
||||
-
|
||||
// Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer
|
||||
for (int previous = 0; previous < i; previous++)
|
||||
{
|
||||
if (translated[previous].active && attribs[previous].mArrayEnabled)
|
||||
{
|
||||
Buffer *previousBuffer = attribs[previous].mBoundBuffer.get();
|
||||
StaticVertexBuffer *previousStaticBuffer = previousBuffer ? previousBuffer->getStaticVertexBuffer() : NULL;
|
||||
|
||||
if (staticBuffer == previousStaticBuffer)
|
||||
{
|
||||
mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[previous], count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
|
||||
+
|
||||
+ buffer->invalidateStaticData();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,7 +49,9 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#define __SCANNER_H 1
|
||||
|
||||
// These lengths do not include the NULL terminator.
|
||||
#define MAX_SYMBOL_NAME_LEN 256
|
||||
// see bug 675625: NVIDIA driver crash with lengths >= 253
|
||||
// this is only an interim fix, the real fix is name mapping, see ANGLE bug 144 / r619
|
||||
#define MAX_SYMBOL_NAME_LEN 250
|
||||
#define MAX_STRING_LEN 511
|
||||
|
||||
#include "compiler/preprocessor/parser.h"
|
||||
|
|
|
@ -139,8 +139,6 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
|
|||
else if (staticBuffer->lookupAttribute(attribs[i]) == -1)
|
||||
{
|
||||
// This static buffer doesn't have matching attributes, so fall back to using the streaming buffer
|
||||
buffer->invalidateStaticData();
|
||||
|
||||
// Add the space of all previous attributes belonging to the invalidated static buffer to the streaming buffer
|
||||
for (int previous = 0; previous < i; previous++)
|
||||
{
|
||||
|
@ -157,6 +155,8 @@ GLenum VertexDataManager::prepareVertexData(GLint start, GLsizei count, Translat
|
|||
}
|
||||
|
||||
mStreamingBuffer->addRequiredSpace(spaceRequired(attribs[i], count));
|
||||
|
||||
buffer->invalidateStaticData();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -65,9 +65,9 @@ public:
|
|||
// aLength is the length of the aText array and also the length of the aBreakBefore
|
||||
// output array.
|
||||
virtual void GetJISx4051Breaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore) = 0;
|
||||
PRUint8* aBreakBefore) = 0;
|
||||
virtual void GetJISx4051Breaks(const PRUint8* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore) = 0;
|
||||
PRUint8* aBreakBefore) = 0;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsILineBreaker, NS_ILINEBREAKER_IID)
|
||||
|
|
|
@ -42,12 +42,12 @@
|
|||
|
||||
void
|
||||
NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
NS_ASSERTION(aText, "aText shouldn't be null");
|
||||
TextBreakLocatorRef breakLocator;
|
||||
|
||||
memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
|
||||
memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRUint8));
|
||||
|
||||
OSStatus status = UCCreateTextBreakLocator(NULL, 0, kUCTextBreakLineMask, &breakLocator);
|
||||
|
||||
|
|
|
@ -47,6 +47,6 @@
|
|||
*/
|
||||
void
|
||||
NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore);
|
||||
PRUint8* aBreakBefore);
|
||||
|
||||
#endif /* nsComplexBreaker_h__ */
|
||||
|
|
|
@ -786,7 +786,7 @@ nsJISx4051LineBreaker::WordMove(const PRUnichar* aText, PRUint32 aLen,
|
|||
}
|
||||
|
||||
PRInt32 ret;
|
||||
nsAutoTArray<PRPackedBool, 2000> breakState;
|
||||
nsAutoTArray<PRUint8, 2000> breakState;
|
||||
if (!textNeedsJISx4051 || !breakState.AppendElements(end - begin)) {
|
||||
// No complex text character, do not try to do complex line break.
|
||||
// (This is required for serializers. See Bug #344816.)
|
||||
|
@ -833,7 +833,7 @@ nsJISx4051LineBreaker::Prev(const PRUnichar* aText, PRUint32 aLen,
|
|||
|
||||
void
|
||||
nsJISx4051LineBreaker::GetJISx4051Breaks(const PRUnichar* aChars, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
PRUint32 cur;
|
||||
PRInt8 lastClass = CLASS_NONE;
|
||||
|
@ -890,7 +890,7 @@ nsJISx4051LineBreaker::GetJISx4051Breaks(const PRUnichar* aChars, PRUint32 aLeng
|
|||
|
||||
void
|
||||
nsJISx4051LineBreaker::GetJISx4051Breaks(const PRUint8* aChars, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
PRUint32 cur;
|
||||
PRInt8 lastClass = CLASS_NONE;
|
||||
|
|
|
@ -53,9 +53,9 @@ public:
|
|||
PRInt32 Prev( const PRUnichar* aText, PRUint32 aLen, PRUint32 aPos);
|
||||
|
||||
virtual void GetJISx4051Breaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore);
|
||||
PRUint8* aBreakBefore);
|
||||
virtual void GetJISx4051Breaks(const PRUint8* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore);
|
||||
PRUint8* aBreakBefore);
|
||||
|
||||
private:
|
||||
PRInt32 WordMove(const PRUnichar* aText, PRUint32 aLen, PRUint32 aPos,
|
||||
|
|
|
@ -45,11 +45,11 @@
|
|||
|
||||
void
|
||||
NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
NS_ASSERTION(aText, "aText shouldn't be null");
|
||||
|
||||
memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRPackedBool));
|
||||
memset(aBreakBefore, PR_FALSE, aLength * sizeof(PRUint8));
|
||||
|
||||
nsAutoTArray<PangoLogAttr, 2000> attrBuffer;
|
||||
if (!attrBuffer.AppendElements(aLength + 1))
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
void
|
||||
NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
NS_ASSERTION(aText, "aText shouldn't be null");
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
|
||||
void
|
||||
NS_GetComplexLineBreaks(const PRUnichar* aText, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore)
|
||||
PRUint8* aBreakBefore)
|
||||
{
|
||||
NS_ASSERTION(aText, "aText shouldn't be null");
|
||||
|
||||
|
|
|
@ -1019,7 +1019,7 @@ ifdef MOZ_ETW
|
|||
ETWProvider.h ETWProvider.rc ETWProvider.mof: ETWProvider.man
|
||||
$(MC) -um -mof $^
|
||||
|
||||
$(CPPSRCS:%.cpp=%.$(OBJ_SUFFIX)): ETWProvider.h
|
||||
jsprobes.$(OBJ_SUFFIX): ETWProvider.h
|
||||
|
||||
ETWProvider.res: ETWProvider.rc
|
||||
$(RC) -r -i "$(SDKDIR)Include" $^
|
||||
|
|
|
@ -192,7 +192,7 @@ ifdef CPP_UNIT_TESTS
|
|||
CPPSRCS += $(CPP_UNIT_TESTS)
|
||||
SIMPLE_PROGRAMS += $(CPP_UNIT_TESTS:.cpp=$(BIN_SUFFIX))
|
||||
INCLUDES += -I$(DIST)/include/testing
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS)
|
||||
LIBS += $(XPCOM_GLUE_LDOPTS) $(NSPR_LIBS) $(MOZ_JS_LIBS)
|
||||
|
||||
# ...and run them the usual way
|
||||
check::
|
||||
|
|
|
@ -5041,10 +5041,11 @@ dnl ========================================================
|
|||
dnl callgrind
|
||||
dnl ========================================================
|
||||
MOZ_ARG_ENABLE_BOOL(callgrind,
|
||||
[ --enable-callgrind Enable callgrind profiling],
|
||||
[ --enable-callgrind Enable callgrind profiling. Implies --enable-profiling.],
|
||||
MOZ_CALLGRIND=1,
|
||||
MOZ_CALLGRIND= )
|
||||
if test -n "$MOZ_CALLGRIND"; then
|
||||
MOZ_PROFILING=1
|
||||
AC_DEFINE(MOZ_CALLGRIND)
|
||||
fi
|
||||
|
||||
|
|
|
@ -746,9 +746,6 @@ JS_PUBLIC_API(JSRuntime *)
|
|||
JS_NewRuntime(uint32 maxbytes)
|
||||
{
|
||||
if (!js_NewRuntimeWasCalled) {
|
||||
#ifdef MOZ_ETW
|
||||
EventRegisterMozillaSpiderMonkey();
|
||||
#endif
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* This code asserts that the numbers associated with the error names
|
||||
|
@ -789,18 +786,22 @@ JS_NewRuntime(uint32 maxbytes)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
Probes::createRuntime(rt);
|
||||
return rt;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_DestroyRuntime(JSRuntime *rt)
|
||||
{
|
||||
Probes::destroyRuntime(rt);
|
||||
Foreground::delete_(rt);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_ShutDown(void)
|
||||
{
|
||||
Probes::shutdown();
|
||||
|
||||
#ifdef MOZ_TRACEVIS
|
||||
StopTraceVis();
|
||||
#endif
|
||||
|
@ -809,10 +810,6 @@ JS_ShutDown(void)
|
|||
js_CleanupLocks();
|
||||
#endif
|
||||
PRMJ_NowShutdown();
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
EventUnregisterMozillaSpiderMonkey();
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void *)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
|
||||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
|
@ -77,7 +78,9 @@ class HashTableEntry {
|
|||
|
||||
public:
|
||||
HashTableEntry() : keyHash(0), t() {}
|
||||
HashTableEntry(MoveRef<HashTableEntry> rhs) : keyHash(rhs->keyHash), t(Move(rhs->t)) { }
|
||||
void operator=(const HashTableEntry &rhs) { keyHash = rhs.keyHash; t = rhs.t; }
|
||||
void operator=(MoveRef<HashTableEntry> rhs) { keyHash = rhs->keyHash; t = Move(rhs->t); }
|
||||
|
||||
NonConstT t;
|
||||
|
||||
|
@ -552,7 +555,7 @@ class HashTable : private AllocPolicy
|
|||
for (Entry *src = oldTable, *end = src + oldCap; src != end; ++src) {
|
||||
if (src->isLive()) {
|
||||
src->unsetCollision();
|
||||
findFreeEntry(src->getKeyHash()) = *src;
|
||||
findFreeEntry(src->getKeyHash()) = Move(*src);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -881,6 +884,12 @@ class HashMapEntry
|
|||
public:
|
||||
HashMapEntry() : key(), value() {}
|
||||
HashMapEntry(const Key &k, const Value &v) : key(k), value(v) {}
|
||||
HashMapEntry(MoveRef<HashMapEntry> rhs)
|
||||
: key(Move(rhs->key)), value(Move(rhs->value)) { }
|
||||
void operator=(MoveRef<HashMapEntry> rhs) {
|
||||
const_cast<Key &>(key) = Move(rhs->key);
|
||||
value = Move(rhs->value);
|
||||
}
|
||||
|
||||
const Key key;
|
||||
Value value;
|
||||
|
@ -1019,6 +1028,15 @@ class HashMap
|
|||
return true;
|
||||
}
|
||||
|
||||
bool add(AddPtr &p, const Key &k, MoveRef<Value> v) {
|
||||
Entry *pentry;
|
||||
if (!impl.add(p, &pentry))
|
||||
return false;
|
||||
const_cast<Key &>(pentry->key) = k;
|
||||
pentry->value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool add(AddPtr &p, const Key &k) {
|
||||
Entry *pentry;
|
||||
if (!impl.add(p, &pentry))
|
||||
|
|
|
@ -33,6 +33,14 @@
|
|||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
#include "jswin.h"
|
||||
#include <evntprov.h>
|
||||
|
||||
/* Generated from ETWProvider.man */
|
||||
#include "ETWProvider.h"
|
||||
#endif
|
||||
|
||||
#include "jsapi.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsatom.h"
|
||||
|
@ -180,3 +188,243 @@ Probes::stopProfiling()
|
|||
Shark::Stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
/*
|
||||
* ETW (Event Tracing for Windows)
|
||||
*
|
||||
* These are here rather than in the .h file to avoid having to include
|
||||
* windows.h in a header.
|
||||
*/
|
||||
bool
|
||||
Probes::ETWCallTrackingActive(JSContext *cx)
|
||||
{
|
||||
return MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry);
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCreateRuntime(JSRuntime *rt)
|
||||
{
|
||||
static bool registered = false;
|
||||
if (!registered) {
|
||||
EventRegisterMozillaSpiderMonkey();
|
||||
registered = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWDestroyRuntime(JSRuntime *rt)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWShutdown()
|
||||
{
|
||||
EventUnregisterMozillaSpiderMonkey();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
|
||||
{
|
||||
int lineno = script ? script->lineno : -1;
|
||||
JSAutoByteString bytes;
|
||||
return (EventWriteEvtFunctionEntry(ScriptFilename(script), lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
|
||||
{
|
||||
int lineno = script ? script->lineno : -1;
|
||||
JSAutoByteString bytes;
|
||||
return (EventWriteEvtFunctionExit(ScriptFilename(script), lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS);
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCreateObject(JSContext *cx, JSObject *obj)
|
||||
{
|
||||
int lineno;
|
||||
const char * script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
return EventWriteEvtObjectCreate(script_filename, lineno,
|
||||
ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
|
||||
obj ? obj->slotsAndStructSize() : 0) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWFinalizeObject(JSObject *obj)
|
||||
{
|
||||
return EventWriteEvtObjectFinalize(ObjectClassname(obj),
|
||||
reinterpret_cast<JSUint64>(obj)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize)
|
||||
{
|
||||
int lineno;
|
||||
const char *script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
return EventWriteEvtObjectResize(script_filename, lineno,
|
||||
ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
|
||||
oldSize, newSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCreateString(JSContext *cx, JSString *string, size_t length)
|
||||
{
|
||||
int lineno;
|
||||
const char *script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
return EventWriteEvtStringCreate(script_filename, lineno,
|
||||
reinterpret_cast<JSUint64>(string), length) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWFinalizeString(JSString *string)
|
||||
{
|
||||
return EventWriteEvtStringFinalize(reinterpret_cast<JSUint64>(string), string->length()) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCompileScriptBegin(const char *filename, int lineno)
|
||||
{
|
||||
return EventWriteEvtScriptCompileBegin(filename, lineno) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCompileScriptEnd(const char *filename, int lineno)
|
||||
{
|
||||
return EventWriteEvtScriptCompileEnd(filename, lineno) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCalloutBegin(JSContext *cx, JSFunction *fun)
|
||||
{
|
||||
const char *script_filename;
|
||||
int lineno;
|
||||
JSAutoByteString bytes;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
return EventWriteEvtCalloutBegin(script_filename,
|
||||
lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCalloutEnd(JSContext *cx, JSFunction *fun)
|
||||
{
|
||||
const char *script_filename;
|
||||
int lineno;
|
||||
JSAutoByteString bytes;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
return EventWriteEvtCalloutEnd(script_filename,
|
||||
lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes)
|
||||
{
|
||||
return EventWriteEvtMemoryAcquire(reinterpret_cast<JSUint64>(cx->compartment),
|
||||
reinterpret_cast<JSUint64>(address),
|
||||
nbytes) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes)
|
||||
{
|
||||
return EventWriteEvtMemoryRelease(reinterpret_cast<JSUint64>(cx->compartment),
|
||||
reinterpret_cast<JSUint64>(address),
|
||||
nbytes) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCStart(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCStart(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCEnd(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCEnd(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCStartMarkPhase(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCStartMarkPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCEndMarkPhase(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCEndMarkPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCStartSweepPhase(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCStartSweepPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWGCEndSweepPhase(JSCompartment *compartment)
|
||||
{
|
||||
return EventWriteEvtGCEndSweepPhase(reinterpret_cast<JSUint64>(compartment)) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCustomMark(JSString *string)
|
||||
{
|
||||
const jschar *chars = string->getCharsZ(NULL);
|
||||
return !chars || EventWriteEvtCustomString(chars) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCustomMark(const char *string)
|
||||
{
|
||||
return EventWriteEvtCustomANSIString(string) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWCustomMark(int marker)
|
||||
{
|
||||
return EventWriteEvtCustomInt(marker) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWStartExecution(JSContext *cx, JSScript *script)
|
||||
{
|
||||
int lineno = script ? script->lineno : -1;
|
||||
return EventWriteEvtExecuteStart(ScriptFilename(script), lineno) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWStopExecution(JSContext *cx, JSScript *script)
|
||||
{
|
||||
int lineno = script ? script->lineno : -1;
|
||||
return EventWriteEvtExecuteDone(ScriptFilename(script), lineno) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
bool
|
||||
Probes::ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
|
||||
{
|
||||
return EventWriteEvtHeapResize(reinterpret_cast<JSUint64>(compartment),
|
||||
oldSize, newSize) == ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -44,14 +44,6 @@
|
|||
|
||||
namespace js {
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
#include "jswin.h"
|
||||
#include <evntprov.h>
|
||||
|
||||
/* Generated from ETWProvider.man */
|
||||
#include "ETWProvider.h"
|
||||
#endif
|
||||
|
||||
class Probes {
|
||||
static bool ProfilingActive;
|
||||
static bool controlProfilers(JSContext *cx, bool toState);
|
||||
|
@ -99,6 +91,10 @@ class Probes {
|
|||
static void handleFunctionReturn(JSContext *cx, JSFunction *fun, JSScript *script);
|
||||
static void finalizeObjectImpl(JSObject *obj);
|
||||
public:
|
||||
static bool createRuntime(JSRuntime *rt);
|
||||
static bool destroyRuntime(JSRuntime *rt);
|
||||
static bool shutdown();
|
||||
|
||||
/*
|
||||
* Pause/resume whatever profiling mechanism is currently compiled
|
||||
* in, if applicable. This will not affect things like dtrace.
|
||||
|
@ -176,8 +172,74 @@ class Probes {
|
|||
|
||||
static bool startProfiling();
|
||||
static void stopProfiling();
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
// ETW Handlers
|
||||
static bool ETWCreateRuntime(JSRuntime *rt);
|
||||
static bool ETWDestroyRuntime(JSRuntime *rt);
|
||||
static bool ETWShutdown();
|
||||
static bool ETWCallTrackingActive(JSContext *cx);
|
||||
static bool ETWEnterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
|
||||
static bool ETWExitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter);
|
||||
static bool ETWCreateObject(JSContext *cx, JSObject *obj);
|
||||
static bool ETWFinalizeObject(JSObject *obj);
|
||||
static bool ETWResizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSize);
|
||||
static bool ETWCreateString(JSContext *cx, JSString *string, size_t length);
|
||||
static bool ETWFinalizeString(JSString *string);
|
||||
static bool ETWCompileScriptBegin(const char *filename, int lineno);
|
||||
static bool ETWCompileScriptEnd(const char *filename, int lineno);
|
||||
static bool ETWCalloutBegin(JSContext *cx, JSFunction *fun);
|
||||
static bool ETWCalloutEnd(JSContext *cx, JSFunction *fun);
|
||||
static bool ETWAcquireMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
static bool ETWReleaseMemory(JSContext *cx, void *address, size_t nbytes);
|
||||
static bool ETWGCStart(JSCompartment *compartment);
|
||||
static bool ETWGCEnd(JSCompartment *compartment);
|
||||
static bool ETWGCStartMarkPhase(JSCompartment *compartment);
|
||||
static bool ETWGCEndMarkPhase(JSCompartment *compartment);
|
||||
static bool ETWGCStartSweepPhase(JSCompartment *compartment);
|
||||
static bool ETWGCEndSweepPhase(JSCompartment *compartment);
|
||||
static bool ETWCustomMark(JSString *string);
|
||||
static bool ETWCustomMark(const char *string);
|
||||
static bool ETWCustomMark(int marker);
|
||||
static bool ETWStartExecution(JSContext *cx, JSScript *script);
|
||||
static bool ETWStopExecution(JSContext *cx, JSScript *script);
|
||||
static bool ETWResizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize);
|
||||
#endif
|
||||
};
|
||||
|
||||
inline bool
|
||||
Probes::createRuntime(JSRuntime *rt)
|
||||
{
|
||||
bool ok = true;
|
||||
#ifdef MOZ_ETW
|
||||
if (!ETWCreateRuntime(rt))
|
||||
ok = false;
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::destroyRuntime(JSRuntime *rt)
|
||||
{
|
||||
bool ok = true;
|
||||
#ifdef MOZ_ETW
|
||||
if (!ETWDestroyRuntime(rt))
|
||||
ok = false;
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::shutdown()
|
||||
{
|
||||
bool ok = true;
|
||||
#ifdef MOZ_ETW
|
||||
if (!ETWShutdown())
|
||||
ok = false;
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
inline bool
|
||||
Probes::callTrackingActive(JSContext *cx)
|
||||
{
|
||||
|
@ -190,7 +252,7 @@ Probes::callTrackingActive(JSContext *cx)
|
|||
return true;
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive && MCGEN_ENABLE_CHECK(MozillaSpiderMonkey_Context, EvtFunctionEntry))
|
||||
if (ProfilingActive && ETWCallTrackingActive(cx))
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
|
@ -225,15 +287,8 @@ Probes::enterJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter
|
|||
cx->doFunctionCallback(fun, script, counter);
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
JSScript* script = fun ? FUN_SCRIPT(fun) : NULL;
|
||||
int lineno = script ? script->lineno : -1;
|
||||
JSAutoByteString bytes;
|
||||
if (EventWriteEvtFunctionEntry(ScriptFilename(script), lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWEnterJSFun(cx, fun, script, counter))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -254,15 +309,8 @@ Probes::exitJSFun(JSContext *cx, JSFunction *fun, JSScript *script, int counter)
|
|||
cx->doFunctionCallback(fun, script, counter);
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
JSScript* script = fun ? FUN_SCRIPT(fun) : NULL;
|
||||
int lineno = script ? script->lineno : -1;
|
||||
JSAutoByteString bytes;
|
||||
if (EventWriteEvtFunctionExit(ScriptFilename(script), lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWExitJSFun(cx, fun, script, counter))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -274,9 +322,8 @@ Probes::resizeHeap(JSCompartment *compartment, size_t oldSize, size_t newSize)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtHeapResize(reinterpret_cast<JSUint64>(compartment), oldSize, newSize) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWResizeHeap(compartment, oldSize, newSize))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -292,16 +339,8 @@ Probes::createObject(JSContext *cx, JSObject *obj)
|
|||
JAVASCRIPT_OBJECT_CREATE(ObjectClassname(obj), (uintptr_t)obj);
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
int lineno;
|
||||
const char * script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
if (EventWriteEvtObjectCreate(script_filename, lineno,
|
||||
ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
|
||||
obj ? obj->slotsAndStructSize() : 0) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWCreateObject(cx, obj))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -321,10 +360,8 @@ Probes::finalizeObject(JSObject *obj)
|
|||
}
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtObjectFinalize(ObjectClassname(obj),
|
||||
reinterpret_cast<JSUint64>(obj)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWFinalizeObject(obj))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -336,16 +373,8 @@ Probes::resizeObject(JSContext *cx, JSObject *obj, size_t oldSize, size_t newSiz
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
int lineno;
|
||||
const char *script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
if (EventWriteEvtObjectResize(script_filename, lineno,
|
||||
ObjectClassname(obj), reinterpret_cast<JSUint64>(obj),
|
||||
oldSize, newSize) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWResizeObject(cx, obj, oldSize, newSize))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -357,15 +386,8 @@ Probes::createString(JSContext *cx, JSString *string, size_t length)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
int lineno;
|
||||
const char *script_filename;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
if (EventWriteEvtStringCreate(script_filename, lineno,
|
||||
reinterpret_cast<JSUint64>(string), length) != ERROR_SUCCESS)
|
||||
ok = 0;
|
||||
}
|
||||
if (ProfilingActive && !ETWCreateString(cx, string, length))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -377,9 +399,8 @@ Probes::finalizeString(JSString *string)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtStringFinalize(reinterpret_cast<JSUint64>(string), string->length()) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWFinalizeString(string))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -391,9 +412,8 @@ Probes::compileScriptBegin(JSContext *cx, const char *filename, int lineno)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtScriptCompileBegin(filename, lineno) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWCompileScriptBegin(filename, lineno))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -405,9 +425,8 @@ Probes::compileScriptEnd(JSContext *cx, JSScript *script, const char *filename,
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtScriptCompileEnd(filename, lineno) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWCompileScriptEnd(filename, lineno))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -419,18 +438,8 @@ Probes::calloutBegin(JSContext *cx, JSFunction *fun)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
const char *script_filename;
|
||||
int lineno;
|
||||
JSAutoByteString bytes;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
if (EventWriteEvtCalloutBegin(script_filename,
|
||||
lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWCalloutBegin(cx, fun))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -442,18 +451,8 @@ Probes::calloutEnd(JSContext *cx, JSFunction *fun)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
const char *script_filename;
|
||||
int lineno;
|
||||
JSAutoByteString bytes;
|
||||
current_location(cx, &lineno, &script_filename);
|
||||
|
||||
if (EventWriteEvtCalloutEnd(script_filename,
|
||||
lineno,
|
||||
ObjectClassname((JSObject *)fun),
|
||||
FunctionName(cx, fun, &bytes)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWCalloutEnd(cx, fun))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -465,11 +464,8 @@ Probes::acquireMemory(JSContext *cx, void *address, size_t nbytes)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtMemoryAcquire(reinterpret_cast<JSUint64>(cx->compartment),
|
||||
reinterpret_cast<JSUint64>(address),
|
||||
nbytes) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWAcquireMemory(cx, address, nbytes))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -481,11 +477,8 @@ Probes::releaseMemory(JSContext *cx, void *address, size_t nbytes)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtMemoryRelease(reinterpret_cast<JSUint64>(cx->compartment),
|
||||
reinterpret_cast<JSUint64>(address),
|
||||
nbytes) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWReleaseMemory(cx, address, nbytes))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -497,9 +490,8 @@ Probes::GCStart(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCStart(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCStart(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -511,9 +503,8 @@ Probes::GCEnd(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCEnd(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCEnd(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -525,9 +516,8 @@ Probes::GCStartMarkPhase(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCStartMarkPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCStartMarkPhase(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -539,9 +529,8 @@ Probes::GCEndMarkPhase(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCEndMarkPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCEndMarkPhase(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -553,9 +542,8 @@ Probes::GCStartSweepPhase(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCStartSweepPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCStartSweepPhase(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -567,9 +555,8 @@ Probes::GCEndSweepPhase(JSCompartment *compartment)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtGCEndSweepPhase(reinterpret_cast<JSUint64>(compartment)) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWGCEndSweepPhase(compartment))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -581,11 +568,8 @@ Probes::CustomMark(JSString *string)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
const jschar *chars = string->getCharsZ(NULL);
|
||||
if (!chars || EventWriteEvtCustomString(chars) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWCustomMark(string))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -597,9 +581,8 @@ Probes::CustomMark(const char *string)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtCustomANSIString(string) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWCustomMark(string))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -611,9 +594,8 @@ Probes::CustomMark(int marker)
|
|||
bool ok = true;
|
||||
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive)
|
||||
if (EventWriteEvtCustomInt(marker) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
if (ProfilingActive && !ETWCustomMark(marker))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -630,11 +612,8 @@ Probes::startExecution(JSContext *cx, JSScript *script)
|
|||
script->lineno);
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
int lineno = script ? script->lineno : -1;
|
||||
if (EventWriteEvtExecuteStart(ScriptFilename(script), lineno) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWStartExecution(cx, script))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
@ -651,11 +630,8 @@ Probes::stopExecution(JSContext *cx, JSScript *script)
|
|||
script->lineno);
|
||||
#endif
|
||||
#ifdef MOZ_ETW
|
||||
if (ProfilingActive) {
|
||||
int lineno = script ? script->lineno : -1;
|
||||
if (EventWriteEvtExecuteDone(ScriptFilename(script), lineno) != ERROR_SUCCESS)
|
||||
ok = false;
|
||||
}
|
||||
if (ProfilingActive && !ETWStopExecution(cx, script))
|
||||
ok = false;
|
||||
#endif
|
||||
|
||||
return ok;
|
||||
|
|
115
js/src/jsutil.h
115
js/src/jsutil.h
|
@ -693,6 +693,121 @@ PodEqual(T *one, T *two, size_t len)
|
|||
*/
|
||||
enum MaybeReportError { REPORT_ERROR = true, DONT_REPORT_ERROR = false };
|
||||
|
||||
/*
|
||||
* "Move" References
|
||||
*
|
||||
* Some types can be copied much more efficiently if we know the original's
|
||||
* value need not be preserved --- that is, if we are doing a "move", not a
|
||||
* "copy". For example, if we have:
|
||||
*
|
||||
* Vector<T> u;
|
||||
* Vector<T> v(u);
|
||||
*
|
||||
* the constructor for v must apply a copy constructor to each element of u ---
|
||||
* taking time linear in the length of u. However, if we know we will not need u
|
||||
* any more once v has been initialized, then we could initialize v very
|
||||
* efficiently simply by stealing u's dynamically allocated buffer and giving it
|
||||
* to v --- a constant-time operation, regardless of the size of u.
|
||||
*
|
||||
* Moves often appear in container implementations. For example, when we append
|
||||
* to a vector, we may need to resize its buffer. This entails moving each of
|
||||
* its extant elements from the old, smaller buffer to the new, larger buffer.
|
||||
* But once the elements have been migrated, we're just going to throw away the
|
||||
* old buffer; we don't care if they still have their values. So if the vector's
|
||||
* element type can implement "move" more efficiently than "copy", the vector
|
||||
* resizing should by all means use a "move" operation. Hash tables also need to
|
||||
* be resized.
|
||||
*
|
||||
* The details of the optimization, and whether it's worth applying, vary from
|
||||
* one type to the next. And while some constructor calls are moves, many really
|
||||
* are copies, and can't be optimized this way. So we need:
|
||||
*
|
||||
* 1) a way for a particular invocation of a copy constructor to say that it's
|
||||
* really a move, and that the value of the original isn't important
|
||||
* afterwards (althought it must still be safe to destroy); and
|
||||
*
|
||||
* 2) a way for a type (like Vector) to announce that it can be moved more
|
||||
* efficiently than it can be copied, and provide an implementation of that
|
||||
* move operation.
|
||||
*
|
||||
* The Move(T &) function takes a reference to a T, and returns an MoveRef<T>
|
||||
* referring to the same value; that's 1). An MoveRef<T> is simply a reference
|
||||
* to a T, annotated to say that a copy constructor applied to it may move that
|
||||
* T, instead of copying it. Finally, a constructor that accepts an MoveRef<T>
|
||||
* should perform a more efficient move, instead of a copy, providing 2).
|
||||
*
|
||||
* So, where we might define a copy constructor for a class C like this:
|
||||
*
|
||||
* C(const C &rhs) { ... copy rhs to this ... }
|
||||
*
|
||||
* we would declare a move constructor like this:
|
||||
*
|
||||
* C(MoveRef<C> rhs) { ... move rhs to this ... }
|
||||
*
|
||||
* And where we might perform a copy like this:
|
||||
*
|
||||
* C c2(c1);
|
||||
*
|
||||
* we would perform a move like this:
|
||||
*
|
||||
* C c2(Move(c1))
|
||||
*
|
||||
* Note that MoveRef<T> implicitly converts to T &, so you can pass an
|
||||
* MoveRef<T> to an ordinary copy constructor for a type that doesn't support a
|
||||
* special move constructor, and you'll just get a copy. This means that
|
||||
* templates can use Move whenever they know they won't use the original value
|
||||
* any more, even if they're not sure whether the type at hand has a specialized
|
||||
* move constructor. If it doesn't, the MoveRef<T> will just convert to a T &,
|
||||
* and the ordinary copy constructor will apply.
|
||||
*
|
||||
* A class with a move constructor can also provide a move assignment operator,
|
||||
* which runs this's destructor, and then applies the move constructor to
|
||||
* *this's memory. A typical definition:
|
||||
*
|
||||
* C &operator=(MoveRef<C> rhs) {
|
||||
* this->~C();
|
||||
* new(this) C(rhs);
|
||||
* return *this;
|
||||
* }
|
||||
*
|
||||
* With that in place, one can write move assignments like this:
|
||||
*
|
||||
* c2 = Move(c1);
|
||||
*
|
||||
* This destroys c1, moves c1's value to c2, and leaves c1 in an undefined but
|
||||
* destructible state.
|
||||
*
|
||||
* This header file defines MoveRef and Move in the js namespace. It's up to
|
||||
* individual containers to annotate moves as such, by calling Move; and it's up
|
||||
* to individual types to define move constructors.
|
||||
*
|
||||
* One hint: if you're writing a move constructor where the type has members
|
||||
* that should be moved themselves, it's much nicer to write this:
|
||||
*
|
||||
* C(MoveRef<C> c) : x(c->x), y(c->y) { }
|
||||
*
|
||||
* than the equivalent:
|
||||
*
|
||||
* C(MoveRef<C> c) { new(&x) X(c->x); new(&y) Y(c->y); }
|
||||
*
|
||||
* especially since GNU C++ fails to notice that this does indeed initialize x
|
||||
* and y, which may matter if they're const.
|
||||
*/
|
||||
template<typename T>
|
||||
class MoveRef {
|
||||
public:
|
||||
typedef T Referent;
|
||||
explicit MoveRef(T &t) : pointer(&t) { }
|
||||
T &operator*() const { return *pointer; }
|
||||
T *operator->() const { return pointer; }
|
||||
operator T &() const { return *pointer; }
|
||||
private:
|
||||
T *pointer;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
MoveRef<T> Move(T &t) { return MoveRef<T>(t); }
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* defined(__cplusplus) */
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "jsalloc.h"
|
||||
#include "jstl.h"
|
||||
#include "jsprvtd.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
/* Silence dire "bugs in previous versions of MSVC have been fixed" warnings */
|
||||
#ifdef _MSC_VER
|
||||
|
@ -82,6 +83,16 @@ struct VectorImpl
|
|||
new(dst) T(*p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Move-constructs objects in the uninitialized range
|
||||
* [dst, dst+(srcend-srcbeg)) from the range [srcbeg, srcend).
|
||||
*/
|
||||
template <class U>
|
||||
static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
|
||||
for (const U *p = srcbeg; p != srcend; ++p, ++dst)
|
||||
new(dst) T(Move(*p));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy-constructs objects in the uninitialized range [dst, dst+n) from the
|
||||
* same object u.
|
||||
|
@ -104,7 +115,7 @@ struct VectorImpl
|
|||
if (!newbuf)
|
||||
return false;
|
||||
for (T *dst = newbuf, *src = v.beginNoCheck(); src != v.endNoCheck(); ++dst, ++src)
|
||||
new(dst) T(*src);
|
||||
new(dst) T(Move(*src));
|
||||
VectorImpl::destroy(v.beginNoCheck(), v.endNoCheck());
|
||||
v.free_(v.mBegin);
|
||||
v.mBegin = newbuf;
|
||||
|
@ -150,6 +161,11 @@ struct VectorImpl<T, N, AP, true>
|
|||
*dst = *p;
|
||||
}
|
||||
|
||||
template <class U>
|
||||
static inline void moveConstruct(T *dst, const U *srcbeg, const U *srcend) {
|
||||
copyConstruct(dst, srcbeg, srcend);
|
||||
}
|
||||
|
||||
static inline void copyConstructN(T *dst, size_t n, const T &t) {
|
||||
for (T *p = dst, *end = dst + n; p != end; ++p)
|
||||
*p = t;
|
||||
|
@ -287,7 +303,7 @@ class Vector : private AllocPolicy
|
|||
#endif
|
||||
|
||||
/* Append operations guaranteed to succeed due to pre-reserved space. */
|
||||
void internalAppend(const T &t);
|
||||
template <class U> void internalAppend(U t);
|
||||
void internalAppendN(const T &t, size_t n);
|
||||
template <class U> void internalAppend(const U *begin, size_t length);
|
||||
template <class U, size_t O, class BP> void internalAppend(const Vector<U,O,BP> &other);
|
||||
|
@ -298,6 +314,8 @@ class Vector : private AllocPolicy
|
|||
typedef T ElementType;
|
||||
|
||||
Vector(AllocPolicy = AllocPolicy());
|
||||
Vector(MoveRef<Vector>); /* Move constructor. */
|
||||
Vector &operator=(MoveRef<Vector>); /* Move assignment. */
|
||||
~Vector();
|
||||
|
||||
/* accessors */
|
||||
|
@ -386,8 +404,15 @@ class Vector : private AllocPolicy
|
|||
/* Clears and releases any heap-allocated storage. */
|
||||
void clearAndFree();
|
||||
|
||||
/* Potentially fallible append operations. */
|
||||
bool append(const T &t);
|
||||
/*
|
||||
* Potentially fallible append operations.
|
||||
*
|
||||
* The function templates that take an unspecified type U require a
|
||||
* const T & or a MoveRef<T>. The MoveRef<T> variants move their
|
||||
* operands into the vector, instead of copying them. If they fail, the
|
||||
* operand is left unmoved.
|
||||
*/
|
||||
template <class U> bool append(U t);
|
||||
bool appendN(const T &t, size_t n);
|
||||
template <class U> bool append(const U *begin, const U *end);
|
||||
template <class U> bool append(const U *begin, size_t length);
|
||||
|
@ -467,6 +492,51 @@ Vector<T,N,AllocPolicy>::Vector(AllocPolicy ap)
|
|||
#endif
|
||||
{}
|
||||
|
||||
/* Move constructor. */
|
||||
template <class T, size_t N, class AllocPolicy>
|
||||
JS_ALWAYS_INLINE
|
||||
Vector<T, N, AllocPolicy>::Vector(MoveRef<Vector> rhs)
|
||||
: AllocPolicy(rhs)
|
||||
{
|
||||
mLength = rhs->mLength;
|
||||
mCapacity = rhs->mCapacity;
|
||||
#ifdef DEBUG
|
||||
mReserved = rhs->mReserved;
|
||||
#endif
|
||||
|
||||
if (rhs->usingInlineStorage()) {
|
||||
/* We can't move the buffer over in this case, so copy elements. */
|
||||
Impl::moveConstruct(mBegin, rhs->beginNoCheck(), rhs->endNoCheck());
|
||||
/*
|
||||
* Leave rhs's mLength, mBegin, mCapacity, and mReserved as they are.
|
||||
* The elements in its in-line storage still need to be destroyed.
|
||||
*/
|
||||
} else {
|
||||
/*
|
||||
* Take src's buffer, and turn src into an empty vector using
|
||||
* in-line storage.
|
||||
*/
|
||||
mBegin = rhs->mBegin;
|
||||
rhs->mBegin = (T *) rhs->storage.addr();
|
||||
rhs->mCapacity = sInlineCapacity;
|
||||
rhs->mLength = 0;
|
||||
#ifdef DEBUG
|
||||
rhs->mReserved = 0;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Move assignment. */
|
||||
template <class T, size_t N, class AP>
|
||||
JS_ALWAYS_INLINE
|
||||
Vector<T, N, AP> &
|
||||
Vector<T, N, AP>::operator=(MoveRef<Vector> rhs)
|
||||
{
|
||||
this->~Vector();
|
||||
new(this) Vector(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
JS_ALWAYS_INLINE
|
||||
Vector<T,N,AP>::~Vector()
|
||||
|
@ -547,7 +617,7 @@ Vector<T,N,AP>::convertToHeapStorage(size_t lengthInc)
|
|||
return false;
|
||||
|
||||
/* Copy inline elements into heap buffer. */
|
||||
Impl::copyConstruct(newBuf, beginNoCheck(), endNoCheck());
|
||||
Impl::moveConstruct(newBuf, beginNoCheck(), endNoCheck());
|
||||
Impl::destroy(beginNoCheck(), endNoCheck());
|
||||
|
||||
/* Switch in heap buffer. */
|
||||
|
@ -572,16 +642,16 @@ inline bool
|
|||
Vector<T,N,AP>::reserve(size_t request)
|
||||
{
|
||||
REENTRANCY_GUARD_ET_AL;
|
||||
if (request <= mCapacity || growStorageBy(request - mLength)) {
|
||||
if (request > mCapacity && !growStorageBy(request - mLength))
|
||||
return false;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (request > mReserved)
|
||||
mReserved = request;
|
||||
JS_ASSERT(mLength <= mReserved);
|
||||
JS_ASSERT(mReserved <= mCapacity);
|
||||
if (request > mReserved)
|
||||
mReserved = request;
|
||||
JS_ASSERT(mLength <= mReserved);
|
||||
JS_ASSERT(mReserved <= mCapacity);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
|
@ -679,8 +749,9 @@ Vector<T,N,AP>::clearAndFree()
|
|||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class U>
|
||||
JS_ALWAYS_INLINE bool
|
||||
Vector<T,N,AP>::append(const T &t)
|
||||
Vector<T,N,AP>::append(U t)
|
||||
{
|
||||
REENTRANCY_GUARD_ET_AL;
|
||||
if (mLength == mCapacity && !growStorageBy(1))
|
||||
|
@ -695,8 +766,9 @@ Vector<T,N,AP>::append(const T &t)
|
|||
}
|
||||
|
||||
template <class T, size_t N, class AP>
|
||||
template <class U>
|
||||
JS_ALWAYS_INLINE void
|
||||
Vector<T,N,AP>::internalAppend(const T &t)
|
||||
Vector<T,N,AP>::internalAppend(U t)
|
||||
{
|
||||
JS_ASSERT(mLength + 1 <= mReserved);
|
||||
JS_ASSERT(mReserved <= mCapacity);
|
||||
|
@ -881,7 +953,7 @@ Vector<T,N,AP>::replaceRawBuffer(T *p, size_t length)
|
|||
mBegin = (T *)storage.addr();
|
||||
mLength = length;
|
||||
mCapacity = sInlineCapacity;
|
||||
Impl::copyConstruct(mBegin, p, p + length);
|
||||
Impl::moveConstruct(mBegin, p, p + length);
|
||||
Impl::destroy(p, p + length);
|
||||
this->free_(p);
|
||||
} else {
|
||||
|
|
|
@ -4790,7 +4790,7 @@ Help(JSContext *cx, uintN argc, jsval *vp)
|
|||
fprintf(gOutFile, "%s\n", JS_GetImplementationVersion());
|
||||
if (argc == 0) {
|
||||
fputs(shell_help_header, gOutFile);
|
||||
for (i = 0; shell_functions[i].name; i++)
|
||||
for (i = 0; i < JS_ARRAY_LENGTH(shell_help_messages); ++i)
|
||||
fprintf(gOutFile, "%s\n", shell_help_messages[i]);
|
||||
} else {
|
||||
did_header = 0;
|
||||
|
@ -4807,11 +4807,16 @@ Help(JSContext *cx, uintN argc, jsval *vp)
|
|||
str = NULL;
|
||||
}
|
||||
if (str) {
|
||||
JSFlatString *flatStr = JS_FlattenString(cx, str);
|
||||
if (!flatStr)
|
||||
JSAutoByteString funcName(cx, str);
|
||||
if (!funcName)
|
||||
return JS_FALSE;
|
||||
for (j = 0; shell_functions[j].name; j++) {
|
||||
if (JS_FlatStringEqualsAscii(flatStr, shell_functions[j].name)) {
|
||||
for (j = 0; j < JS_ARRAY_LENGTH(shell_help_messages); ++j) {
|
||||
/* Help messages are required to be formatted "functionName(..." */
|
||||
const char *msg = shell_help_messages[j];
|
||||
const char *p = strchr(msg, '(');
|
||||
JS_ASSERT(p);
|
||||
|
||||
if (strncmp(funcName.ptr(), msg, p - msg) == 0) {
|
||||
if (!did_header) {
|
||||
did_header = 1;
|
||||
fputs(shell_help_header, gOutFile);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
url-prefix ../../jsreftest.html?test=ecma_5/Global/
|
||||
fails-if(!xulRuntime.shell) script adding-global-var-nonextensible-error.js
|
||||
fails-if(!xulRuntime.shell) script cross-global-implicit-this.js
|
||||
skip-if(!xulRuntime.shell) script cross-global-implicit-this.js
|
||||
script parseInt-01.js
|
||||
script parseFloat-01.js
|
||||
script eval-01.js
|
||||
|
|
|
@ -11,3 +11,4 @@ script regress-613820-2.js
|
|||
script regress-613820-3.js
|
||||
silentfail skip-if(!xulRuntime.shell&&(Android||xulRuntime.OS=="WINNT")) script regress-617935.js
|
||||
script instance-property-storage-introspection.js
|
||||
script regexp-space-character-class.js
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is JavaScript Engine testing utilities.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2008
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s): Dave Mandelin
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
var gTestfile = 'regexp-space-character-class.js';
|
||||
//-----------------------------------------------------------------------------
|
||||
var BUGNUMBER = 514808;
|
||||
var summary = 'Correct space character class in regexes';
|
||||
var actual = '';
|
||||
var expect = '';
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
test();
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
function test()
|
||||
{
|
||||
enterFunc ('test');
|
||||
printBugNumber(BUGNUMBER);
|
||||
printStatus (summary);
|
||||
|
||||
var spaces = [ "\u0009", "\u000b", "\u000c", "\u0020", "\u00a0", "\u1680",
|
||||
"\u180e", "\u2000", "\u2001", "\u2002", "\u2003", "\u2004",
|
||||
"\u2005", "\u2006", "\u2007", "\u2008", "\u2009", "\u200a",
|
||||
"\u202f", "\u205f", "\u3000" ];
|
||||
var line_terminators = [ "\u2028", "\u2029", "\u000a", "\u000d" ];
|
||||
var space_chars = [].concat(spaces, line_terminators);
|
||||
|
||||
var non_space_chars = [ "\u200b", "\u200c", "\u200d",
|
||||
"\ufeff" ];
|
||||
|
||||
var chars = [].concat(space_chars, non_space_chars);
|
||||
var is_space = [].concat(space_chars.map(function(ch) { return true; }),
|
||||
non_space_chars.map(function(ch) { return false; }));
|
||||
var expect = is_space.join(',');
|
||||
|
||||
var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
|
||||
reportCompare(expect, actual, summary);
|
||||
|
||||
jit(true);
|
||||
var actual = chars.map(function(ch) { return /\s/.test(ch); }).join(',');
|
||||
reportCompare(expect, actual, summary);
|
||||
jit(false);
|
||||
|
||||
exitFunc ('test');
|
||||
}
|
|
@ -15,3 +15,4 @@ script new-with-non-constructor.js
|
|||
script error-undefined-message.js
|
||||
script regexp-functions-with-undefined.js
|
||||
script unnamed-function.js
|
||||
script unicode-identifier-1d17.js
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
|
||||
var BUGNUMBER = 497692;
|
||||
var summary = 'Javascript does not treat Unicode 1D17 as valid identifier character';
|
||||
|
||||
print(BUGNUMBER + ": " + summary);
|
||||
|
||||
/**************
|
||||
* BEGIN TEST *
|
||||
**************/
|
||||
|
||||
var o = {}
|
||||
try {
|
||||
eval('o.\\u1D17 = 42');
|
||||
}
|
||||
catch (e) {
|
||||
assertEq('should not fail', true);
|
||||
}
|
||||
|
||||
assertEq(o['\u1d17'], 42);
|
||||
|
||||
if (typeof reportCompare == 'function')
|
||||
reportCompare(true, true);
|
|
@ -42,6 +42,7 @@
|
|||
/* Per JSRuntime object */
|
||||
|
||||
#include "xpcprivate.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "WrapperFactory.h"
|
||||
#include "dom_quickstubs.h"
|
||||
|
||||
|
@ -57,6 +58,7 @@
|
|||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::xpconnect::memory;
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
|
@ -1227,6 +1229,205 @@ XPCJSRuntime::~XPCJSRuntime()
|
|||
XPCPerThreadData::ShutDown();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
PRInt64
|
||||
GetCompartmentScriptsSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for(JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->totalSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
PRInt64
|
||||
GetCompartmentMjitCodeSize(JSCompartment *c)
|
||||
{
|
||||
return c->getMjitCodeSize();
|
||||
}
|
||||
|
||||
PRInt64
|
||||
GetCompartmentMjitDataSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for(JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->jitDataSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif // JS_METHODJIT
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
PRInt64
|
||||
GetCompartmentTjitCodeSize(JSCompartment *c)
|
||||
{
|
||||
if(c->hasTraceMonitor())
|
||||
{
|
||||
size_t total, frag_size, free_size;
|
||||
c->traceMonitor()->getCodeAllocStats(total, frag_size, free_size);
|
||||
return total;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
GetCompartmentTjitDataAllocatorsMainSize(JSCompartment *c)
|
||||
{
|
||||
return c->hasTraceMonitor()
|
||||
? c->traceMonitor()->getVMAllocatorsMainSize()
|
||||
: 0;
|
||||
}
|
||||
|
||||
PRInt64
|
||||
GetCompartmentTjitDataAllocatorsReserveSize(JSCompartment *c)
|
||||
{
|
||||
return c->hasTraceMonitor()
|
||||
? c->traceMonitor()->getVMAllocatorsReserveSize()
|
||||
: 0;
|
||||
}
|
||||
|
||||
#endif // JS_TRACER
|
||||
|
||||
void
|
||||
CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
{
|
||||
// Append a new CompartmentStats to the vector.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats compartmentStats(cx, compartment);
|
||||
data->compartmentStatsVector.infallibleAppend(compartmentStats);
|
||||
CompartmentStats *curr = data->compartmentStatsVector.end() - 1;
|
||||
data->currCompartmentStats = curr;
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
curr->scripts = GetCompartmentScriptsSize(compartment);
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitCode = GetCompartmentMjitCodeSize(compartment);
|
||||
curr->mjitData = GetCompartmentMjitDataSize(compartment);
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
|
||||
curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
|
||||
curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
|
||||
size_t traceKind, size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
data->currCompartmentStats->gcHeapArenaHeaders +=
|
||||
sizeof(js::gc::ArenaHeader);
|
||||
data->currCompartmentStats->gcHeapArenaPadding +=
|
||||
arena->thingsStartOffset(thingSize) - 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);
|
||||
}
|
||||
|
||||
void
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
|
||||
size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats *curr = data->currCompartmentStats;
|
||||
if(traceKind == JSTRACE_OBJECT)
|
||||
{
|
||||
curr->gcHeapObjects += thingSize;
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if(obj->hasSlotsArray())
|
||||
curr->objectSlots += obj->numSlots() * sizeof(js::Value);
|
||||
}
|
||||
else if(traceKind == JSTRACE_STRING)
|
||||
{
|
||||
curr->gcHeapStrings += thingSize;
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->stringChars += str->charsHeapSize();
|
||||
}
|
||||
else if(traceKind == JSTRACE_SHAPE)
|
||||
{
|
||||
curr->gcHeapShapes += thingSize;
|
||||
js::Shape *shape = static_cast<js::Shape *>(thing);
|
||||
if(shape->hasTable())
|
||||
curr->propertyTables += shape->getTable()->sizeOf();
|
||||
}
|
||||
else
|
||||
{
|
||||
JS_ASSERT(traceKind == JSTRACE_XML);
|
||||
curr->gcHeapXml += thingSize;
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline void
|
||||
ReportMemory(const nsACString &path, PRInt32 kind, PRInt32 units,
|
||||
PRInt64 amount, const char (&desc)[N],
|
||||
nsIMemoryMultiReporterCallback *callback, nsISupports *closure)
|
||||
{
|
||||
callback->Callback(NS_LITERAL_CSTRING(""), path, kind, units, amount,
|
||||
NS_LITERAL_CSTRING(desc), closure);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline void
|
||||
ReportMemoryBytes(const nsACString &path, PRInt32 kind, PRInt64 amount,
|
||||
const char (&desc)[N],
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
ReportMemory(path, kind, nsIMemoryReporter::UNITS_BYTES, amount, desc,
|
||||
callback, closure);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline void
|
||||
ReportMemoryBytes0(const nsCString &path, PRInt32 kind, PRInt64 amount,
|
||||
const char (&desc)[N],
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
if(amount)
|
||||
ReportMemoryBytes(path, kind, amount, desc, callback, closure);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline void
|
||||
ReportMemoryPercentage(const nsACString &path, PRInt32 kind, PRInt64 amount,
|
||||
const char (&desc)[N],
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
ReportMemory(path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, amount, desc,
|
||||
callback, closure);
|
||||
}
|
||||
|
||||
template <int N>
|
||||
inline const nsCString
|
||||
MakeMemoryReporterPath(const nsACString &pathPrefix,
|
||||
const nsACString &compartmentName,
|
||||
const char (&reporterName)[N])
|
||||
{
|
||||
return pathPrefix + NS_LITERAL_CSTRING("compartment(") + compartmentName +
|
||||
NS_LITERAL_CSTRING(")/") + nsDependentCString(reporterName);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class XPConnectGCChunkAllocator
|
||||
: public js::GCChunkAllocator
|
||||
{
|
||||
|
@ -1282,25 +1483,6 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSGCHeap,
|
|||
gXPCJSChunkAllocator.GetGCChunkBytesInUse,
|
||||
"Memory used by the garbage-collected JavaScript heap.")
|
||||
|
||||
static PRInt64
|
||||
GetJSStack()
|
||||
{
|
||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
|
||||
PRInt64 n = 0;
|
||||
for (js::ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
n += i.threadData()->stackSpace.committedSize();
|
||||
return n;
|
||||
}
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSStack,
|
||||
"explicit/js/stack",
|
||||
KIND_NONHEAP,
|
||||
nsIMemoryReporter::UNITS_BYTES,
|
||||
GetJSStack,
|
||||
"Memory used for the JavaScript stack. This is the committed portion "
|
||||
"of the stack; any uncommitted portion is not measured because it "
|
||||
"hardly costs anything.")
|
||||
|
||||
static PRInt64
|
||||
GetJSSystemCompartmentCount()
|
||||
{
|
||||
|
@ -1354,262 +1536,247 @@ NS_MEMORY_REPORTER_IMPLEMENT(XPConnectJSUserCompartmentCount,
|
|||
"compartments listed under 'js' if a garbage collection occurs at an "
|
||||
"inopportune time, but such cases should be rare.")
|
||||
|
||||
namespace mozilla {
|
||||
namespace xpconnect {
|
||||
namespace memory {
|
||||
|
||||
CompartmentStats::CompartmentStats(JSContext *cx, JSCompartment *c)
|
||||
{
|
||||
memset(this, 0, sizeof(*this));
|
||||
|
||||
if(c == cx->runtime->atomsCompartment)
|
||||
{
|
||||
name.AssignLiteral("atoms");
|
||||
}
|
||||
else if(c->principals)
|
||||
{
|
||||
if(c->principals->codebase)
|
||||
{
|
||||
// A hack: replace forward slashes with '\\' so they aren't
|
||||
// treated as path separators. Users of the reporters
|
||||
// (such as about:memory) have to undo this change.
|
||||
name.Assign(c->principals->codebase);
|
||||
name.ReplaceChar('/', '\\');
|
||||
|
||||
// If it's the system compartment, append the address.
|
||||
// This means that multiple system compartments (and there
|
||||
// can be many) can be distinguished.
|
||||
if(c->isSystemCompartment)
|
||||
{
|
||||
// ample; 64-bit address max is 18 chars
|
||||
static const int maxLength = 31;
|
||||
nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
|
||||
name.Append(address);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name.AssignLiteral("null-codebase");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
name.AssignLiteral("null-principal");
|
||||
}
|
||||
}
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data)
|
||||
{
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if(!cx)
|
||||
{
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
JSAutoRequest ar(cx);
|
||||
|
||||
data->compartmentStatsVector.reserve(rt->compartments.length());
|
||||
js::IterateCompartmentsArenasCells(cx, data, CompartmentCallback,
|
||||
ArenaCallback, CellCallback);
|
||||
}
|
||||
|
||||
JS_DestroyContextNoGC(cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ReportCompartmentStats(const CompartmentStats &stats,
|
||||
const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/arena-headers"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapArenaHeaders,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that is used to hold internal book-keeping information.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/arena-padding"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapArenaPadding,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that is unused and present only so that other data is aligned. "
|
||||
"This constitutes internal fragmentation.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/arena-unused"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapArenaUnused,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that could be holding useful data but currently isn't.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/objects"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapObjects,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"objects.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/strings"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapStrings,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"string headers. String headers contain various pieces of information "
|
||||
"about a string, but do not contain (except in the case of very short "
|
||||
"strings) the string characters; characters in longer strings are counted "
|
||||
"under 'gc-heap/string-chars' instead.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/shapes"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapShapes,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"shapes. A shape is an internal data structure that makes JavaScript "
|
||||
"property accesses fast.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"gc-heap/xml"),
|
||||
JS_GC_HEAP_KIND, stats.gcHeapXml,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"E4X XML objects.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"object-slots"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.objectSlots,
|
||||
"Memory allocated for the compartment's non-fixed object slot arrays, "
|
||||
"which are used to represent object properties. Some objects also "
|
||||
"contain a fixed number of slots which are stored on the compartment's "
|
||||
"JavaScript heap; those slots are not counted here, but in "
|
||||
"'gc-heap/objects' instead.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"string-chars"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.stringChars,
|
||||
"Memory allocated to hold the compartment's string characters. Sometimes "
|
||||
"more memory is allocated than necessary, to simplify string "
|
||||
"concatenation. Each string also includes a header which is stored on the "
|
||||
"compartment's JavaScript heap; that header is not counted here, but in "
|
||||
"'gc-heap/strings' instead.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"property-tables"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.propertyTables,
|
||||
"Memory allocated for the compartment's property tables. A property "
|
||||
"table is an internal data structure that makes JavaScript property "
|
||||
"accesses fast.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"scripts"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.scripts,
|
||||
"Memory allocated for the compartment's JSScripts. A JSScript is created "
|
||||
"for each user-defined function in a script. One is also created for "
|
||||
"the top-level code in a script. Each JSScript includes byte-code and "
|
||||
"various other things.",
|
||||
callback, closure);
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"mjit-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, stats.mjitCode,
|
||||
"Memory used by the method JIT to hold the compartment's generated code.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"mjit-data"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats.mjitData,
|
||||
"Memory used by the method JIT for the compartment's compilation data: "
|
||||
"JITScripts, native maps, and inline cache structs.",
|
||||
callback, closure);
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"tjit-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, stats.tjitCode,
|
||||
"Memory used by the trace JIT to hold the compartment's generated code.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"tjit-data/allocators-main"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.tjitDataAllocatorsMain,
|
||||
"Memory used by the trace JIT to store the compartment's trace-related "
|
||||
"data. This data is allocated via the compartment's VMAllocators.",
|
||||
callback, closure);
|
||||
|
||||
ReportMemoryBytes0(MakeMemoryReporterPath(pathPrefix, stats.name,
|
||||
"tjit-data/allocators-reserve"),
|
||||
nsIMemoryReporter::KIND_HEAP,
|
||||
stats.tjitDataAllocatorsReserve,
|
||||
"Memory used by the trace JIT and held in reserve for the compartment's "
|
||||
"VMAllocators in case of OOM.",
|
||||
callback, closure);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ReportJSStackSizeForRuntime(JSRuntime *rt, const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
PRInt64 stackSize = 0;
|
||||
for(js::ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
stackSize += i.threadData()->stackSpace.committedSize();
|
||||
|
||||
ReportMemoryBytes(pathPrefix + NS_LITERAL_CSTRING("stack"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, stackSize,
|
||||
"Memory used for the JavaScript stack. This is the committed portion "
|
||||
"of the stack; any uncommitted portion is not measured because it "
|
||||
"hardly costs anything.",
|
||||
callback, closure);
|
||||
}
|
||||
|
||||
} // namespace memory
|
||||
} // namespace xpconnect
|
||||
} // namespace mozilla
|
||||
|
||||
class XPConnectJSCompartmentsMultiReporter : public nsIMemoryMultiReporter
|
||||
{
|
||||
private:
|
||||
struct CompartmentStats
|
||||
{
|
||||
CompartmentStats(JSContext *cx, JSCompartment *c) {
|
||||
memset(this, 0, sizeof(*this));
|
||||
|
||||
if (c == cx->runtime->atomsCompartment) {
|
||||
name = NS_LITERAL_CSTRING("atoms");
|
||||
} else if (c->principals) {
|
||||
if (c->principals->codebase) {
|
||||
// A hack: replace forward slashes with '\\' so they aren't
|
||||
// treated as path separators. Users of the reporters
|
||||
// (such as about:memory) have to undo this change.
|
||||
name.Assign(c->principals->codebase);
|
||||
char* cur = name.BeginWriting();
|
||||
char* end = name.EndWriting();
|
||||
for (; cur < end; ++cur) {
|
||||
if ('/' == *cur) {
|
||||
*cur = '\\';
|
||||
}
|
||||
}
|
||||
// If it's the system compartment, append the address.
|
||||
// This means that multiple system compartments (and there
|
||||
// can be many) can be distinguished.
|
||||
if (c->isSystemCompartment) {
|
||||
static const int maxLength = 31; // ample; 64-bit address max is 18 chars
|
||||
nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
|
||||
name.Append(address);
|
||||
}
|
||||
} else {
|
||||
name = NS_LITERAL_CSTRING("null-codebase");
|
||||
}
|
||||
} else {
|
||||
name = NS_LITERAL_CSTRING("null-principal");
|
||||
}
|
||||
}
|
||||
|
||||
nsCString name;
|
||||
PRInt64 gcHeapArenaHeaders;
|
||||
PRInt64 gcHeapArenaPadding;
|
||||
PRInt64 gcHeapArenaUnused;
|
||||
|
||||
PRInt64 gcHeapObjects;
|
||||
PRInt64 gcHeapStrings;
|
||||
PRInt64 gcHeapShapes;
|
||||
PRInt64 gcHeapXml;
|
||||
|
||||
PRInt64 objectSlots;
|
||||
PRInt64 stringChars;
|
||||
PRInt64 propertyTables;
|
||||
|
||||
PRInt64 scripts;
|
||||
#ifdef JS_METHODJIT
|
||||
PRInt64 mjitCode;
|
||||
PRInt64 mjitData;
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
PRInt64 tjitCode;
|
||||
PRInt64 tjitDataAllocatorsMain;
|
||||
PRInt64 tjitDataAllocatorsReserve;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct IterateData
|
||||
{
|
||||
IterateData(JSRuntime *rt)
|
||||
: compartmentStatsVector()
|
||||
, currCompartmentStats(NULL)
|
||||
{
|
||||
compartmentStatsVector.reserve(rt->compartments.length());
|
||||
}
|
||||
|
||||
js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
|
||||
CompartmentStats *currCompartmentStats;
|
||||
};
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentScriptsSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for (JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->totalSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentMjitCodeSize(JSCompartment *c)
|
||||
{
|
||||
return c->getMjitCodeSize();
|
||||
}
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentMjitDataSize(JSCompartment *c)
|
||||
{
|
||||
PRInt64 n = 0;
|
||||
for (JSScript *script = (JSScript *)c->scripts.next;
|
||||
&script->links != &c->scripts;
|
||||
script = (JSScript *)script->links.next)
|
||||
{
|
||||
n += script->jitDataSize();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
#endif // JS_METHODJIT
|
||||
|
||||
#ifdef JS_TRACER
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentTjitCodeSize(JSCompartment *c)
|
||||
{
|
||||
if (c->hasTraceMonitor()) {
|
||||
size_t total, frag_size, free_size;
|
||||
c->traceMonitor()->getCodeAllocStats(total, frag_size, free_size);
|
||||
return total;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentTjitDataAllocatorsMainSize(JSCompartment *c)
|
||||
{
|
||||
return c->hasTraceMonitor()
|
||||
? c->traceMonitor()->getVMAllocatorsMainSize()
|
||||
: 0;
|
||||
}
|
||||
|
||||
static PRInt64
|
||||
GetCompartmentTjitDataAllocatorsReserveSize(JSCompartment *c)
|
||||
{
|
||||
return c->hasTraceMonitor()
|
||||
? c->traceMonitor()->getVMAllocatorsReserveSize()
|
||||
: 0;
|
||||
}
|
||||
|
||||
#endif // JS_TRACER
|
||||
|
||||
static void
|
||||
CompartmentCallback(JSContext *cx, void *vdata, JSCompartment *compartment)
|
||||
{
|
||||
// Append a new CompartmentStats to the vector.
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats compartmentStats(cx, compartment);
|
||||
data->compartmentStatsVector.infallibleAppend(compartmentStats);
|
||||
CompartmentStats *curr = data->compartmentStatsVector.end() - 1;
|
||||
data->currCompartmentStats = curr;
|
||||
|
||||
// Get the compartment-level numbers.
|
||||
curr->scripts = GetCompartmentScriptsSize(compartment);
|
||||
#ifdef JS_METHODJIT
|
||||
curr->mjitCode = GetCompartmentMjitCodeSize(compartment);
|
||||
curr->mjitData = GetCompartmentMjitDataSize(compartment);
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
curr->tjitCode = GetCompartmentTjitCodeSize(compartment);
|
||||
curr->tjitDataAllocatorsMain = GetCompartmentTjitDataAllocatorsMainSize(compartment);
|
||||
curr->tjitDataAllocatorsReserve = GetCompartmentTjitDataAllocatorsReserveSize(compartment);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ArenaCallback(JSContext *cx, void *vdata, js::gc::Arena *arena,
|
||||
size_t traceKind, size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
data->currCompartmentStats->gcHeapArenaHeaders +=
|
||||
sizeof(js::gc::ArenaHeader);
|
||||
data->currCompartmentStats->gcHeapArenaPadding +=
|
||||
arena->thingsStartOffset(thingSize) - 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);
|
||||
}
|
||||
|
||||
static void
|
||||
CellCallback(JSContext *cx, void *vdata, void *thing, size_t traceKind,
|
||||
size_t thingSize)
|
||||
{
|
||||
IterateData *data = static_cast<IterateData *>(vdata);
|
||||
CompartmentStats *curr = data->currCompartmentStats;
|
||||
if (traceKind == JSTRACE_OBJECT) {
|
||||
curr->gcHeapObjects += thingSize;
|
||||
JSObject *obj = static_cast<JSObject *>(thing);
|
||||
if (obj->hasSlotsArray()) {
|
||||
curr->objectSlots += obj->numSlots() * sizeof(js::Value);
|
||||
}
|
||||
} else if (traceKind == JSTRACE_STRING) {
|
||||
curr->gcHeapStrings += thingSize;
|
||||
JSString *str = static_cast<JSString *>(thing);
|
||||
curr->stringChars += str->charsHeapSize();
|
||||
} else if (traceKind == JSTRACE_SHAPE) {
|
||||
curr->gcHeapShapes += thingSize;
|
||||
js::Shape *shape = static_cast<js::Shape *>(thing);
|
||||
if (shape->hasTable()) {
|
||||
curr->propertyTables += shape->getTable()->sizeOf();
|
||||
}
|
||||
} else {
|
||||
JS_ASSERT(traceKind == JSTRACE_XML);
|
||||
curr->gcHeapXml += thingSize;
|
||||
}
|
||||
// Yes, this is a subtraction: see ArenaCallback() for details.
|
||||
curr->gcHeapArenaUnused -= thingSize;
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
XPConnectJSCompartmentsMultiReporter()
|
||||
{
|
||||
}
|
||||
|
||||
nsCString mkPath(const nsACString &compartmentName,
|
||||
const char* reporterName)
|
||||
{
|
||||
nsCString path(NS_LITERAL_CSTRING("explicit/js/compartment("));
|
||||
path += compartmentName;
|
||||
path += NS_LITERAL_CSTRING(")/");
|
||||
path += nsDependentCString(reporterName);
|
||||
return path;
|
||||
}
|
||||
|
||||
NS_IMETHOD CollectReports(nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure)
|
||||
{
|
||||
JSRuntime *rt = nsXPConnect::GetRuntimeInstance()->GetJSRuntime();
|
||||
IterateData data(rt);
|
||||
|
||||
// In the first step we get all the stats and stash them in a local
|
||||
// data structure. In the second step we pass all the stashed stats to
|
||||
// the callback. Separating these steps is important because the
|
||||
// callback may be a JS function, and executing JS while getting these
|
||||
// stats seems like a bad idea.
|
||||
{
|
||||
JSContext *cx = JS_NewContext(rt, 0);
|
||||
if (!cx) {
|
||||
NS_ERROR("couldn't create context for memory tracing");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
JS_BeginRequest(cx);
|
||||
js::IterateCompartmentsArenasCells(cx, &data, CompartmentCallback, ArenaCallback,
|
||||
CellCallback);
|
||||
JS_EndRequest(cx);
|
||||
JS_DestroyContextNoGC(cx);
|
||||
}
|
||||
|
||||
NS_NAMED_LITERAL_CSTRING(p, "");
|
||||
IterateData data;
|
||||
if(!CollectCompartmentStatsForRuntime(rt, &data))
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PRInt64 gcHeapChunkTotal = gXPCJSChunkAllocator.GetGCChunkBytesInUse();
|
||||
// This is initialized to gcHeapChunkTotal, and then we subtract used
|
||||
|
@ -1617,27 +1784,13 @@ public:
|
|||
PRInt64 gcHeapChunkUnused = gcHeapChunkTotal;
|
||||
PRInt64 gcHeapArenaUnused = 0;
|
||||
|
||||
#define BYTES(path, kind, amount, desc) \
|
||||
callback->Callback(p, path, kind, nsIMemoryReporter::UNITS_BYTES, \
|
||||
amount, NS_LITERAL_CSTRING(desc), closure)
|
||||
|
||||
#define BYTES0(path, kind, amount, desc) \
|
||||
do { \
|
||||
if (amount != 0) \
|
||||
BYTES(path, kind, amount, desc); \
|
||||
} while (0)
|
||||
|
||||
#define PERCENTAGE(path, kind, amount, desc) \
|
||||
callback->Callback(p, path, kind, nsIMemoryReporter::UNITS_PERCENTAGE, \
|
||||
amount, NS_LITERAL_CSTRING(desc), closure);
|
||||
NS_NAMED_LITERAL_CSTRING(pathPrefix, "explicit/js/");
|
||||
|
||||
// This is the second step (see above).
|
||||
for (CompartmentStats *stats = data.compartmentStatsVector.begin();
|
||||
stats != data.compartmentStatsVector.end();
|
||||
++stats)
|
||||
for(CompartmentStats *stats = data.compartmentStatsVector.begin();
|
||||
stats != data.compartmentStatsVector.end();
|
||||
++stats)
|
||||
{
|
||||
nsCString &name = stats->name;
|
||||
|
||||
gcHeapChunkUnused -=
|
||||
stats->gcHeapArenaHeaders + stats->gcHeapArenaPadding +
|
||||
stats->gcHeapArenaUnused +
|
||||
|
@ -1646,100 +1799,7 @@ public:
|
|||
|
||||
gcHeapArenaUnused += stats->gcHeapArenaUnused;
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/arena-headers"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapArenaHeaders,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that is used to hold internal book-keeping information.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/arena-padding"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapArenaPadding,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that is unused and present only so that other data is aligned. "
|
||||
"This constitutes internal fragmentation.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/arena-unused"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapArenaUnused,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap, within "
|
||||
"arenas, that could be holding useful data but currently isn't.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/objects"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapObjects,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"objects.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/strings"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapStrings,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"string headers. String headers contain various pieces of information "
|
||||
"about a string, but do not contain (except in the case of very short "
|
||||
"strings) the string characters; characters in longer strings are counted "
|
||||
"under 'gc-heap/string-chars' instead.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/shapes"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapShapes,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"shapes. A shape is an internal data structure that makes JavaScript "
|
||||
"property accesses fast.");
|
||||
|
||||
BYTES0(mkPath(name, "gc-heap/xml"),
|
||||
JS_GC_HEAP_KIND, stats->gcHeapXml,
|
||||
"Memory on the compartment's garbage-collected JavaScript heap that holds "
|
||||
"E4X XML objects.");
|
||||
|
||||
BYTES0(mkPath(name, "object-slots"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->objectSlots,
|
||||
"Memory allocated for the compartment's non-fixed object slot arrays, "
|
||||
"which are used to represent object properties. Some objects also "
|
||||
"contain a fixed number of slots which are stored on the compartment's "
|
||||
"JavaScript heap; those slots are not counted here, but in "
|
||||
"'gc-heap/objects' instead.");
|
||||
|
||||
BYTES0(mkPath(name, "string-chars"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->stringChars,
|
||||
"Memory allocated to hold the compartment's string characters. Sometimes "
|
||||
"more memory is allocated than necessary, to simplify string "
|
||||
"concatenation. Each string also includes a header which is stored on the "
|
||||
"compartment's JavaScript heap; that header is not counted here, but in "
|
||||
"'gc-heap/strings' instead.");
|
||||
|
||||
BYTES0(mkPath(name, "property-tables"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->propertyTables,
|
||||
"Memory allocated for the compartment's property tables. A property "
|
||||
"table is an internal data structure that makes JavaScript property "
|
||||
"accesses fast.");
|
||||
|
||||
BYTES0(mkPath(name, "scripts"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->scripts,
|
||||
"Memory allocated for the compartment's JSScripts. A JSScript is created "
|
||||
"for each user-defined function in a script. One is also created for "
|
||||
"the top-level code in a script. Each JSScript includes byte-code and "
|
||||
"various other things.");
|
||||
|
||||
#ifdef JS_METHODJIT
|
||||
BYTES0(mkPath(name, "mjit-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, stats->mjitCode,
|
||||
"Memory used by the method JIT to hold the compartment's generated code.");
|
||||
|
||||
BYTES0(mkPath(name, "mjit-data"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->mjitData,
|
||||
"Memory used by the method JIT for the compartment's compilation data: "
|
||||
"JITScripts, native maps, and inline cache structs.");
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
BYTES0(mkPath(name, "tjit-code"),
|
||||
nsIMemoryReporter::KIND_NONHEAP, stats->tjitCode,
|
||||
"Memory used by the trace JIT to hold the compartment's generated code.");
|
||||
|
||||
BYTES0(mkPath(name, "tjit-data/allocators-main"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->tjitDataAllocatorsMain,
|
||||
"Memory used by the trace JIT to store the compartment's trace-related "
|
||||
"data. This data is allocated via the compartment's VMAllocators.");
|
||||
|
||||
BYTES0(mkPath(name, "tjit-data/allocators-reserve"),
|
||||
nsIMemoryReporter::KIND_HEAP, stats->tjitDataAllocatorsReserve,
|
||||
"Memory used by the trace JIT and held in reserve for the compartment's "
|
||||
"VMAllocators in case of OOM.");
|
||||
#endif
|
||||
ReportCompartmentStats(*stats, pathPrefix, callback, closure);
|
||||
}
|
||||
|
||||
JS_ASSERT(gcHeapChunkTotal % js::GC_CHUNK_SIZE == 0);
|
||||
|
@ -1756,36 +1816,47 @@ public:
|
|||
(gcHeapChunkUnused + gcHeapArenaUnused) * 10000 /
|
||||
gXPCJSChunkAllocator.GetGCChunkBytesInUse();
|
||||
|
||||
BYTES(NS_LITERAL_CSTRING("explicit/js/gc-heap-chunk-unused"),
|
||||
JS_GC_HEAP_KIND, gcHeapChunkUnused,
|
||||
ReportMemoryBytes(pathPrefix +
|
||||
NS_LITERAL_CSTRING("gc-heap-chunk-unused"),
|
||||
JS_GC_HEAP_KIND, gcHeapChunkUnused,
|
||||
"Memory on the garbage-collected JavaScript heap, within chunks, that "
|
||||
"could be holding useful data but currently isn't.");
|
||||
"could be holding useful data but currently isn't.",
|
||||
callback, closure);
|
||||
|
||||
BYTES(NS_LITERAL_CSTRING("js-gc-heap-chunk-unused"),
|
||||
nsIMemoryReporter::KIND_OTHER, gcHeapChunkUnused,
|
||||
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-chunk-unused"),
|
||||
nsIMemoryReporter::KIND_OTHER, gcHeapChunkUnused,
|
||||
"The same as 'explicit/js/gc-heap-chunk-unused'. Shown here for "
|
||||
"easy comparison with 'js-gc-heap' and 'js-gc-heap-arena-unused'.");
|
||||
"easy comparison with 'js-gc-heap' and 'js-gc-heap-arena-unused'.",
|
||||
callback, closure);
|
||||
|
||||
BYTES(NS_LITERAL_CSTRING("explicit/js/gc-heap-chunk-admin"),
|
||||
JS_GC_HEAP_KIND, gcHeapChunkAdmin,
|
||||
ReportMemoryBytes(pathPrefix +
|
||||
NS_LITERAL_CSTRING("gc-heap-chunk-admin"),
|
||||
JS_GC_HEAP_KIND, gcHeapChunkAdmin,
|
||||
"Memory on the garbage-collected JavaScript heap, within chunks, that is "
|
||||
"used to hold internal book-keeping information.");
|
||||
"used to hold internal book-keeping information.",
|
||||
callback, closure);
|
||||
|
||||
BYTES(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
|
||||
nsIMemoryReporter::KIND_OTHER, gcHeapArenaUnused,
|
||||
ReportMemoryBytes(NS_LITERAL_CSTRING("js-gc-heap-arena-unused"),
|
||||
nsIMemoryReporter::KIND_OTHER, gcHeapArenaUnused,
|
||||
"Memory on the garbage-collected JavaScript heap, within arenas, that "
|
||||
"could be holding useful data but currently isn't. This is the sum of "
|
||||
"all compartments' 'gc-heap/arena-unused' numbers.");
|
||||
"all compartments' 'gc-heap/arena-unused' numbers.",
|
||||
callback, closure);
|
||||
|
||||
PERCENTAGE(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
|
||||
nsIMemoryReporter::KIND_OTHER, gcHeapUnusedPercentage,
|
||||
ReportMemoryPercentage(NS_LITERAL_CSTRING("js-gc-heap-unused-fraction"),
|
||||
nsIMemoryReporter::KIND_OTHER,
|
||||
gcHeapUnusedPercentage,
|
||||
"Fraction of the garbage-collected JavaScript heap that is unused. "
|
||||
"Computed as ('js-gc-heap-chunk-unused' + 'js-gc-heap-arena-unused') / "
|
||||
"'js-gc-heap'.");
|
||||
"'js-gc-heap'.",
|
||||
callback, closure);
|
||||
|
||||
ReportJSStackSizeForRuntime(rt, pathPrefix, callback, closure);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_THREADSAFE_ISUPPORTS1(
|
||||
XPConnectJSCompartmentsMultiReporter
|
||||
, nsIMemoryMultiReporter
|
||||
|
@ -1868,7 +1939,6 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
|
|||
mJSRuntime->setCustomGCChunkAllocator(&gXPCJSChunkAllocator);
|
||||
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSGCHeap));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSStack));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSSystemCompartmentCount));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(XPConnectJSUserCompartmentCount));
|
||||
NS_RegisterMemoryMultiReporter(new XPConnectJSCompartmentsMultiReporter);
|
||||
|
|
|
@ -43,10 +43,12 @@
|
|||
#include "jsapi.h"
|
||||
#include "jsobj.h"
|
||||
#include "jsgc.h"
|
||||
#include "jspubtd.h"
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsStringGlue.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
|
@ -183,4 +185,67 @@ nsWrapperCache::GetWrapper() const
|
|||
return obj;
|
||||
}
|
||||
|
||||
class nsIMemoryMultiReporterCallback;
|
||||
|
||||
namespace mozilla {
|
||||
namespace xpconnect {
|
||||
namespace memory {
|
||||
|
||||
struct CompartmentStats
|
||||
{
|
||||
CompartmentStats(JSContext *cx, JSCompartment *c);
|
||||
|
||||
nsCString name;
|
||||
PRInt64 gcHeapArenaHeaders;
|
||||
PRInt64 gcHeapArenaPadding;
|
||||
PRInt64 gcHeapArenaUnused;
|
||||
|
||||
PRInt64 gcHeapObjects;
|
||||
PRInt64 gcHeapStrings;
|
||||
PRInt64 gcHeapShapes;
|
||||
PRInt64 gcHeapXml;
|
||||
|
||||
PRInt64 objectSlots;
|
||||
PRInt64 stringChars;
|
||||
PRInt64 propertyTables;
|
||||
|
||||
PRInt64 scripts;
|
||||
#ifdef JS_METHODJIT
|
||||
PRInt64 mjitCode;
|
||||
PRInt64 mjitData;
|
||||
#endif
|
||||
#ifdef JS_TRACER
|
||||
PRInt64 tjitCode;
|
||||
PRInt64 tjitDataAllocatorsMain;
|
||||
PRInt64 tjitDataAllocatorsReserve;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct IterateData
|
||||
{
|
||||
IterateData()
|
||||
: compartmentStatsVector(), currCompartmentStats(NULL) { }
|
||||
|
||||
js::Vector<CompartmentStats, 0, js::SystemAllocPolicy> compartmentStatsVector;
|
||||
CompartmentStats *currCompartmentStats;
|
||||
};
|
||||
|
||||
JSBool
|
||||
CollectCompartmentStatsForRuntime(JSRuntime *rt, IterateData *data);
|
||||
|
||||
void
|
||||
ReportCompartmentStats(const CompartmentStats &stats,
|
||||
const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure);
|
||||
|
||||
void
|
||||
ReportJSStackSizeForRuntime(JSRuntime *rt, const nsACString &pathPrefix,
|
||||
nsIMemoryMultiReporterCallback *callback,
|
||||
nsISupports *closure);
|
||||
|
||||
} // namespace memory
|
||||
} // namespace xpconnect
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml" class="reftest-print">
|
||||
<style><![CDATA[
|
||||
tfoot::after { content: "m"; position: fixed;}
|
||||
]]>
|
||||
</style>
|
||||
<td></td>
|
||||
<tfoot style="page-break-before: always;"></tfoot>
|
||||
</html>
|
|
@ -342,3 +342,4 @@ load 663662-2.html
|
|||
load 665837.html
|
||||
load 668941.xhtml
|
||||
load 670226.html
|
||||
asserts(2) load 675246-1.xhtml # Bug 675713
|
||||
|
|
|
@ -728,7 +728,8 @@ public:
|
|||
|
||||
// If false (which is the default) then call SetPrimaryFrame() as needed
|
||||
// during frame construction. If true, don't make any SetPrimaryFrame()
|
||||
// calls. The mCreatingExtraFrames == PR_TRUE mode is meant to be used for
|
||||
// calls, except for generated content which doesn't have a primary frame
|
||||
// yet. The mCreatingExtraFrames == PR_TRUE mode is meant to be used for
|
||||
// construction of random "extra" frames for elements via normal frame
|
||||
// construction APIs (e.g. replication of things across pages in paginated
|
||||
// mode).
|
||||
|
@ -3810,7 +3811,14 @@ nsCSSFrameConstructor::ConstructFrameFromItemInternal(FrameConstructionItem& aIt
|
|||
((bits & FCDATA_IS_LINE_PARTICIPANT) != 0),
|
||||
"Incorrectly set FCDATA_IS_LINE_PARTICIPANT bits");
|
||||
|
||||
if (!aState.mCreatingExtraFrames && !(bits & FCDATA_SKIP_FRAMESET)) {
|
||||
// Even if mCreatingExtraFrames is set, we may need to SetPrimaryFrame for
|
||||
// generated content that doesn't have one yet. Note that we have to examine
|
||||
// the frame bit, because by this point mIsGeneratedContent has been cleared
|
||||
// on aItem.
|
||||
if ((!aState.mCreatingExtraFrames ||
|
||||
((primaryFrame->GetStateBits() & NS_FRAME_GENERATED_CONTENT) &&
|
||||
!aItem.mContent->GetPrimaryFrame())) &&
|
||||
!(bits & FCDATA_SKIP_FRAMESET)) {
|
||||
aItem.mContent->SetPrimaryFrame(primaryFrame);
|
||||
}
|
||||
|
||||
|
|
|
@ -1432,6 +1432,15 @@ public:
|
|||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PLDHashOperator StyleSizeEnumerator(PresShellPtrKey *aEntry,
|
||||
void *userArg)
|
||||
{
|
||||
PresShell *aShell = static_cast<PresShell*>(aEntry->GetKey());
|
||||
PRUint32 *val = (PRUint32*)userArg;
|
||||
*val += aShell->StyleSet()->SizeOf();
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static PRUint32
|
||||
EstimateShellsMemory(nsTHashtable<PresShellPtrKey>::Enumerator aEnumerator)
|
||||
{
|
||||
|
@ -1439,12 +1448,15 @@ public:
|
|||
sLiveShells->EnumerateEntries(aEnumerator, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PRInt64 SizeOfLayoutMemoryReporter() {
|
||||
return EstimateShellsMemory(LiveShellSizeEnumerator);
|
||||
}
|
||||
|
||||
static PRInt64 SizeOfStyleMemoryReporter() {
|
||||
return EstimateShellsMemory(StyleSizeEnumerator);
|
||||
}
|
||||
|
||||
protected:
|
||||
void QueryIsActive();
|
||||
nsresult UpdateImageLockingState();
|
||||
|
@ -1654,12 +1666,19 @@ nsTHashtable<PresShell::PresShellPtrKey> *nsIPresShell::sLiveShells = 0;
|
|||
static PRBool sSynthMouseMove = PR_TRUE;
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(LayoutPresShell,
|
||||
"explicit/layout/all",
|
||||
"explicit/layout/arenas",
|
||||
KIND_HEAP,
|
||||
UNITS_BYTES,
|
||||
PresShell::SizeOfLayoutMemoryReporter,
|
||||
"Memory used by layout PresShell, PresContext, and other related areas.")
|
||||
|
||||
NS_MEMORY_REPORTER_IMPLEMENT(LayoutStyle,
|
||||
"explicit/layout/styledata",
|
||||
KIND_HEAP,
|
||||
UNITS_BYTES,
|
||||
PresShell::SizeOfStyleMemoryReporter,
|
||||
"Memory used by the style system.")
|
||||
|
||||
PresShell::PresShell()
|
||||
: mMouseLocation(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE)
|
||||
{
|
||||
|
@ -1688,6 +1707,7 @@ PresShell::PresShell()
|
|||
static bool registeredReporter = false;
|
||||
if (!registeredReporter) {
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutPresShell));
|
||||
NS_RegisterMemoryReporter(new NS_MEMORY_REPORTER_NAME(LayoutStyle));
|
||||
Preferences::AddBoolVarCache(&sSynthMouseMove,
|
||||
"layout.reflow.synthMouseMove", PR_TRUE);
|
||||
registeredReporter = true;
|
||||
|
|
|
@ -187,7 +187,7 @@ nsFormControlFrame::GetUsableScreenRect(nsPresContext* aPresContext)
|
|||
nsRect screen;
|
||||
|
||||
nsDeviceContext *context = aPresContext->DeviceContext();
|
||||
PRBool dropdownCanOverlapOSBar = PR_FALSE;
|
||||
PRInt32 dropdownCanOverlapOSBar = PR_FALSE;
|
||||
nsILookAndFeel *lookAndFeel = aPresContext->LookAndFeel();
|
||||
lookAndFeel->GetMetric(nsILookAndFeel::eMetric_MenusCanOverlapOSBar,
|
||||
dropdownCanOverlapOSBar);
|
||||
|
|
|
@ -119,7 +119,7 @@ nsBlockReflowContext::ComputeCollapsedTopMargin(const nsHTMLReflowState& aRS,
|
|||
// OK because our traversal is idempotent.
|
||||
for (nsBlockFrame* block = static_cast<nsBlockFrame*>(frame);
|
||||
block; block = static_cast<nsBlockFrame*>(block->GetNextInFlow())) {
|
||||
for (PRBool overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
|
||||
for (PRIntn overflowLines = PR_FALSE; overflowLines <= PR_TRUE; ++overflowLines) {
|
||||
nsBlockFrame::line_iterator line;
|
||||
nsBlockFrame::line_iterator line_end;
|
||||
PRBool anyLines = PR_TRUE;
|
||||
|
|
|
@ -203,12 +203,12 @@ static PRLogModuleInfo* gLogModule;
|
|||
|
||||
static PRLogModuleInfo* gStyleVerifyTreeLogModuleInfo;
|
||||
|
||||
static PRBool gStyleVerifyTreeEnable = PRBool(0x55);
|
||||
static PRUint32 gStyleVerifyTreeEnable = 0x55;
|
||||
|
||||
PRBool
|
||||
nsFrame::GetVerifyStyleTreeEnable()
|
||||
{
|
||||
if (gStyleVerifyTreeEnable == PRBool(0x55)) {
|
||||
if (gStyleVerifyTreeEnable == 0x55) {
|
||||
if (nsnull == gStyleVerifyTreeLogModuleInfo) {
|
||||
gStyleVerifyTreeLogModuleInfo = PR_NewLogModule("styleverifytree");
|
||||
gStyleVerifyTreeEnable = 0 != gStyleVerifyTreeLogModuleInfo->level;
|
||||
|
|
|
@ -1463,7 +1463,7 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
|
|||
, mShouldBuildLayer(PR_FALSE)
|
||||
{
|
||||
// lookup if we're allowed to overlap the content from the look&feel object
|
||||
PRBool canOverlap;
|
||||
PRInt32 canOverlap;
|
||||
nsPresContext* presContext = mOuter->PresContext();
|
||||
presContext->LookAndFeel()->
|
||||
GetMetric(nsILookAndFeel::eMetric_ScrollbarsCanOverlapContent, canOverlap);
|
||||
|
|
|
@ -88,7 +88,7 @@ nsTransformedTextRun::SetCapitalization(PRUint32 aStart, PRUint32 aLength,
|
|||
|
||||
PRBool
|
||||
nsTransformedTextRun::SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore,
|
||||
PRUint8* aBreakBefore,
|
||||
gfxContext* aRefContext)
|
||||
{
|
||||
PRBool changed = gfxTextRun::SetPotentialLineBreaks(aStart, aLength,
|
||||
|
@ -264,7 +264,7 @@ nsFontVariantTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
|||
PRUint32 runStart = 0;
|
||||
PRBool runIsLowercase = PR_FALSE;
|
||||
nsAutoTArray<nsStyleContext*,50> styleArray;
|
||||
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
||||
nsAutoTArray<PRUint8,50> canBreakBeforeArray;
|
||||
|
||||
PRUint32 i;
|
||||
for (i = 0; i <= length; ++i) {
|
||||
|
@ -338,7 +338,7 @@ nsCaseTransformTextRunFactory::RebuildTextRun(nsTransformedTextRun* aTextRun,
|
|||
nsAutoString convertedString;
|
||||
nsAutoTArray<PRPackedBool,50> charsToMergeArray;
|
||||
nsAutoTArray<nsStyleContext*,50> styleArray;
|
||||
nsAutoTArray<PRPackedBool,50> canBreakBeforeArray;
|
||||
nsAutoTArray<PRUint8,50> canBreakBeforeArray;
|
||||
PRUint32 extraCharsCount = 0;
|
||||
|
||||
PRUint32 i;
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
PRPackedBool* aCapitalization,
|
||||
gfxContext* aRefContext);
|
||||
virtual PRBool SetPotentialLineBreaks(PRUint32 aStart, PRUint32 aLength,
|
||||
PRPackedBool* aBreakBefore,
|
||||
PRUint8* aBreakBefore,
|
||||
gfxContext* aRefContext);
|
||||
/**
|
||||
* Called after SetCapitalization and SetPotentialLineBreaks
|
||||
|
|
|
@ -126,6 +126,12 @@ CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
|
|||
return PR_FALSE;
|
||||
}
|
||||
|
||||
/* virtual */ PRInt64
|
||||
CommonAnimationManager::SizeOf() const
|
||||
{
|
||||
return sizeof(*this);
|
||||
}
|
||||
|
||||
/* static */ PRBool
|
||||
CommonAnimationManager::ExtractComputedValueForTransition(
|
||||
nsCSSProperty aProperty,
|
||||
|
|
|
@ -71,6 +71,7 @@ public:
|
|||
virtual nsRestyleHint
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
|
||||
virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
|
||||
virtual PRInt64 SizeOf() const;
|
||||
|
||||
/**
|
||||
* Notify the manager that the pres context is going away.
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче