merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2014-10-27 15:50:43 +01:00
Родитель fdba7c2dc0 eea1f5cc9b
Коммит 8f9ca11b22
144 изменённых файлов: 3150 добавлений и 1619 удалений

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

@ -39,7 +39,7 @@ oopCommandlineHandler.prototype = {
}
},
helpInfo: " -oop Use out-of-process model in B2G\n",
helpInfo: " --oop Use out-of-process model in B2G\n",
classID: Components.ID("{e30b0e13-2d12-4cb0-bc4c-4e617a1bf76e}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
};

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

@ -35,9 +35,11 @@ int main(int argc, char* argv[], char* envp[]){
sprintf(full_path, "%s/%s", cwd, B2G_NAME);
sprintf(full_profile_path, "%s/%s", cwd, GAIA_PATH);
free(cwd);
printf("Running: %s -profile %s\n", full_path, full_profile_path);
printf("Running: %s --profile %s\n", full_path, full_profile_path);
fflush(stdout);
fflush(stderr);
// XXX: yes, the printf above says --profile and this execle uses -profile.
// Bug 1088430 will change the execle to use --profile.
execle(full_path, full_path, "-profile", full_profile_path, NULL, envp);
error("unable to start");
perror(argv[0]);

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

@ -4259,7 +4259,7 @@ nsBrowserAccess.prototype = {
var isExternal = (aContext == Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
if (isExternal && aURI && aURI.schemeIs("chrome")) {
dump("use -chrome command-line option to load external chrome urls\n");
dump("use --chrome command-line option to load external chrome urls\n");
return null;
}

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

@ -6,10 +6,10 @@ function test() {
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
is(gBrowser.tabs.length, tabCount + 1,
"'-new-tab about:blank' opens a new tab");
"'--new-tab about:blank' opens a new tab");
is(gBrowser.selectedTab, gBrowser.tabs[tabCount],
"'-new-tab about:blank' selects the new tab");
"'--new-tab about:blank' selects the new tab");
is(document.activeElement, gURLBar.inputField,
"'-new-tab about:blank' focuses the location bar");
"'--new-tab about:blank' focuses the location bar");
gBrowser.removeCurrentTab();
}

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

@ -92,7 +92,7 @@ function test() {
}
aWindow.gBrowser.addEventListener("pageshow", function pageShown(event) {
// If data: -url PAC file isn't loaded soon enough, we may get about:privatebrowsing loaded
// If data: --url PAC file isn't loaded soon enough, we may get about:privatebrowsing loaded
if (event.target.location == "about:blank" ||
event.target.location == "about:privatebrowsing") {
aWindow.gBrowser.selectedBrowser.loadURI(testURI);

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

@ -48,7 +48,7 @@ function shouldLoadURI(aURI) {
return true;
dump("*** Preventing external load of chrome: URI into browser window\n");
dump(" Use -chrome <uri> instead\n");
dump(" Use --chrome <uri> instead\n");
return false;
}
@ -456,16 +456,16 @@ nsBrowserContentHandler.prototype = {
#endif
},
helpInfo : " -browser Open a browser window.\n" +
" -new-window <url> Open <url> in a new window.\n" +
" -new-tab <url> Open <url> in a new tab.\n" +
" -private-window <url> Open <url> in a new private window.\n" +
helpInfo : " --browser Open a browser window.\n" +
" --new-window <url> Open <url> in a new window.\n" +
" --new-tab <url> Open <url> in a new tab.\n" +
" --private-window <url> Open <url> in a new private window.\n" +
#ifdef XP_WIN
" -preferences Open Options dialog.\n" +
" --preferences Open Options dialog.\n" +
#else
" -preferences Open Preferences dialog.\n" +
" --preferences Open Preferences dialog.\n" +
#endif
" -search <term> Search <term> with your default search engine.\n",
" --search <term> Search <term> with your default search engine.\n",
/* nsIBrowserHandler */

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

@ -3,7 +3,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* -setDefaultBrowser commandline handler
* --setDefaultBrowser commandline handler
* Makes the current executable the "default browser".
*/
@ -22,7 +22,7 @@ nsSetDefaultBrowser.prototype = {
}
},
helpInfo: " -setDefaultBrowser Set this app as the default browser.\n",
helpInfo: " --setDefaultBrowser Set this app as the default browser.\n",
classID: Components.ID("{F57899D0-4E2C-4ac6-9E29-50C736103B0C}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),

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

@ -67,8 +67,8 @@ devtoolsCommandlineHandler.prototype = {
}
},
helpInfo : " -jsconsole Open the Browser Console.\n" +
" -jsdebugger Open the Browser Toolbox.\n",
helpInfo : " --jsconsole Open the Browser Console.\n" +
" --jsdebugger Open the Browser Toolbox.\n",
classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),

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

@ -10,7 +10,7 @@ Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Services", "resource://gre/modules/Services.jsm");
/**
* Handles -webide command line option.
* Handles --webide command line option.
*/
function webideCli() { }
@ -23,10 +23,10 @@ webideCli.prototype = {
return;
}
// If -webide is used remotely, we don't want to open
// If --webide is used remotely, we don't want to open
// a new tab.
//
// If -webide is used for a new Firefox instance, we
// If --webide is used for a new Firefox instance, we
// want to open webide only.
cmdLine.preventDefault = true;

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

@ -137,10 +137,10 @@ BrowserCLH.prototype = {
#endif
// Instantiate the search service so the search engine cache is created now
// instead when the application is running. The install process will register
// this component by using the -silent command line flag, thereby creating
// this component by using the --silent command line flag, thereby creating
// the cache during install, not runtime.
// NOTE: This code assumes this CLH is run before the nsDefaultCLH, which
// consumes the "-silent" flag.
// consumes the "--silent" flag.
if (aCmdLine.findFlag("silent", false) > -1) {
let searchService = Services.search;
let autoComplete = Cc["@mozilla.org/autocomplete/search;1?name=history"].

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

@ -616,7 +616,7 @@ void LaunchDesktopBrowserWithParams(CStringW& aBrowserPath, CStringW& aVerb,
params += "\"";
}
// Tack on any extra parameters we received (for example -profilemanager)
// Tack on any extra parameters we received (for example --profilemanager)
if (!aParameters.IsEmpty()) {
params += " ";
params += aParameters;

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

@ -4005,7 +4005,7 @@ else
# Support comm-central.
if test -n "$EXTERNAL_SOURCE_DIR" ; then
MOZ_BUILD_APP="$EXTERNAL_SOURCE_DIR/$MOZ_BUILD_APP"
MOZ_BUILD_APP=`${PYTHON} -c "import os.path; print(os.path.relpath(\"${MOZ_BUILD_APP}\", \"${srcdir}\"))"`
MOZ_BUILD_APP=`${PYTHON} -c "import mozpack.path as mozpath; print(mozpath.relpath(\"${MOZ_BUILD_APP}\", \"${srcdir}\"))"`
fi
# We have a valid application only if it has a build.mk file in its top
# directory.

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

@ -9642,7 +9642,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// Disallow external chrome: loads targetted at content windows
bool isChrome = false;
if (NS_SUCCEEDED(aURI->SchemeIs("chrome", &isChrome)) && isChrome) {
NS_WARNING("blocked external chrome: url -- use '-chrome' option");
NS_WARNING("blocked external chrome: url -- use '--chrome' option");
return NS_ERROR_FAILURE;
}

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

@ -4141,11 +4141,6 @@ nsContentUtils::CreateContextualFragment(nsINode* aContextNode,
while (content && content->IsElement()) {
nsString& tagName = *tagStack.AppendElement();
if (!&tagName) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
tagName = content->NodeInfo()->QualifiedName();
// see if we need to add xmlns declarations

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

@ -9355,21 +9355,30 @@ nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, in
SelectionChangeEventInit init;
init.mBubbles = true;
if (aSel) {
nsCOMPtr<nsIDOMRange> range;
nsresult rv = aSel->GetRangeAt(0, getter_AddRefs(range));
if (NS_SUCCEEDED(rv) && range) {
nsRefPtr<nsRange> nsrange = static_cast<nsRange*>(range.get());
init.mBoundingClientRect = nsrange->GetBoundingClientRect(true, false);
range->ToString(init.mSelectedText);
Selection* selection = static_cast<Selection*>(aSel);
int32_t rangeCount = selection->GetRangeCount();
nsLayoutUtils::RectAccumulator accumulator;
for (int32_t idx = 0; idx < rangeCount; ++idx) {
nsRange* range = selection->GetRangeAt(idx);
nsRange::CollectClientRects(&accumulator, range,
range->GetStartParent(), range->StartOffset(),
range->GetEndParent(), range->EndOffset(),
true, false);
}
nsRect rect = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect :
accumulator.mResultRect;
nsRefPtr<DOMRect> domRect = new DOMRect(ToSupports(this));
domRect->SetLayoutRect(rect);
init.mBoundingClientRect = domRect;
for (uint32_t reasonType = 0;
reasonType < static_cast<uint32_t>(SelectionChangeReason::EndGuard_);
++reasonType) {
SelectionChangeReason strongReasonType =
static_cast<SelectionChangeReason>(reasonType);
if (CheckReason(aReason, strongReasonType)) {
init.mReasons.AppendElement(strongReasonType);
}
selection->Stringify(init.mSelectedText);
for (uint32_t reasonType = 0;
reasonType < static_cast<uint32_t>(SelectionChangeReason::EndGuard_);
++reasonType) {
SelectionChangeReason strongReasonType =
static_cast<SelectionChangeReason>(reasonType);
if (CheckReason(aReason, strongReasonType)) {
init.mReasons.AppendElement(strongReasonType);
}
}

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

@ -26,7 +26,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=811701
is(math.outerHTML, "<math><mtext>test</mtext></math>",
"<math> should have innerHTML");
math.innerHTML = "<mo>+</mo>";
is(math.firstChild.namespaceURI, "http://www.w3.org/1999/xhtml",
is(math.firstChild.namespaceURI, "http://www.w3.org/1998/Math/MathML",
"Should have the right namespace after setting innerHTML on <math>");
var polygon = document.querySelector("polygon");
@ -41,8 +41,8 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=811701
var svg = document.querySelector("svg");
svg.innerHTML = "<rect/>";
is(svg.firstChild.namespaceURI, "http://www.w3.org/1999/xhtml",
"Should have the right namespace after setting innerHTML on <math>");
is(svg.firstChild.namespaceURI, "http://www.w3.org/2000/svg",
"Should have the right namespace after setting innerHTML on <svg>");
</script>
</body>
</html>

0
dom/html/HTMLMediaElement.cpp Executable file → Normal file
Просмотреть файл

0
dom/html/HTMLMediaElement.h Executable file → Normal file
Просмотреть файл

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

@ -173,10 +173,6 @@ protected:
// yet. We want to make sure to only do this once.
bool mNotifiedRootInsertion;
uint8_t mScriptEnabled : 1;
uint8_t mFramesEnabled : 1;
uint8_t unused : 6; // bits available if someone needs one
mozilla::dom::NodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1];
nsresult FlushTags();
@ -724,25 +720,6 @@ NS_INTERFACE_TABLE_TAIL_INHERITING(nsContentSink)
NS_IMPL_ADDREF_INHERITED(HTMLContentSink, nsContentSink)
NS_IMPL_RELEASE_INHERITED(HTMLContentSink, nsContentSink)
static bool
IsScriptEnabled(nsIDocument *aDoc, nsIDocShell *aContainer)
{
NS_ENSURE_TRUE(aDoc && aContainer, true);
nsCOMPtr<nsIScriptGlobalObject> globalObject =
do_QueryInterface(aDoc->GetInnerWindow());
// Getting context is tricky if the document hasn't had its
// GlobalObject set yet
if (!globalObject) {
globalObject = aContainer->GetScriptGlobalObject();
}
NS_ENSURE_TRUE(globalObject && globalObject->GetGlobalJSObject(), true);
return nsContentUtils::GetSecurityManager()->
ScriptAllowed(globalObject->GetGlobalJSObject());
}
nsresult
HTMLContentSink::Init(nsIDocument* aDoc,
nsIURI* aURI,
@ -762,21 +739,6 @@ HTMLContentSink::Init(nsIDocument* aDoc,
NS_ASSERTION(mDocShell, "oops no docshell!");
// Find out if subframes are enabled
if (mDocShell) {
bool subFramesEnabled = true;
mDocShell->GetAllowSubframes(&subFramesEnabled);
if (subFramesEnabled) {
mFramesEnabled = true;
}
}
// Find out if scripts are enabled, if not, show <noscript> content
if (IsScriptEnabled(aDoc, mDocShell)) {
mScriptEnabled = true;
}
// Changed from 8192 to greatly improve page loading performance on
// large pages. See bugzilla bug 77540.
mMaxTextRun = Preferences::GetInt("content.maxtextrun", 8191);

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

@ -213,7 +213,9 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mDropVideoUntilNextDiscontinuity(false),
mDecodeToSeekTarget(false),
mCurrentTimeBeforeSeek(0),
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED)
mLastFrameStatus(MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED),
mDecodingFrozenAtStateMetadata(false),
mDecodingFrozenAtStateDecoding(false)
{
MOZ_COUNT_CTOR(MediaDecoderStateMachine);
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
@ -1356,8 +1358,9 @@ void MediaDecoderStateMachine::SetDormant(bool aDormant)
SetState(DECODER_STATE_DORMANT);
mDecoder->GetReentrantMonitor().NotifyAll();
} else if ((aDormant != true) && (mState == DECODER_STATE_DORMANT)) {
mDecodingFrozenAtStateMetadata = true;
mDecodingFrozenAtStateDecoding = true;
ScheduleStateMachine();
mStartTime = 0;
mCurrentFrameTime = 0;
SetState(DECODER_STATE_DECODING_NONE);
mDecoder->GetReentrantMonitor().NotifyAll();
@ -1454,6 +1457,10 @@ void MediaDecoderStateMachine::Play()
SetState(DECODER_STATE_DECODING);
mDecodeStartTime = TimeStamp::Now();
}
if (mDecodingFrozenAtStateDecoding) {
mDecodingFrozenAtStateDecoding = false;
DispatchDecodeTasksIfNeeded();
}
// Once we start playing, we don't want to minimize our prerolling, as we
// assume the user is likely to want to keep playing in future.
mMinimizePreroll = false;
@ -1515,6 +1522,8 @@ void MediaDecoderStateMachine::Seek(const SeekTarget& aTarget)
NS_ASSERTION(NS_IsMainThread(), "Should be on main thread.");
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecodingFrozenAtStateDecoding = false;
if (mState == DECODER_STATE_SHUTDOWN) {
return;
}
@ -1622,6 +1631,11 @@ MediaDecoderStateMachine::DispatchDecodeTasksIfNeeded()
return;
}
if (mState == DECODER_STATE_DECODING && mDecodingFrozenAtStateDecoding) {
DECODER_LOG("DispatchDecodeTasksIfNeeded return due to "
"mFreezeDecodingAtStateDecoding");
return;
}
// NeedToDecodeAudio() can go from false to true while we hold the
// monitor, but it can't go from true to false. This can happen because
// NeedToDecodeAudio() takes into account the amount of decoded audio
@ -1972,6 +1986,10 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
SetStartTime(0);
res = FinishDecodeMetadata();
NS_ENSURE_SUCCESS(res, res);
} else if (mDecodingFrozenAtStateMetadata) {
SetStartTime(mStartTime);
res = FinishDecodeMetadata();
NS_ENSURE_SUCCESS(res, res);
} else {
if (HasAudio()) {
ReentrantMonitorAutoExit unlock(mDecoder->GetReentrantMonitor());
@ -1997,7 +2015,7 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
return NS_ERROR_FAILURE;
}
if (!mScheduler->IsRealTime()) {
if (!mScheduler->IsRealTime() && !mDecodingFrozenAtStateMetadata) {
const VideoData* v = VideoQueue().PeekFront();
const AudioData* a = AudioQueue().PeekFront();
@ -2029,6 +2047,8 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
mStartTime, mEndTime, GetDuration(),
mDecoder->IsTransportSeekable(), mDecoder->IsMediaSeekable());
mDecodingFrozenAtStateMetadata = false;
if (HasAudio() && !HasVideo()) {
// We're playing audio only. We don't need to worry about slow video
// decodes causing audio underruns, so don't buffer so much audio in

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

@ -921,6 +921,17 @@ protected:
mozilla::MediaMetadataManager mMetadataManager;
MediaDecoderOwner::NextFrameStatus mLastFrameStatus;
// True if we are back from DECODER_STATE_DORMANT state, and we can skip
// SetStartTime because the mStartTime already set before. Also we don't need
// to decode any audio/video since the MediaDecoder will trigger a seek
// operation soon.
// mDecodingFrozenAtStateMetadata: turn on/off at
// SetDormant/FinishDecodeMetadata.
// mDecodingFrozenAtStateDecoding: turn on/off at
// SetDormant/Seek,Play.
bool mDecodingFrozenAtStateMetadata;
bool mDecodingFrozenAtStateDecoding;
};
} // namespace mozilla;

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

@ -101,16 +101,4 @@ RtspMediaCodecReader::ReadMetadata(MediaInfo* aInfo,
return rv;
}
// Called on Binder thread.
void
RtspMediaCodecReader::codecReserved(Track& aTrack)
{
// TODO: fix me, we need a SeekTime(0) here because the
// MediaDecoderStateMachine will update the mStartTime after ReadMetadata.
MediaCodecReader::codecReserved(aTrack);
if (aTrack.mCodec != nullptr) {
mRtspResource->SeekTime(0);
}
}
} // namespace mozilla

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

@ -65,8 +65,6 @@ public:
virtual nsresult ReadMetadata(MediaInfo* aInfo,
MetadataTags** aTags) MOZ_OVERRIDE;
virtual void codecReserved(Track& aTrack) MOZ_OVERRIDE;
private:
// A pointer to RtspMediaResource for calling the Rtsp specific function.
// The lifetime of mRtspResource is controlled by MediaDecoder. MediaDecoder

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

@ -7,6 +7,8 @@
#include "nsGkAtoms.h"
#include "mozilla/dom/SVGRectElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Matrix.h"
#include "mozilla/gfx/Rect.h"
#include "mozilla/gfx/PathHelpers.h"
#include <algorithm>
@ -108,6 +110,36 @@ SVGRectElement::GetLengthInfo()
//----------------------------------------------------------------------
// nsSVGPathGeometryElement methods
bool
SVGRectElement::GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
const Matrix& aTransform)
{
Rect r;
Float rx, ry;
GetAnimatedLengthValues(&r.x, &r.y, &r.width, &r.height, &rx, &ry, nullptr);
if (r.IsEmpty()) {
// Rendering of the element disabled
r.SetEmpty(); // make sure width/height are actually zero
*aBounds = r;
return true;
}
rx = std::max(rx, 0.0f);
ry = std::max(ry, 0.0f);
if (rx != 0 || ry != 0) {
return false;
}
if (aStrokeWidth > 0.f) {
r.Inflate(aStrokeWidth / 2.f);
}
*aBounds = aTransform.TransformBounds(r);
return true;
}
void
SVGRectElement::GetAsSimplePath(SimplePath* aSimplePath)
{

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

@ -30,6 +30,8 @@ public:
virtual bool HasValidDimensions() const MOZ_OVERRIDE;
// nsSVGPathGeometryElement methods:
virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
const Matrix& aTransform) MOZ_OVERRIDE;
virtual void GetAsSimplePath(SimplePath* aSimplePath) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;

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

@ -34,6 +34,7 @@ protected:
typedef mozilla::gfx::DrawTarget DrawTarget;
typedef mozilla::gfx::FillRule FillRule;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Matrix Matrix;
typedef mozilla::gfx::Path Path;
typedef mozilla::gfx::Point Point;
typedef mozilla::gfx::PathBuilder PathBuilder;
@ -69,6 +70,11 @@ public:
virtual bool IsMarkable();
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
virtual bool GetGeometryBounds(Rect* aBounds, Float aStrokeWidth,
const Matrix& aTransform) {
return false;
}
/**
* For use with GetAsSimplePath.
*/

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

@ -174,6 +174,9 @@ uint32_t gMaxWorkersPerDomain = MAX_WORKERS_PER_DOMAIN;
// Does not hold an owning reference.
RuntimeService* gRuntimeService = nullptr;
// Only true during the call to Init.
bool gRuntimeServiceDuringInit = false;
#ifdef ENABLE_TESTS
bool gTestPBackground = false;
#endif // ENABLE_TESTS
@ -464,13 +467,14 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
// If we're running in Init() then do this for every pref we care about.
// Otherwise we just want to update the parameter that changed.
for (uint32_t index = rts ? JSSettings::kGCSettingsArraySize - 1 : 0;
for (uint32_t index = !gRuntimeServiceDuringInit
? JSSettings::kGCSettingsArraySize - 1 : 0;
index < JSSettings::kGCSettingsArraySize;
index++) {
LiteralRebindingCString matchName;
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "max");
if (memPrefName == matchName || (!rts && index == 0)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 0)) {
int32_t prefValue = GetWorkerPref(matchName, -1);
uint32_t value = (prefValue <= 0 || prefValue >= 0x1000) ?
uint32_t(-1) :
@ -480,7 +484,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "high_water_mark");
if (memPrefName == matchName || (!rts && index == 1)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 1)) {
int32_t prefValue = GetWorkerPref(matchName, 128);
UpdatOtherJSGCMemoryOption(rts, JSGC_MAX_MALLOC_BYTES,
uint32_t(prefValue) * 1024 * 1024);
@ -489,7 +493,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_high_frequency_time_limit_ms");
if (memPrefName == matchName || (!rts && index == 2)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 2)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_HIGH_FREQUENCY_TIME_LIMIT);
continue;
@ -497,7 +501,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_low_frequency_heap_growth");
if (memPrefName == matchName || (!rts && index == 3)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 3)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_LOW_FREQUENCY_HEAP_GROWTH);
continue;
@ -505,7 +509,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_high_frequency_heap_growth_min");
if (memPrefName == matchName || (!rts && index == 4)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 4)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MIN);
continue;
@ -513,7 +517,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_high_frequency_heap_growth_max");
if (memPrefName == matchName || (!rts && index == 5)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 5)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_HIGH_FREQUENCY_HEAP_GROWTH_MAX);
continue;
@ -521,7 +525,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_high_frequency_low_limit_mb");
if (memPrefName == matchName || (!rts && index == 6)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 6)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_HIGH_FREQUENCY_LOW_LIMIT);
continue;
@ -529,7 +533,7 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_high_frequency_high_limit_mb");
if (memPrefName == matchName || (!rts && index == 7)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 7)) {
UpdateCommonJSGCMemoryOption(rts, matchName,
JSGC_HIGH_FREQUENCY_HIGH_LIMIT);
continue;
@ -537,13 +541,13 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX
"gc_allocation_threshold_mb");
if (memPrefName == matchName || (!rts && index == 8)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 8)) {
UpdateCommonJSGCMemoryOption(rts, matchName, JSGC_ALLOCATION_THRESHOLD);
continue;
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_incremental_slice_ms");
if (memPrefName == matchName || (!rts && index == 9)) {
if (memPrefName == matchName || (gRuntimeServiceDuringInit && index == 9)) {
int32_t prefValue = GetWorkerPref(matchName, -1);
uint32_t value =
(prefValue <= 0 || prefValue >= 100000) ? 0 : uint32_t(prefValue);
@ -552,7 +556,8 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_dynamic_heap_growth");
if (memPrefName == matchName || (!rts && index == 10)) {
if (memPrefName == matchName ||
(gRuntimeServiceDuringInit && index == 10)) {
bool prefValue = GetWorkerPref(matchName, false);
UpdatOtherJSGCMemoryOption(rts, JSGC_DYNAMIC_HEAP_GROWTH,
prefValue ? 0 : 1);
@ -560,7 +565,8 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_dynamic_mark_slice");
if (memPrefName == matchName || (!rts && index == 11)) {
if (memPrefName == matchName ||
(gRuntimeServiceDuringInit && index == 11)) {
bool prefValue = GetWorkerPref(matchName, false);
UpdatOtherJSGCMemoryOption(rts, JSGC_DYNAMIC_MARK_SLICE,
prefValue ? 0 : 1);
@ -568,13 +574,15 @@ LoadJSGCMemoryOptions(const char* aPrefName, void* /* aClosure */)
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_min_empty_chunk_count");
if (memPrefName == matchName || (!rts && index == 12)) {
if (memPrefName == matchName ||
(gRuntimeServiceDuringInit && index == 12)) {
UpdateCommonJSGCMemoryOption(rts, matchName, JSGC_MIN_EMPTY_CHUNK_COUNT);
continue;
}
matchName.RebindLiteral(PREF_MEM_OPTIONS_PREFIX "gc_max_empty_chunk_count");
if (memPrefName == matchName || (!rts && index == 13)) {
if (memPrefName == matchName ||
(gRuntimeServiceDuringInit && index == 13)) {
UpdateCommonJSGCMemoryOption(rts, matchName, JSGC_MAX_EMPTY_CHUNK_COUNT);
continue;
}
@ -1765,6 +1773,9 @@ RuntimeService::Init()
NS_WARNING("Failed to register for offline notification event!");
}
MOZ_ASSERT(!gRuntimeServiceDuringInit, "This should be false!");
gRuntimeServiceDuringInit = true;
if (NS_FAILED(Preferences::RegisterCallback(
LoadJSGCMemoryOptions,
PREF_JS_OPTIONS_PREFIX PREF_MEM_OPTIONS_PREFIX,
@ -1822,6 +1833,9 @@ RuntimeService::Init()
NS_WARNING("Failed to register pref callbacks!");
}
MOZ_ASSERT(gRuntimeServiceDuringInit, "Should be true!");
gRuntimeServiceDuringInit = false;
// We assume atomic 32bit reads/writes. If this assumption doesn't hold on
// some wacky platform then the worst that could happen is that the close
// handler will run for a slightly different amount of time.

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

@ -262,7 +262,7 @@ APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
apzc = insertResult.first->second;
PrintAPZCInfo(aLayer, apzc);
}
APZCTM_LOG("Found APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
APZCTM_LOG("Found APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), guid.mLayersId, guid.mScrollId);
// If we haven't encountered a layer already with the same metrics, then we need to
// do the full reuse-or-make-an-APZC algorithm, which is contained inside the block
@ -315,7 +315,7 @@ APZCTreeManager::PrepareAPZCForLayer(const LayerMetricsWrapper& aLayer,
apzc->SetPrevSibling(nullptr);
apzc->SetLastChild(nullptr);
}
APZCTM_LOG("Using APZC %p for layer %p with identifiers %lld %lld\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
APZCTM_LOG("Using APZC %p for layer %p with identifiers %" PRId64 " %" PRId64 "\n", apzc, aLayer.GetLayer(), aLayersId, aMetrics.GetScrollId());
apzc->NotifyLayersUpdated(aMetrics,
aState.mIsFirstPaint && (aLayersId == aState.mOriginatingLayersId));

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

@ -105,7 +105,7 @@ uint64_t
InputQueue::InjectNewTouchBlock(AsyncPanZoomController* aTarget)
{
TouchBlockState* block = StartNewTouchBlock(aTarget, true);
INPQ_LOG("%p injecting new touch block with id %llu and target %p\n",
INPQ_LOG("%p injecting new touch block with id %" PRIu64 " and target %p\n",
this, block->GetBlockId(), aTarget);
ScheduleContentResponseTimeout(aTarget, block->GetBlockId());
return block->GetBlockId();
@ -162,7 +162,7 @@ void
InputQueue::ContentResponseTimeout(const uint64_t& aInputBlockId) {
AsyncPanZoomController::AssertOnControllerThread();
INPQ_LOG("got a content response timeout; block=%llu\n", aInputBlockId);
INPQ_LOG("got a content response timeout; block=%" PRIu64 "\n", aInputBlockId);
bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
@ -179,7 +179,7 @@ void
InputQueue::ContentReceivedTouch(uint64_t aInputBlockId, bool aPreventDefault) {
AsyncPanZoomController::AssertOnControllerThread();
INPQ_LOG("got a content response; block=%llu\n", aInputBlockId);
INPQ_LOG("got a content response; block=%" PRIu64 "\n", aInputBlockId);
bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {
@ -196,7 +196,7 @@ void
InputQueue::SetAllowedTouchBehavior(uint64_t aInputBlockId, const nsTArray<TouchBehaviorFlags>& aBehaviors) {
AsyncPanZoomController::AssertOnControllerThread();
INPQ_LOG("got allowed touch behaviours; block=%llu\n", aInputBlockId);
INPQ_LOG("got allowed touch behaviours; block=%" PRIu64 "\n", aInputBlockId);
bool success = false;
for (size_t i = 0; i < mTouchBlockQueue.Length(); i++) {
if (mTouchBlockQueue[i]->GetBlockId() == aInputBlockId) {

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

@ -1521,7 +1521,6 @@ TEST_F(APZCGestureDetectorTester, DoubleTapPreventDefaultBoth) {
int time = 0;
uint64_t blockIds[2];
ApzcDoubleTapAndCheckStatus(apzc, 10, 10, time, &blockIds);
printf_stderr("blockids %llu %llu\n", blockIds[0], blockIds[1]);
// responses to the two touchstarts
apzc->ContentReceivedTouch(blockIds[0], true);

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

@ -324,22 +324,6 @@ gfxContext::QuadraticCurveTo(const gfxPoint& pt1, const gfxPoint& pt2)
mPathBuilder->QuadraticBezierTo(ToPoint(pt1), ToPoint(pt2));
}
void
gfxContext::Arc(const gfxPoint& center, gfxFloat radius,
gfxFloat angle1, gfxFloat angle2)
{
EnsurePathBuilder();
mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle1), Float(angle2));
}
void
gfxContext::NegativeArc(const gfxPoint& center, gfxFloat radius,
gfxFloat angle1, gfxFloat angle2)
{
EnsurePathBuilder();
mPathBuilder->Arc(ToPoint(center), Float(radius), Float(angle2), Float(angle1));
}
void
gfxContext::Line(const gfxPoint& start, const gfxPoint& end)
{

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

@ -135,7 +135,7 @@ public:
mozilla::TemporaryRef<Path> GetPath();
/**
* Appends the given path to the current path.
* Sets the given path as the current path.
*/
void SetPath(Path* path);
@ -172,27 +172,6 @@ public:
*/
void QuadraticCurveTo(const gfxPoint& pt1, const gfxPoint& pt2);
/**
* Draws a clockwise arc (i.e. a circle segment).
* @param center The center of the circle
* @param radius The radius of the circle
* @param angle1 Starting angle for the segment
* @param angle2 Ending angle
*/
void Arc(const gfxPoint& center, gfxFloat radius,
gfxFloat angle1, gfxFloat angle2);
/**
* Draws a counter-clockwise arc (i.e. a circle segment).
* @param center The center of the circle
* @param radius The radius of the circle
* @param angle1 Starting angle for the segment
* @param angle2 Ending angle
*/
void NegativeArc(const gfxPoint& center, gfxFloat radius,
gfxFloat angle1, gfxFloat angle2);
// path helpers
/**
* Draws a line from start to end.

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

@ -1572,6 +1572,16 @@ gfxWindowsPlatform::InitD3D11Devices()
{
mD3D11DeviceInitialized = true;
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
int32_t status;
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_DIRECT3D_11_LAYERS, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
return;
}
}
}
nsModuleHandle d3d11Module(LoadLibrarySystem32(L"d3d11.dll"));
decltype(D3D11CreateDevice)* d3d11CreateDevice = (decltype(D3D11CreateDevice)*)
GetProcAddress(d3d11Module, "D3D11CreateDevice");

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

@ -135,7 +135,7 @@ this.PluralForm = {
// Check for array out of bounds or empty strings
if ((ret == undefined) || (ret == "")) {
// Report the caller to help figure out who is causing badness
let caller = PluralForm.get.caller ? PluralForm.get.caller.name : "top";
let caller = Components.stack.caller ? Components.stack.caller.name : "top";
// Display a message in the error console
log(["Index #", index, " of '", aWords, "' for value ", aNum,

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

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* This unit test makes sure that PluralForm.get can be called from strict mode
*/
Components.utils.import("resource://gre/modules/PluralForm.jsm");
delete PluralForm.numForms;
delete PluralForm.get;
[PluralForm.get, PluralForm.numForms] = PluralForm.makeGetter(9);
function run_test() {
"use strict";
do_check_eq(3, PluralForm.numForms());
do_check_eq("one", PluralForm.get(5, 'one;many'));
}

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

@ -13,6 +13,7 @@ skip-if = toolkit == "windows" || toolkit == "cocoa"
[test_collation_mac_icu.js]
run-if = toolkit == "cocoa"
[test_bug1086527.js]
[test_pluralForm.js]
[test_pluralForm_english.js]
[test_pluralForm_makeGetter.js]

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

@ -466,7 +466,7 @@ namespace js {
// Unary SIMD operators
template<typename T>
struct Abs {
static inline T apply(T x) { return x < 0 ? -1 * x : x; }
static inline T apply(T x) { return mozilla::Abs(x); }
};
template<typename T>
struct Neg {
@ -712,14 +712,14 @@ Swizzle(JSContext *cx, unsigned argc, Value *vp)
if (args.length() != (V::lanes + 1) || !IsVectorObject<V>(args[0]))
return ErrorBadArgs(cx);
int32_t lanes[V::lanes];
uint32_t lanes[V::lanes];
for (unsigned i = 0; i < V::lanes; i++) {
int32_t lane = -1;
if (!ToInt32(cx, args[i + 1], &lane))
return false;
if (lane < 0 || lane >= V::lanes)
if (lane < 0 || uint32_t(lane) >= V::lanes)
return ErrorBadArgs(cx);
lanes[i] = lane;
lanes[i] = uint32_t(lane);
}
Elem *val = TypedObjectMemory<Elem *>(args[0]);
@ -741,14 +741,14 @@ Shuffle(JSContext *cx, unsigned argc, Value *vp)
if (args.length() != (V::lanes + 2) || !IsVectorObject<V>(args[0]) || !IsVectorObject<V>(args[1]))
return ErrorBadArgs(cx);
int32_t lanes[V::lanes];
uint32_t lanes[V::lanes];
for (unsigned i = 0; i < V::lanes; i++) {
int32_t lane = -1;
if (!ToInt32(cx, args[i + 2], &lane))
return false;
if (lane < 0 || lane >= (2 * V::lanes))
if (lane < 0 || uint32_t(lane) >= (2 * V::lanes))
return ErrorBadArgs(cx);
lanes[i] = lane;
lanes[i] = uint32_t(lane);
}
Elem *lhs = TypedObjectMemory<Elem *>(args[0]);

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

@ -8,8 +8,6 @@ var summary = 'float32x4 abs';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(-1, 2, -3, 4);
var c = SIMD.float32x4.abs(a);
assertEq(c.x, 1);
@ -17,6 +15,20 @@ function test() {
assertEq(c.z, 3);
assertEq(c.w, 4);
var d = float32x4(-1.63, 2.46, -3.17, 4.94);
var f = SIMD.float32x4.abs(d);
assertEq(f.x, Math.fround(1.63));
assertEq(f.y, Math.fround(2.46));
assertEq(f.z, Math.fround(3.17));
assertEq(f.w, Math.fround(4.94));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.abs(g);
assertEq(i.x, NaN);
assertEq(i.y, 0);
assertEq(i.z, Infinity);
assertEq(i.w, Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,11 +5,13 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 add';
function addf(a, b) {
return Math.fround(Math.fround(a) + Math.fround(b));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.add(a, b);
@ -18,6 +20,22 @@ function test() {
assertEq(c.z, 33);
assertEq(c.w, 44);
var d = float32x4(1.57, 2.27, 3.57, 4.19);
var e = float32x4(10.31, 20.49, 30.41, 40.72);
var f = SIMD.float32x4.add(d, e);
assertEq(f.x, addf(1.57, 10.31));
assertEq(f.y, addf(2.27, 20.49));
assertEq(f.z, addf(3.57, 30.41));
assertEq(f.w, addf(4.19, 40.72));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var h = float32x4(0, -0, -Infinity, -Infinity);
var i = SIMD.float32x4.add(g, h);
assertEq(i.x, NaN);
assertEq(i.y, -0);
assertEq(i.z, NaN);
assertEq(i.w, -Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -19,8 +19,6 @@ var andf = (function() {
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.and(a, b);
@ -29,6 +27,22 @@ function test() {
assertEq(c.z, andf(3, 30));
assertEq(c.w, andf(4, 40));
var d = float32x4(1.51, 2.98, 3.65, 4.34);
var e = float32x4(10.29, 20.12, 30.79, 40.41);
var f = SIMD.float32x4.and(d, e);
assertEq(f.x, andf(1.51, 10.29));
assertEq(f.y, andf(2.98, 20.12));
assertEq(f.z, andf(3.65, 30.79));
assertEq(f.w, andf(4.34, 40.41));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var h = float32x4(NaN, -0, -Infinity, Infinity);
var i = SIMD.float32x4.and(g, h);
assertEq(i.x, NaN);
assertEq(i.y, -0);
assertEq(i.z, Infinity);
assertEq(i.w, Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,14 +8,34 @@ var summary = 'float32x4 clamp';
function test() {
print(BUGNUMBER + ": " + summary);
var a = float32x4(-13.37, 10.46, 31.79, 0.54);
var lower = float32x4(2.1, 1.1, 50.13, 0.0);
var upper = float32x4(2.56, 5.55, 55.93, 1.1);
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(-20, 10, 30, 0.5);
var lower = float32x4(2, 1, 50, 0);
var upper = float32x4(2.5, 5, 55, 1);
var c = SIMD.float32x4.clamp(a, lower, upper);
assertEq(c.x, Math.fround(2.1));
assertEq(c.y, Math.fround(5.55));
assertEq(c.z, Math.fround(50.13));
assertEq(c.w, Math.fround(0.54));
assertEq(c.x, 2);
assertEq(c.y, 5);
assertEq(c.z, 50);
assertEq(c.w, 0.5);
var d = float32x4(-13.37, 10.46, 31.79, 0.54);
var lower1 = float32x4(2.1, 1.1, 50.13, 0.0);
var upper1 = float32x4(2.56, 5.55, 55.93, 1.1);
var f = SIMD.float32x4.clamp(d, lower1, upper1);
assertEq(f.x, Math.fround(2.1));
assertEq(f.y, Math.fround(5.55));
assertEq(f.z, Math.fround(50.13));
assertEq(f.w, Math.fround(0.54));
var g = float32x4(4, -Infinity, 10, -10);
var lower2 = float32x4(5, -Infinity, -Infinity, -Infinity);
var upper2 = float32x4(Infinity, 5, Infinity, Infinity);
var i = SIMD.float32x4.clamp(g, lower2, upper2);
assertEq(i.x, 5);
assertEq(i.y, -Infinity);
assertEq(i.z, 10);
assertEq(i.w, -10);
if (typeof reportCompare === "function")
reportCompare(true, true);

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

@ -5,22 +5,39 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 div';
function divf(a, b) {
return Math.fround(Math.fround(a) / Math.fround(b));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.div(b,a);
var c = SIMD.float32x4.div(b, a);
assertEq(c.x, 10);
assertEq(c.y, 10);
assertEq(c.z, 10);
assertEq(c.w, 10);
var d = float32x4(1.26, 2.03, 3.17, 4.59);
var e = float32x4(11.025, 17.3768, 29.1957, 46.4049);
var f = SIMD.float32x4.div(e, d);
assertEq(f.x, divf(11.025, 1.26));
assertEq(f.y, divf(17.3768, 2.03));
assertEq(f.z, divf(29.1957, 3.17));
assertEq(f.w, divf(46.4049, 4.59));
var g = float32x4(0, -0, Infinity, -Infinity);
var h = float32x4(1, 1, -Infinity, Infinity);
var i = SIMD.float32x4.div(h, g);
assertEq(i.x, Infinity);
assertEq(i.y, -Infinity);
assertEq(i.z, NaN);
assertEq(i.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -8,7 +8,7 @@ var summary = 'float32x4 equal';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of NaN/-0/Infinity/-Infinity border cases.
var a = float32x4(1, 20, 30, 40);
var b = float32x4(10, 20, 30, 4);
@ -18,6 +18,14 @@ function test() {
assertEq(c.z, -1);
assertEq(c.w, 0);
var d = float32x4(1.89, 20.51, 30.46, 40.12);
var e = float32x4(10.89, 20.51, Math.fround(30.46), 4.12);
var f = SIMD.float32x4.equal(d, e);
assertEq(c.x, 0);
assertEq(c.y, -1);
assertEq(c.z, -1);
assertEq(c.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 fromInt32x4';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var a = int32x4(1, 2, 3, 4);
var c = SIMD.float32x4.fromInt32x4(a);
@ -17,6 +18,15 @@ function test() {
assertEq(c.z, 3);
assertEq(c.w, 4);
var value1 = Math.pow(2, 30) - 1;
var value2 = -Math.pow(2, 30);
var d = int32x4(INT32_MIN, INT32_MAX, value1, value2);
var f = float32x4.fromInt32x4(d);
assertEq(f.x, Math.fround(INT32_MIN));
assertEq(f.y, Math.fround(INT32_MAX));
assertEq(f.z, Math.fround(value1));
assertEq(f.w, Math.fround(value2));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 fromInt32x4Bits';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var INT32_MAX = Math.pow(2, 31) - 1;
var INT32_MIN = -Math.pow(2, 31);
var a = int32x4(100, 200, 300, 400);
var c = SIMD.float32x4.fromInt32x4Bits(a);
@ -17,6 +18,13 @@ function test() {
assertEq(c.z, 4.203895392974451e-43);
assertEq(c.w, 5.605193857299268e-43);
var d = int32x4(INT32_MIN, INT32_MAX, 0, 0);
var f = float32x4.fromInt32x4Bits(d);
assertEq(f.x, -0);
assertEq(f.y, NaN);
assertEq(f.z, 0);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,16 +8,25 @@ var summary = 'float32x4 greaterThan';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 3, 40);
var b = float32x4(10, 2, 30, 4);
var c = SIMD.float32x4.greaterThan(b,a);
var c = SIMD.float32x4.greaterThan(b, a);
assertEq(c.x, -1);
assertEq(c.y, 0);
assertEq(c.z, -1);
assertEq(c.w, 0);
var d = float32x4(10.8399, 20.37, 3.07, 4.6802);
var e = float32x4(10.8401, 20.367, 3.1, 4.6801);
var f = float32x4.greaterThan(e, d);
assertEq(f.x, -1);
assertEq(f.y, 0);
assertEq(f.z, -1);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,16 +8,25 @@ var summary = 'float32x4 greaterThanOrEqual';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 30, 40);
var b = float32x4(10, 20, 30, 4);
var c = SIMD.float32x4.greaterThanOrEqual(b,a);
var c = SIMD.float32x4.greaterThanOrEqual(b, a);
assertEq(c.x, -1);
assertEq(c.y, -1);
assertEq(c.z, -1);
assertEq(c.w, 0);
var d = float32x4(10.029, 20.87, 30.56, 4.7);
var e = float32x4(10.03, 20.87, 30.56, 4.698);
var f = float32x4.greaterThanOrEqual(e, d);
assertEq(f.x, -1);
assertEq(f.y, -1);
assertEq(f.z, -1);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 lessThan';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 3, 40);
var b = float32x4(10, 2, 30, 4);
@ -18,6 +19,14 @@ function test() {
assertEq(c.z, -1);
assertEq(c.w, 0);
var d = float32x4(1.5399, 20.001, 30.045, 4.74);
var e = float32x4(1.54, 19.999, 30.05, 4.72);
var f = float32x4.lessThan(a, b);
assertEq(f.x, -1);
assertEq(f.y, 0);
assertEq(f.z, -1);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 lessThanOrEqual';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 30, 40);
var b = float32x4(10, 20, 30, 4);
@ -18,6 +19,14 @@ function test() {
assertEq(c.z, -1);
assertEq(c.w, 0);
var d = float32x4(9.999, 20.78, 30.14, 40.1235);
var e = float32x4(10, 20.78, 30.14, 40.123);
var f = float32x4.lessThanOrEqual(d, e);
assertEq(f.x, -1);
assertEq(f.y, -1);
assertEq(f.z, -1);
assertEq(f.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 max';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 30, 4);
var b = float32x4(10, 2, 3, 40);
@ -18,6 +19,14 @@ function test() {
assertEq(c.z, 30);
assertEq(c.w, 40);
var d = float32x4(9.999, 2.1234, 30.4443, 4);
var e = float32x4(10, 2.1233, 30.4444, 4.0001);
var f = float32x4.max(d, e);
assertEq(f.x, 10);
assertEq(f.y, Math.fround(2.1234));
assertEq(f.z, Math.fround(30.4444));
assertEq(f.w, Math.fround(4.0001));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,8 @@ var summary = 'float32x4 min';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of -0/Infinity/-Infinity border cases.
// FIXME -- Bug 1068028: Amend to check for correctness of NaN border cases once the semantics are defined.
var a = float32x4(1, 20, 3, 40);
var b = float32x4(10, 2, 30, 4);
@ -18,6 +19,14 @@ function test() {
assertEq(c.z, 3);
assertEq(c.w, 4);
var d = float32x4(1.4321, 20.5567, 30.8999, 4.0002);
var e = float32x4(1.432, 20.5568, 30.8998, 4.0001);
var f = float32x4.min(d, e);
assertEq(f.x, Math.fround(1.432));
assertEq(f.y, Math.fround(20.5567));
assertEq(f.z, Math.fround(30.8998));
assertEq(f.w, Math.fround(4.0001));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -3,13 +3,15 @@ var BUGNUMBER = 946042;
var float32x4 = SIMD.float32x4;
var int32x4 = SIMD.int32x4;
var summary = 'float32x4 add';
var summary = 'float32x4 mul';
function mulf(a, b) {
return Math.fround(Math.fround(a) * Math.fround(b));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.mul(a, b);
@ -18,9 +20,24 @@ function test() {
assertEq(c.z, 90);
assertEq(c.w, 160);
var d = float32x4(1.66, 2.57, 3.73, 4.12);
var e = float32x4(10.67, 20.68, 30.02, 40.58);
var f = SIMD.float32x4.mul(d, e);
assertEq(f.x, mulf(1.66, 10.67));
assertEq(f.y, mulf(2.57, 20.68));
assertEq(f.z, mulf(3.73, 30.02));
assertEq(f.w, mulf(4.12, 40.58));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var h = float32x4(NaN, -0, -Infinity, 0);
var i = SIMD.float32x4.mul(g, h);
assertEq(i.x, NaN);
assertEq(i.y, 0);
assertEq(i.z, -Infinity);
assertEq(i.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}
test();

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

@ -8,8 +8,6 @@ var summary = 'float32x4 neg';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var c = SIMD.float32x4.neg(a);
assertEq(c.x, -1);
@ -17,6 +15,20 @@ function test() {
assertEq(c.z, -3);
assertEq(c.w, -4);
var d = float32x4(0.999, -0.001, 3.78, 4.05);
var f = SIMD.float32x4.neg(d);
assertEq(f.x, Math.fround(-0.999));
assertEq(f.y, Math.fround(0.001));
assertEq(f.z, Math.fround(-3.78));
assertEq(f.w, Math.fround(-4.05));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.neg(g);
assertEq(i.x, NaN);
assertEq(i.y, 0);
assertEq(i.z, -Infinity);
assertEq(i.w, Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -18,8 +18,6 @@ var notf = (function() {
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(2, 13, -37, 4.2);
var c = SIMD.float32x4.not(a);
assertEq(c.x, notf(2));
@ -27,6 +25,20 @@ function test() {
assertEq(c.z, notf(-37));
assertEq(c.w, notf(4.2));
var d = float32x4(2.897, 13.245, -37.781, 5.28);
var f = SIMD.float32x4.not(d);
assertEq(f.x, notf(2.897));
assertEq(f.y, notf(13.245));
assertEq(f.z, notf(-37.781));
assertEq(f.w, notf(5.28));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.not(g);
assertEq(i.x, notf(NaN));
assertEq(i.y, notf(-0));
assertEq(i.z, notf(Infinity));
assertEq(i.w, notf(-Infinity));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,7 +8,7 @@ var summary = 'float32x4 notEqual';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
// FIXME -- Bug 1081697: Amend to check for correctness of NaN/-0/Infinity/-Infinity border cases.
var a = float32x4(1, 20, 30, 40);
var b = float32x4(10, 20, 30, 4);
@ -18,6 +18,14 @@ function test() {
assertEq(c.z, 0);
assertEq(c.w, -1);
var d = float32x4(9.98, 20.65, 30.14, 4.235);
var e = float32x4(9.99, 20.65, Math.fround(30.14), 4.23);
var f = SIMD.float32x4.notEqual(d, e);
assertEq(f.x, -1);
assertEq(f.y, 0);
assertEq(f.z, 0);
assertEq(f.w, -1);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -19,8 +19,6 @@ var orf = (function() {
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.or(a, b);
@ -29,6 +27,22 @@ function test() {
assertEq(c.z, orf(3, 30));
assertEq(c.w, orf(4, 40));
var d = float32x4(1.12, 2.39, 3.83, 4.57);
var e = float32x4(10.76, 20.41, 30.96, 40.23);
var f = SIMD.float32x4.or(d, e);
assertEq(f.x, orf(1.12, 10.76));
assertEq(f.y, orf(2.39, 20.41));
assertEq(f.z, orf(3.83, 30.96));
assertEq(f.w, orf(4.57, 40.23));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var h = float32x4(5, 5, -Infinity, Infinity);
var i = SIMD.float32x4.or(g, h);
assertEq(i.x, orf(NaN, 5));
assertEq(i.y, orf(-0, 5));
assertEq(i.z, orf(Infinity, -Infinity));
assertEq(i.w, orf(-Infinity, Infinity));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,11 +5,13 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 reciprocal';
function reciprocalf(a) {
return Math.fround(1 / Math.fround(a));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 0.5, 0.25, 0.125);
var c = SIMD.float32x4.reciprocal(a);
assertEq(c.x, 1);
@ -17,6 +19,20 @@ function test() {
assertEq(c.z, 4);
assertEq(c.w, 8);
var d = float32x4(1.6, 0.8, 0.4, 0.2);
var f = SIMD.float32x4.reciprocal(d);
assertEq(f.x, reciprocalf(1.6));
assertEq(f.y, reciprocalf(0.8));
assertEq(f.z, reciprocalf(0.4));
assertEq(f.w, reciprocalf(0.2));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.reciprocal(g);
assertEq(i.x, NaN);
assertEq(i.y, -Infinity);
assertEq(i.z, 0);
assertEq(i.w, -0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,11 +5,13 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 reciprocalSqrt';
function reciprocalsqrtf(a) {
return Math.fround(Math.sqrt(1 / Math.fround(a)));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 1, 0.25, 0.25);
var c = SIMD.float32x4.reciprocalSqrt(a);
assertEq(c.x, 1);
@ -17,6 +19,20 @@ function test() {
assertEq(c.z, 2);
assertEq(c.w, 2);
var d = float32x4(25, 16, 6.25, 1.5625);
var f = SIMD.float32x4.reciprocalSqrt(d);
assertEq(f.x, reciprocalsqrtf(25));
assertEq(f.y, reciprocalsqrtf(16));
assertEq(f.z, reciprocalsqrtf(6.25));
assertEq(f.w, reciprocalsqrtf(1.5625));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.reciprocalSqrt(g);
assertEq(i.x, NaN);
assertEq(i.y, -Infinity);
assertEq(i.z, 0);
assertEq(i.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,11 +5,13 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 scale';
function mulf(a, b) {
return Math.fround(Math.fround(a) * Math.fround(b));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var c = SIMD.float32x4.scale(a, 2);
assertEq(c.x, 2);
@ -17,6 +19,20 @@ function test() {
assertEq(c.z, 6);
assertEq(c.w, 8);
var d = float32x4(1.34, 2.76, 3.21, 4.09);
var f = float32x4.scale(d, 2.54);
assertEq(f.x, mulf(1.34, 2.54));
assertEq(f.y, mulf(2.76, 2.54));
assertEq(f.z, mulf(3.21, 2.54));
assertEq(f.w, mulf(4.09, 2.54));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = float32x4.scale(g, 2.54);
assertEq(i.x, NaN);
assertEq(i.y, -0);
assertEq(i.z, Infinity);
assertEq(i.w, -Infinity);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,11 +5,13 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 sqrt';
function sqrtf(a) {
return Math.fround(Math.sqrt(Math.fround(a)));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 4, 9, 16);
var c = SIMD.float32x4.sqrt(a);
assertEq(c.x, 1);
@ -17,6 +19,20 @@ function test() {
assertEq(c.z, 3);
assertEq(c.w, 4);
var d = float32x4(2.7225, 7.3441, 9.4249, -1);
var f = SIMD.float32x4.sqrt(d);
assertEq(f.x, sqrtf(2.7225));
assertEq(f.y, sqrtf(7.3441));
assertEq(f.z, sqrtf(9.4249));
assertEq(f.w, NaN);
var g = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.sqrt(g);
assertEq(i.x, NaN);
assertEq(i.y, -0);
assertEq(i.z, Infinity);
assertEq(i.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -5,19 +5,37 @@ var int32x4 = SIMD.int32x4;
var summary = 'float32x4 sub';
function subf(a, b) {
return Math.fround(Math.fround(a) - Math.fround(b));
}
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.sub(b,a);
var c = SIMD.float32x4.sub(b, a);
assertEq(c.x, 9);
assertEq(c.y, 18);
assertEq(c.z, 27);
assertEq(c.w, 36);
var d = float32x4(1.34, 2.95, 3.17, 4.29);
var e = float32x4(10.18, 20.43, 30.63, 40.38);
var f = SIMD.float32x4.sub(e, d);
assertEq(f.x, subf(10.18, 1.34));
assertEq(f.y, subf(20.43, 2.95));
assertEq(f.z, subf(30.63, 3.17));
assertEq(f.w, subf(40.38, 4.29));
var g = float32x4(NaN, -0, -Infinity, -Infinity);
var h = float32x4(NaN, -0, Infinity, -Infinity);
var i = SIMD.float32x4.sub(h, g);
assertEq(i.x, NaN);
assertEq(i.y, 0);
assertEq(i.z, Infinity);
assertEq(i.w, NaN);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -8,18 +8,81 @@ var summary = 'float32x4 with';
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var x = SIMD.float32x4.withX(a, 5);
var y = SIMD.float32x4.withY(a, 5);
var z = SIMD.float32x4.withZ(a, 5);
var w = SIMD.float32x4.withW(a, 5);
assertEq(x.x, 5);
assertEq(x.y, 2);
assertEq(x.z, 3);
assertEq(x.w, 4);
assertEq(y.x, 1);
assertEq(y.y, 5);
assertEq(y.z, 3);
assertEq(y.w, 4);
assertEq(z.x, 1);
assertEq(z.y, 2);
assertEq(z.z, 5);
assertEq(z.w, 4);
assertEq(w.x, 1);
assertEq(w.y, 2);
assertEq(w.z, 3);
assertEq(w.w, 5);
var b = float32x4(1.87, 2.08, 3.84, 4.17);
var x1 = SIMD.float32x4.withX(b, 5.38);
var y1 = SIMD.float32x4.withY(b, 5.19);
var z1 = SIMD.float32x4.withZ(b, 5.11);
var w1 = SIMD.float32x4.withW(b, 5.07);
assertEq(x1.x, Math.fround(5.38));
assertEq(x1.y, Math.fround(2.08));
assertEq(x1.z, Math.fround(3.84));
assertEq(x1.w, Math.fround(4.17));
assertEq(y1.x, Math.fround(1.87));
assertEq(y1.y, Math.fround(5.19));
assertEq(y1.z, Math.fround(3.84));
assertEq(y1.w, Math.fround(4.17));
assertEq(z1.x, Math.fround(1.87));
assertEq(z1.y, Math.fround(2.08));
assertEq(z1.z, Math.fround(5.11));
assertEq(z1.w, Math.fround(4.17));
assertEq(w1.x, Math.fround(1.87));
assertEq(w1.y, Math.fround(2.08));
assertEq(w1.z, Math.fround(3.84));
assertEq(w1.w, Math.fround(5.07));
var c = float32x4(NaN, -0, Infinity, -Infinity);
var x2 = SIMD.float32x4.withX(c, 0);
var y2 = SIMD.float32x4.withY(c, 0);
var z2 = SIMD.float32x4.withZ(c, 0);
var w2 = SIMD.float32x4.withW(c, 0);
assertEq(x2.x, 0);
assertEq(x2.y, -0);
assertEq(x2.z, Infinity);
assertEq(x2.w, -Infinity);
assertEq(y2.x, NaN);
assertEq(y2.y, 0);
assertEq(y2.z, Infinity);
assertEq(y2.w, -Infinity);
assertEq(z2.x, NaN);
assertEq(z2.y, -0);
assertEq(z2.z, 0);
assertEq(z2.w, -Infinity);
assertEq(w2.x, NaN);
assertEq(w2.y, -0);
assertEq(w2.z, Infinity);
assertEq(w2.w, 0);
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -19,8 +19,6 @@ var xorf = (function() {
function test() {
print(BUGNUMBER + ": " + summary);
// FIXME -- Bug 948379: Amend to check for correctness of border cases.
var a = float32x4(1, 2, 3, 4);
var b = float32x4(10, 20, 30, 40);
var c = SIMD.float32x4.xor(a, b);
@ -29,6 +27,22 @@ function test() {
assertEq(c.z, xorf(3, 30));
assertEq(c.w, xorf(4, 40));
var d = float32x4(1.07, 2.62, 3.79, 4.15);
var e = float32x4(10.38, 20.47, 30.44, 40.16);
var f = SIMD.float32x4.xor(d, e);
assertEq(f.x, xorf(1.07, 10.38));
assertEq(f.y, xorf(2.62, 20.47));
assertEq(f.z, xorf(3.79, 30.44));
assertEq(f.w, xorf(4.15, 40.16));
var g = float32x4(NaN, -0, Infinity, -Infinity);
var h = float32x4(-0, Infinity, -Infinity, NaN);
var i = SIMD.float32x4.xor(g, h);
assertEq(i.x, xorf(NaN, -0));
assertEq(i.y, xorf(-0, Infinity));
assertEq(i.z, xorf(Infinity, -Infinity));
assertEq(i.w, xorf(-Infinity, NaN));
if (typeof reportCompare === "function")
reportCompare(true, true);
}

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

@ -3213,15 +3213,11 @@ XPCJSRuntime::XPCJSRuntime(nsXPConnect* aXPConnect)
const size_t kStackQuota = 2 * kDefaultStackQuota;
const size_t kTrustedScriptBuffer = 246 * 1024;
#elif defined(XP_WIN)
// 1MB is the default stack size on Windows, so use 900k. And since 32-bit
// Windows stack frames are 3.4k each, let's use a buffer of 48k and double
// that for 64-bit.
//
// Note - Frames on Win32 PGO builds seem to have grown recently, and 48k
// stacks seem about 20-30% too small - so we bump it to 64k.
// 1MB is the default stack size on Windows, so use 900k.
// Windows PGO stack frames have unfortunately gotten pretty large lately. :-(
const size_t kStackQuota = 900 * 1024;
const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 96 * 1024
: 64 * 1024;
const size_t kTrustedScriptBuffer = (sizeof(size_t) == 8) ? 120 * 1024
: 80 * 1024;
// The following two configurations are linux-only. Given the numbers above,
// we use 50k and 100k trusted buffers on 32-bit and 64-bit respectively.
#elif defined(DEBUG)

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

@ -384,21 +384,24 @@ SelectionCarets::UpdateSelectionCarets()
return;
}
if (selection->GetRangeCount() <= 0) {
if (selection->IsCollapsed()) {
SetVisibility(false);
return;
}
nsRefPtr<nsRange> range = selection->GetRangeAt(0);
if (range->Collapsed()) {
SetVisibility(false);
return;
}
int32_t rangeCount = selection->GetRangeCount();
nsRefPtr<nsRange> firstRange = selection->GetRangeAt(0);
nsRefPtr<nsRange> lastRange = selection->GetRangeAt(rangeCount - 1);
nsLayoutUtils::FirstAndLastRectCollector collector;
nsRange::CollectClientRects(&collector, range,
range->GetStartParent(), range->StartOffset(),
range->GetEndParent(), range->EndOffset(), true, true);
nsLayoutUtils::FirstAndLastRectCollector collectorStart;
nsRange::CollectClientRects(&collectorStart, firstRange,
firstRange->GetStartParent(), firstRange->StartOffset(),
firstRange->GetEndParent(), firstRange->EndOffset(), true, true);
nsLayoutUtils::FirstAndLastRectCollector collectorEnd;
nsRange::CollectClientRects(&collectorEnd, lastRange,
lastRange->GetStartParent(), lastRange->StartOffset(),
lastRange->GetEndParent(), lastRange->EndOffset(), true, true);
nsIFrame* canvasFrame = mPresShell->GetCanvasFrame();
nsIFrame* rootFrame = mPresShell->GetRootFrame();
@ -412,11 +415,11 @@ SelectionCarets::UpdateSelectionCarets()
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
int32_t startOffset;
nsIFrame* startFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
range, fs, false, startOffset);
firstRange, fs, false, startOffset);
int32_t endOffset;
nsIFrame* endFrame = FindFirstNodeWithFrame(mPresShell->GetDocument(),
range, fs, true, endOffset);
lastRange, fs, true, endOffset);
if (!startFrame || !endFrame) {
SetVisibility(false);
@ -442,15 +445,15 @@ SelectionCarets::UpdateSelectionCarets()
// If start frame is LTR, then place start caret in first rect's leftmost
// otherwise put it to first rect's rightmost.
ReduceRectToVerticalEdge(collector.mFirstRect, startFrameIsRTL);
ReduceRectToVerticalEdge(collectorStart.mFirstRect, startFrameIsRTL);
// Contrary to start frame, if end frame is LTR, put end caret to last
// rect's rightmost position, otherwise, put it to last rect's leftmost.
ReduceRectToVerticalEdge(collector.mLastRect, !endFrameIsRTL);
ReduceRectToVerticalEdge(collectorEnd.mLastRect, !endFrameIsRTL);
nsAutoTArray<nsIFrame*, 16> hitFramesInFirstRect;
nsLayoutUtils::GetFramesForArea(rootFrame,
collector.mFirstRect,
collectorStart.mFirstRect,
hitFramesInFirstRect,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
@ -458,7 +461,7 @@ SelectionCarets::UpdateSelectionCarets()
nsAutoTArray<nsIFrame*, 16> hitFramesInLastRect;
nsLayoutUtils::GetFramesForArea(rootFrame,
collector.mLastRect,
collectorEnd.mLastRect,
hitFramesInLastRect,
nsLayoutUtils::IGNORE_PAINT_SUPPRESSION |
nsLayoutUtils::IGNORE_CROSS_DOC |
@ -467,11 +470,11 @@ SelectionCarets::UpdateSelectionCarets()
SetStartFrameVisibility(hitFramesInFirstRect.Contains(startFrame));
SetEndFrameVisibility(hitFramesInLastRect.Contains(endFrame));
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mFirstRect);
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collector.mLastRect);
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collectorStart.mFirstRect);
nsLayoutUtils::TransformRect(rootFrame, canvasFrame, collectorEnd.mLastRect);
SetStartFramePos(collector.mFirstRect.BottomLeft());
SetEndFramePos(collector.mLastRect.BottomRight());
SetStartFramePos(collectorStart.mFirstRect.BottomLeft());
SetEndFramePos(collectorEnd.mLastRect.BottomRight());
SetVisibility(true);
// If range select only one character, append tilt class name to it.
@ -689,11 +692,13 @@ SelectionCarets::DragSelection(const nsPoint &movePoint)
}
nsRefPtr<dom::Selection> selection = GetSelection();
if (selection->GetRangeCount() <= 0) {
int32_t rangeCount = selection->GetRangeCount();
if (rangeCount <= 0) {
return nsEventStatus_eConsumeNoDefault;
}
nsRefPtr<nsRange> range = selection->GetRangeAt(0);
nsRefPtr<nsRange> range = mDragMode == START_FRAME ?
selection->GetRangeAt(0) : selection->GetRangeAt(rangeCount - 1);
if (!CompareRangeWithContentOffset(range, fs, offsets, mDragMode)) {
return nsEventStatus_eConsumeNoDefault;
}
@ -737,20 +742,22 @@ SelectionCarets::GetCaretYCenterPosition()
}
nsRefPtr<dom::Selection> selection = GetSelection();
if (selection->GetRangeCount() <= 0) {
int32_t rangeCount = selection->GetRangeCount();
if (rangeCount <= 0) {
return 0;
}
nsRefPtr<nsRange> range = selection->GetRangeAt(0);
nsRefPtr<nsFrameSelection> fs = GetFrameSelection();
MOZ_ASSERT(mDragMode != NONE);
nsCOMPtr<nsIContent> node;
uint32_t nodeOffset;
if (mDragMode == START_FRAME) {
nsRefPtr<nsRange> range = selection->GetRangeAt(0);
node = do_QueryInterface(range->GetStartParent());
nodeOffset = range->StartOffset();
} else {
nsRefPtr<nsRange> range = selection->GetRangeAt(rangeCount - 1);
node = do_QueryInterface(range->GetEndParent());
nodeOffset = range->EndOffset();
}
@ -885,12 +892,6 @@ SelectionCarets::NotifySelectionChanged(nsIDOMDocument* aDoc,
nsISelection* aSel,
int16_t aReason)
{
bool isCollapsed;
aSel->GetIsCollapsed(&isCollapsed);
if (isCollapsed) {
SetVisibility(false);
return NS_OK;
}
if (!aReason || (aReason & (nsISelectionListener::DRAG_REASON |
nsISelectionListener::KEYPRESS_REASON |
nsISelectionListener::MOUSEDOWN_REASON))) {

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

@ -4680,15 +4680,6 @@ static int32_t GetMaxChunkLength(nsFontMetrics& aFontMetrics)
return std::min(aFontMetrics.GetMaxStringLength(), MAX_GFX_TEXT_BUF_SIZE);
}
nscoord
nsLayoutUtils::AppUnitWidthOfString(const nsString& aString,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext)
{
return AppUnitWidthOfString(aString.get(), aString.Length(),
aFontMetrics, aContext);
}
nscoord
nsLayoutUtils::AppUnitWidthOfString(const char16_t *aString,
uint32_t aLength,
@ -4706,6 +4697,26 @@ nsLayoutUtils::AppUnitWidthOfString(const char16_t *aString,
return width;
}
nscoord
nsLayoutUtils::AppUnitWidthOfStringBidi(const char16_t* aString,
uint32_t aLength,
const nsIFrame* aFrame,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext)
{
nsPresContext* presContext = aFrame->PresContext();
if (presContext->BidiEnabled()) {
nsBidiLevel level =
nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext());
return nsBidiPresUtils::MeasureTextWidth(aString, aLength, level,
presContext, aContext,
aFontMetrics);
}
aFontMetrics.SetTextRunRTL(false);
return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
aContext);
}
nsBoundingMetrics
nsLayoutUtils::AppUnitBoundsOfString(const char16_t* aString,
uint32_t aLength,
@ -4799,26 +4810,6 @@ nsLayoutUtils::DrawUniDirString(const char16_t* aString,
}
}
nscoord
nsLayoutUtils::GetStringWidth(const nsIFrame* aFrame,
nsRenderingContext* aContext,
nsFontMetrics& aFontMetrics,
const char16_t* aString,
int32_t aLength)
{
nsPresContext* presContext = aFrame->PresContext();
if (presContext->BidiEnabled()) {
nsBidiLevel level =
nsBidiPresUtils::BidiLevelFromStyle(aFrame->StyleContext());
return nsBidiPresUtils::MeasureTextWidth(aString, aLength,
level, presContext, *aContext,
aFontMetrics);
}
aFontMetrics.SetTextRunRTL(false);
return nsLayoutUtils::AppUnitWidthOfString(aString, aLength, aFontMetrics,
*aContext);
}
/* static */ void
nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
nsRenderingContext* aContext,

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

@ -1326,11 +1326,28 @@ public:
}
static nscoord AppUnitWidthOfString(const nsString& aString,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext);
nsRenderingContext& aContext) {
return nsLayoutUtils::AppUnitWidthOfString(aString.get(), aString.Length(),
aFontMetrics, aContext);
}
static nscoord AppUnitWidthOfString(const char16_t *aString,
uint32_t aLength,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext);
static nscoord AppUnitWidthOfStringBidi(const nsString& aString,
const nsIFrame* aFrame,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext) {
return nsLayoutUtils::AppUnitWidthOfStringBidi(aString.get(),
aString.Length(), aFrame,
aFontMetrics, aContext);
}
static nscoord AppUnitWidthOfStringBidi(const char16_t* aString,
uint32_t aLength,
const nsIFrame* aFrame,
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext);
static nsBoundingMetrics AppUnitBoundsOfString(const char16_t* aString,
uint32_t aLength,
nsFontMetrics& aFontMetrics,
@ -1353,12 +1370,6 @@ public:
nsFontMetrics& aFontMetrics,
nsRenderingContext& aContext);
static nscoord GetStringWidth(const nsIFrame* aFrame,
nsRenderingContext* aContext,
nsFontMetrics& aFontMetrics,
const char16_t* aString,
int32_t aLength);
/**
* Helper function for drawing text-shadow. The callback's job
* is to draw whatever needs to be blurred onto the given context.

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

@ -13,3 +13,4 @@ skip = false
[test_touchcaret.py]
[test_selectioncarets.py]
[test_selectioncarets_multiplerange.py]

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

@ -0,0 +1,108 @@
# -*- coding: utf-8 -*-
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
from by import By
from marionette import Actions
from marionette_test import MarionetteTestCase
from selection import SelectionManager
class SelectionCaretsMultipleRangeTest(MarionetteTestCase):
_long_press_time = 1 # 1 second
def setUp(self):
# Code to execute before a tests are run.
MarionetteTestCase.setUp(self)
self.actions = Actions(self.marionette)
def openTestHtml(self, enabled=True):
# Open html for testing and enable selectioncaret and
# non-editable support
self.marionette.execute_script(
'SpecialPowers.setBoolPref("selectioncaret.enabled", %s);' %
('true' if enabled else 'false'))
self.marionette.execute_script(
'SpecialPowers.setBoolPref("selectioncaret.noneditable", %s);' %
('true' if enabled else 'false'))
test_html = self.marionette.absolute_url('test_selectioncarets_multiplerange.html')
self.marionette.navigate(test_html)
self._body = self.marionette.find_element(By.ID, 'bd')
self._sel3 = self.marionette.find_element(By.ID, 'sel3')
self._sel4 = self.marionette.find_element(By.ID, 'sel4')
self._sel6 = self.marionette.find_element(By.ID, 'sel6')
self._nonsel1 = self.marionette.find_element(By.ID, 'nonsel1')
def _long_press_without_contextmenu(self, el, x, y):
return self.actions.press(el, x, y).move_by_offset(0, 0).\
wait(self._long_press_time).release()
def _long_press_to_select_word(self, el, wordOrdinal):
sel = SelectionManager(el)
original_content = sel.content
words = original_content.split()
self.assertTrue(wordOrdinal < len(words),
'Expect at least %d words in the content.' % wordOrdinal)
# Calc offset
offset = 0
for i in range(wordOrdinal):
offset += (len(words[i]) + 1)
# Move caret inside the word.
el.tap()
sel.move_caret_to_front()
sel.move_caret_by_offset(offset)
x, y = sel.caret_location()
# Long press the caret position. Selection carets should appear, and the
# word will be selected. On Windows, those spaces after the word
# will also be selected.
self._long_press_without_contextmenu(el, x, y).perform()
def _to_unix_line_ending(self, s):
"""Changes all Windows/Mac line endings in s to UNIX line endings."""
return s.replace('\r\n', '\n').replace('\r', '\n')
def test_long_press_to_select_non_selectable_word(self):
'''Testing long press on non selectable field.
We should not select anything when long press on non selectable fields.'''
self.openTestHtml(enabled=True)
halfY = self._nonsel1.size['height'] / 2
self._long_press_without_contextmenu(self._nonsel1, 0, halfY).perform()
sel = SelectionManager(self._nonsel1)
range_count = sel.range_count()
self.assertEqual(range_count, 0)
def test_drag_caret_over_non_selectable_field(self):
'''Testing drag caret over non selectable field.
So that the selected content should exclude non selectable field and
end selection caret should appear in last range's position.'''
self.openTestHtml(enabled=True)
# Select target element and get target caret location
self._long_press_to_select_word(self._sel4, 3)
sel = SelectionManager(self._body)
(_, _), (end_caret_x, end_caret_y) = sel.selection_carets_location()
self._long_press_to_select_word(self._sel6, 0)
(_, _), (end_caret2_x, end_caret2_y) = sel.selection_carets_location()
# Select start element
self._long_press_to_select_word(self._sel3, 3)
# Drag end caret to target location
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
self.actions.flick(self._body, caret2_x, caret2_y, end_caret_x, end_caret_y).perform()
self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
'this 3\nuser can select this')
(caret1_x, caret1_y), (caret2_x, caret2_y) = sel.selection_carets_location()
self.actions.flick(self._body, caret2_x, caret2_y, end_caret2_x, end_caret2_y).perform()
self.assertEqual(self._to_unix_line_ending(sel.selected_content.strip()),
'this 3\nuser can select this 4\nuser can select this 5\nuser')

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

@ -763,9 +763,8 @@ TextOverflow::Marker::SetupString(nsIFrame* aFrame)
nsRefPtr<nsFontMetrics> fm;
nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm),
nsLayoutUtils::FontSizeInflationFor(aFrame));
mWidth = nsLayoutUtils::GetStringWidth(aFrame, rc, *fm,
mStyle->mString.get(),
mStyle->mString.Length());
mWidth = nsLayoutUtils::AppUnitWidthOfStringBidi(mStyle->mString, aFrame,
*fm, *rc);
}
mIntrinsicISize = mWidth;
mInitialized = true;

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

@ -602,8 +602,8 @@ nsBulletFrame::GetDesiredSize(nsPresContext* aCX,
GetListItemText(text);
finalSize.BSize(wm) = fm->MaxHeight();
finalSize.ISize(wm) =
nsLayoutUtils::GetStringWidth(this, aRenderingContext, *fm,
text.get(), text.Length());
nsLayoutUtils::AppUnitWidthOfStringBidi(text, this, *fm,
*aRenderingContext);
aMetrics.SetBlockStartAscent(fm->MaxAscent());
break;
}

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

@ -1035,7 +1035,8 @@ nsImageFrame::MeasureString(const char16_t* aString,
// Measure this chunk of text, and see if it fits
nscoord width =
nsLayoutUtils::GetStringWidth(this, &aContext, aFontMetrics, aString, len);
nsLayoutUtils::AppUnitWidthOfStringBidi(aString, len, this, aFontMetrics,
aContext);
bool fits = (totalWidth + width) <= aMaxWidth;
// If it fits on the line, or it's the first word we've processed then

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

@ -243,10 +243,9 @@ nscoord nsPageFrame::GetXPosition(nsRenderingContext& aRenderingContext,
int32_t aJust,
const nsString& aStr)
{
nscoord width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
aFontMetrics,
aStr.get(), aStr.Length());
nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(aStr, this,
aFontMetrics,
aRenderingContext);
nscoord x = aRect.x;
switch (aJust) {
case nsIPrintSettings::kJustLeft:

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

@ -100,10 +100,8 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
nsIFrame* aPrevInFlow)
{
// determine if we are a <frame> or <iframe>
if (aContent) {
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
mIsInline = frameElem ? false : true;
}
nsCOMPtr<nsIDOMHTMLFrameElement> frameElem = do_QueryInterface(aContent);
mIsInline = frameElem ? false : true;
nsLeafFrame::Init(aContent, aParent, aPrevInFlow);

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

@ -0,0 +1,40 @@
<!doctype html>
<html class="reftest-wait">
<math style="font-size:25px; position: absolute; top: 10px; left:10px;">
<mrow id="outer">
<mo>(</mo>
<mrow>
<mn id="a" style="visibility:hidden;">a</mn>
<mo>&amp;</mo>
<mn id="c" style="visibility:hidden;">c</mn>
</mrow>
<mo>)</mo>
</mrow>
</math>
<!-- Implementation kludge. <mfenced> renders the position of the ampersand in
a slightly different position compared to <mo>+<mrow>.
In this test we are only concerned about the size of the fences "(" and
")", so the ampersand gets redacted. -->
<div id="div" style="position: absolute; background:black; top: 0px;
height: 120px;"></div>
<script>
function doTest()
{
a = document.getElementById("a");
c = document.getElementById("c");
div = document.getElementById("div");
outer = document.getElementById("outer");
left = a.getBoundingClientRect().left; // div's left
div.style.left = left + 'px';
div.style.width = (c.getBoundingClientRect().right - left ) + 'px';
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</html>

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

@ -0,0 +1,35 @@
<!doctype html>
<html class="reftest-wait">
<math style="font-size:25px; position: absolute; top: 10px; left:10px;">
<mfenced id="outer" separators="&amp;">
<mn id="a" style="visibility:hidden;">a</mn>
<mn id="c" style="visibility:hidden;">c</mn>
</mfenced>
</math>
<!-- Implementation kludge. <mfenced> renders the position of the ampersand in
a slightly different position compared to <mo>+<mrow>.
In this test we are only concerned about the size of the fences "(" and
")", so the ampersand gets redacted. -->
<div id="div" style="position: absolute; background:black; top: 0px;
height: 120px;"></div>
<script>
function doTest()
{
a = document.getElementById("a");
c = document.getElementById("c");
div = document.getElementById("div");
outer = document.getElementById("outer");
left = a.getBoundingClientRect().left; // div's left
div.style.left = left + 'px';
div.style.width = (c.getBoundingClientRect().right - left ) + 'px';
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
</script>
</html>

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

@ -38,6 +38,7 @@ skip-if(B2G&&browserIsRemote) random-if(smallScreen&&Android) fuzzy(255,200) ==
== mfenced-9.html mfenced-9-ref.html
fails-if(/^Windows\x20NT\x205\.1/.test(http.oscpu)) == mfenced-10.html mfenced-10-ref.html # Windows versions without Cambria Math, see bug 670592
fails-if(winWidget&&d2d) == mfenced-11.html mfenced-11-ref.html
== mfenced-12.html mfenced-12-ref.html
== mi-mathvariant-1.xhtml mi-mathvariant-1-ref.xhtml
== mi-mathvariant-2.xhtml mi-mathvariant-2-ref.xhtml
!= mi-mathvariant-3.html mi-mathvariant-3-ref.html

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

@ -3040,6 +3040,10 @@ struct nsStyleSVGReset {
return mFilters.Length() > 0;
}
bool HasNonScalingStroke() const {
return mVectorEffect == NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE;
}
nsStyleClipPath mClipPath; // [reset]
nsTArray<nsStyleFilter> mFilters; // [reset]
nsCOMPtr<nsIURI> mMask; // [reset]

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

@ -463,113 +463,132 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
nsSVGPathGeometryElement* element =
static_cast<nsSVGPathGeometryElement*>(mContent);
RefPtr<DrawTarget> tmpDT;
bool getFill = (aFlags & nsSVGUtils::eBBoxIncludeFillGeometry) ||
((aFlags & nsSVGUtils::eBBoxIncludeFill) &&
StyleSVG()->mFill.mType != eStyleSVGPaintType_None);
bool getStroke = (aFlags & nsSVGUtils::eBBoxIncludeStrokeGeometry) ||
((aFlags & nsSVGUtils::eBBoxIncludeStroke) &&
nsSVGUtils::HasStroke(this));
bool gotSimpleBounds = false;
if (!StyleSVGReset()->HasNonScalingStroke()) {
Float strokeWidth = getStroke ? nsSVGUtils::GetStrokeWidth(this) : 0.f;
Rect simpleBounds;
gotSimpleBounds = element->GetGeometryBounds(&simpleBounds, strokeWidth,
aToBBoxUserspace);
if (gotSimpleBounds) {
bbox = simpleBounds;
}
}
if (!gotSimpleBounds) {
// Get the bounds using a Moz2D Path object (more expensive):
RefPtr<DrawTarget> tmpDT;
#ifdef XP_WIN
// Unfortunately D2D backed DrawTarget produces bounds with rounding errors
// when whole number results are expected, even in the case of trivial
// calculations. To avoid that and meet the expectations of web content we
// have to use a CAIRO DrawTarget. The most efficient way to do that is to
// wrap the cached cairo_surface_t from ScreenReferenceSurface():
nsRefPtr<gfxASurface> refSurf =
gfxPlatform::GetPlatform()->ScreenReferenceSurface();
tmpDT = gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(refSurf, IntSize(1, 1));
// Unfortunately D2D backed DrawTarget produces bounds with rounding errors
// when whole number results are expected, even in the case of trivial
// calculations. To avoid that and meet the expectations of web content we
// have to use a CAIRO DrawTarget. The most efficient way to do that is to
// wrap the cached cairo_surface_t from ScreenReferenceSurface():
nsRefPtr<gfxASurface> refSurf =
gfxPlatform::GetPlatform()->ScreenReferenceSurface();
tmpDT = gfxPlatform::GetPlatform()->
CreateDrawTargetForSurface(refSurf, IntSize(1, 1));
#else
tmpDT = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
tmpDT = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
#endif
FillRule fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mFillRule);
RefPtr<Path> pathInUserSpace = element->GetOrBuildPath(*tmpDT, fillRule);
if (!pathInUserSpace) {
return bbox;
}
RefPtr<Path> pathInBBoxSpace;
if (aToBBoxUserspace.IsIdentity()) {
pathInBBoxSpace = pathInUserSpace;
} else {
RefPtr<PathBuilder> builder =
pathInUserSpace->TransformedCopyToBuilder(aToBBoxUserspace, fillRule);
pathInBBoxSpace = builder->Finish();
if (!pathInBBoxSpace) {
FillRule fillRule = nsSVGUtils::ToFillRule(StyleSVG()->mFillRule);
RefPtr<Path> pathInUserSpace = element->GetOrBuildPath(*tmpDT, fillRule);
if (!pathInUserSpace) {
return bbox;
}
}
// Be careful when replacing the following logic to get the fill and stroke
// extents independently (instead of computing the stroke extents from the
// path extents). You may think that you can just use the stroke extents if
// there is both a fill and a stroke. In reality it's necessary to calculate
// both the fill and stroke extents, and take the union of the two. There are
// two reasons for this:
//
// # Due to stroke dashing, in certain cases the fill extents could actually
// extend outside the stroke extents.
// # If the stroke is very thin, cairo won't paint any stroke, and so the
// stroke bounds that it will return will be empty.
Rect pathBBoxExtents = pathInBBoxSpace->GetBounds();
if (!pathBBoxExtents.IsFinite()) {
// This can happen in the case that we only have a move-to command in the
// path commands, in which case we know nothing gets rendered.
return bbox;
}
// Account for fill:
if ((aFlags & nsSVGUtils::eBBoxIncludeFillGeometry) ||
((aFlags & nsSVGUtils::eBBoxIncludeFill) &&
StyleSVG()->mFill.mType != eStyleSVGPaintType_None)) {
bbox = pathBBoxExtents;
}
// Account for stroke:
if ((aFlags & nsSVGUtils::eBBoxIncludeStrokeGeometry) ||
((aFlags & nsSVGUtils::eBBoxIncludeStroke) &&
nsSVGUtils::HasStroke(this))) {
#if 0
// This disabled code is how we would calculate the stroke bounds using
// Moz2D Path::GetStrokedBounds(). Unfortunately at the time of writing it
// there are two problems that prevent us from using it.
//
// First, it seems that some of the Moz2D backends are really dumb. Not
// only do some GetStrokeOptions() implementations sometimes significantly
// overestimate the stroke bounds, but if an argument is passed for the
// aTransform parameter then they just return bounds-of-transformed-bounds.
// These two things combined can lead the bounds to be unacceptably
// oversized, leading to massive over-invalidation.
//
// Second, the way we account for non-scaling-stroke by transforming the
// path using the transform to the outer-<svg> element is not compatible
// with the way that nsSVGPathGeometryFrame::Reflow() inserts a scale into
// aToBBoxUserspace and then scales the bounds that we return.
SVGContentUtils::AutoStrokeOptions strokeOptions;
SVGContentUtils::GetStrokeOptions(&strokeOptions, element, StyleContext(),
nullptr, SVGContentUtils::eIgnoreStrokeDashing);
Rect strokeBBoxExtents;
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
Matrix outerSVGToUser = ToMatrix(userToOuterSVG);
outerSVGToUser.Invert();
Matrix outerSVGToBBox = aToBBoxUserspace * outerSVGToUser;
RefPtr<PathBuilder> builder =
pathInUserSpace->TransformedCopyToBuilder(ToMatrix(userToOuterSVG));
RefPtr<Path> pathInOuterSVGSpace = builder->Finish();
strokeBBoxExtents =
pathInOuterSVGSpace->GetStrokedBounds(strokeOptions, outerSVGToBBox);
RefPtr<Path> pathInBBoxSpace;
if (aToBBoxUserspace.IsIdentity()) {
pathInBBoxSpace = pathInUserSpace;
} else {
strokeBBoxExtents =
pathInUserSpace->GetStrokedBounds(strokeOptions, aToBBoxUserspace);
RefPtr<PathBuilder> builder =
pathInUserSpace->TransformedCopyToBuilder(aToBBoxUserspace, fillRule);
pathInBBoxSpace = builder->Finish();
if (!pathInBBoxSpace) {
return bbox;
}
}
MOZ_ASSERT(strokeBBoxExtents.IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(strokeBBoxExtents);
// Be careful when replacing the following logic to get the fill and stroke
// extents independently (instead of computing the stroke extents from the
// path extents). You may think that you can just use the stroke extents if
// there is both a fill and a stroke. In reality it's necessary to
// calculate both the fill and stroke extents, and take the union of the
// two. There are two reasons for this:
//
// # Due to stroke dashing, in certain cases the fill extents could
// actually extend outside the stroke extents.
// # If the stroke is very thin, cairo won't paint any stroke, and so the
// stroke bounds that it will return will be empty.
Rect pathBBoxExtents = pathInBBoxSpace->GetBounds();
if (!pathBBoxExtents.IsFinite()) {
// This can happen in the case that we only have a move-to command in the
// path commands, in which case we know nothing gets rendered.
return bbox;
}
// Account for fill:
if (getFill) {
bbox = pathBBoxExtents;
}
// Account for stroke:
if (getStroke) {
#if 0
// This disabled code is how we would calculate the stroke bounds using
// Moz2D Path::GetStrokedBounds(). Unfortunately at the time of writing
// it there are two problems that prevent us from using it.
//
// First, it seems that some of the Moz2D backends are really dumb. Not
// only do some GetStrokeOptions() implementations sometimes
// significantly overestimate the stroke bounds, but if an argument is
// passed for the aTransform parameter then they just return bounds-of-
// transformed-bounds. These two things combined can lead the bounds to
// be unacceptably oversized, leading to massive over-invalidation.
//
// Second, the way we account for non-scaling-stroke by transforming the
// path using the transform to the outer-<svg> element is not compatible
// with the way that nsSVGPathGeometryFrame::Reflow() inserts a scale
// into aToBBoxUserspace and then scales the bounds that we return.
SVGContentUtils::AutoStrokeOptions strokeOptions;
SVGContentUtils::GetStrokeOptions(&strokeOptions, element,
StyleContext(), nullptr,
SVGContentUtils::eIgnoreStrokeDashing);
Rect strokeBBoxExtents;
gfxMatrix userToOuterSVG;
if (nsSVGUtils::GetNonScalingStrokeTransform(this, &userToOuterSVG)) {
Matrix outerSVGToUser = ToMatrix(userToOuterSVG);
outerSVGToUser.Invert();
Matrix outerSVGToBBox = aToBBoxUserspace * outerSVGToUser;
RefPtr<PathBuilder> builder =
pathInUserSpace->TransformedCopyToBuilder(ToMatrix(userToOuterSVG));
RefPtr<Path> pathInOuterSVGSpace = builder->Finish();
strokeBBoxExtents =
pathInOuterSVGSpace->GetStrokedBounds(strokeOptions, outerSVGToBBox);
} else {
strokeBBoxExtents =
pathInUserSpace->GetStrokedBounds(strokeOptions, aToBBoxUserspace);
}
MOZ_ASSERT(strokeBBoxExtents.IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(strokeBBoxExtents);
#else
// For now we just use nsSVGUtils::PathExtentsToMaxStrokeExtents:
gfxRect strokeBBoxExtents =
nsSVGUtils::PathExtentsToMaxStrokeExtents(ThebesRect(pathBBoxExtents),
this,
ThebesMatrix(aToBBoxUserspace));
MOZ_ASSERT(ToRect(strokeBBoxExtents).IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(strokeBBoxExtents);
gfxRect strokeBBoxExtents =
nsSVGUtils::PathExtentsToMaxStrokeExtents(ThebesRect(pathBBoxExtents),
this,
ThebesMatrix(aToBBoxUserspace));
MOZ_ASSERT(ToRect(strokeBBoxExtents).IsFinite(), "bbox is about to go bad");
bbox.UnionEdges(strokeBBoxExtents);
#endif
}
}
// Account for markers:

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

@ -67,8 +67,8 @@ RecordingCmdLineHandler.prototype =
cmdLine.preventDefault = true;
},
helpInfo : " -recording <file> Record drawing for a given URL.\n" +
" -recording-output <file> Specify destination file for a drawing recording.\n"
helpInfo : " --recording <file> Record drawing for a given URL.\n" +
" --recording-output <file> Specify destination file for a drawing recording.\n"
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RecordingCmdLineHandler]);

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

@ -105,7 +105,7 @@ RefTestCmdLineHandler.prototype =
cmdLine.preventDefault = true;
},
helpInfo : " -reftest <file> Run layout acceptance tests on given manifest.\n"
helpInfo : " --reftest <file> Run layout acceptance tests on given manifest.\n"
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RefTestCmdLineHandler]);

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

@ -727,8 +727,8 @@ nsListBoxBodyFrame::ComputeIntrinsicISize(nsBoxLayoutState& aBoxLayoutState)
getter_AddRefs(fm));
nscoord textWidth =
nsLayoutUtils::GetStringWidth(this, rendContext, *fm,
value.get(), value.Length());
nsLayoutUtils::AppUnitWidthOfStringBidi(value, this, *fm,
*rendContext);
textWidth += width;
if (textWidth > largestWidth)

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

@ -613,10 +613,9 @@ nsTextBoxFrame::CalculateTitleForWidth(nsPresContext* aPresContext,
nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fm));
// see if the text will completely fit in the width given
nscoord titleWidth = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
*fm,
mTitle.get(), mTitle.Length());
nscoord titleWidth =
nsLayoutUtils::AppUnitWidthOfStringBidi(mTitle, this, *fm,
aRenderingContext);
if (titleWidth <= aWidth) {
mCroppedTitle = mTitle;
if (HasRTLChars(mTitle)) {
@ -713,8 +712,8 @@ nsTextBoxFrame::CalculateTitleForWidth(nsPresContext* aPresContext,
case CropCenter:
{
nscoord stringWidth =
nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fm,
mTitle.get(), mTitle.Length());
nsLayoutUtils::AppUnitWidthOfStringBidi(mTitle, this, *fm,
aRenderingContext);
if (stringWidth <= aWidth) {
// the entire string will fit in the maximum width
mCroppedTitle.Insert(mTitle, 0);
@ -771,8 +770,8 @@ nsTextBoxFrame::CalculateTitleForWidth(nsPresContext* aPresContext,
break;
}
return nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fm,
mCroppedTitle.get(), mCroppedTitle.Length());
return nsLayoutUtils::AppUnitWidthOfStringBidi(mCroppedTitle, this, *fm,
aRenderingContext);
}
#define OLD_ELLIPSIS NS_LITERAL_STRING("...")
@ -1000,8 +999,8 @@ nsTextBoxFrame::GetTextSize(nsPresContext* aPresContext,
nsLayoutUtils::GetFontMetricsForFrame(this, getter_AddRefs(fontMet));
aSize.height = fontMet->MaxHeight();
aSize.width =
nsLayoutUtils::GetStringWidth(this, &aRenderingContext, *fontMet,
aString.get(), aString.Length());
nsLayoutUtils::AppUnitWidthOfStringBidi(aString, this, *fontMet,
aRenderingContext);
aAscent = fontMet->MaxAscent();
}

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

@ -1319,9 +1319,9 @@ nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
{
NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
nscoord width =
nsLayoutUtils::GetStringWidth(this, &aRenderingContext, aFontMetrics,
aText.get(), aText.Length());
nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this,
aFontMetrics,
aRenderingContext);
nscoord maxWidth = aTextRect.width;
if (aColumn->Overflow()) {
@ -1459,9 +1459,8 @@ nsTreeBodyFrame::AdjustForCellText(nsAutoString& aText,
}
}
width = nsLayoutUtils::GetStringWidth(this, &aRenderingContext,
aFontMetrics, aText.get(),
aText.Length());
width = nsLayoutUtils::AppUnitWidthOfStringBidi(aText, this, aFontMetrics,
aRenderingContext);
}
switch (aColumn->GetTextAlignment()) {
@ -1748,9 +1747,8 @@ nsTreeBodyFrame::GetCellWidth(int32_t aRow, nsTreeColumn* aCol,
nsLayoutUtils::GetFontMetricsForStyleContext(textContext,
getter_AddRefs(fm));
// Get the width of the text itself
nscoord width =
nsLayoutUtils::GetStringWidth(this, aRenderingContext, *fm,
cellText.get(), cellText.Length());
nscoord width = nsLayoutUtils::AppUnitWidthOfStringBidi(cellText, this, *fm,
*aRenderingContext);
nscoord totalTextWidth = width + bp.left + bp.right;
aDesiredSize += totalTextWidth;
return NS_OK;

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

@ -227,18 +227,6 @@ InfallibleAllocPolicy::ExitOnFailure(const void* aP)
}
}
class FpWriteFunc : public JSONWriteFunc
{
public:
explicit FpWriteFunc(FILE* aFp) : mFp(aFp) {}
~FpWriteFunc() { fclose(mFp); }
void Write(const char* aStr) { fputs(aStr, mFp); }
private:
FILE* mFp;
};
static double
Percent(size_t part, size_t whole)
{
@ -289,17 +277,11 @@ class Options
{}
};
enum Mode {
Normal, // run normally
Test // do some basic correctness tests
};
char* mDMDEnvVar; // a saved copy, for later printing
NumOption<size_t> mSampleBelowSize;
NumOption<uint32_t> mMaxFrames;
bool mShowDumpStats;
Mode mMode;
void BadArg(const char* aArg);
static const char* ValueIfMatch(const char* aArg, const char* aOptionName);
@ -316,9 +298,7 @@ public:
size_t MaxFrames() const { return mMaxFrames.mActual; }
size_t ShowDumpStats() const { return mShowDumpStats; }
void SetSampleBelowSize(size_t aN) { mSampleBelowSize.mActual = aN; }
bool IsTestMode() const { return mMode == Test; }
void SetSampleBelowSize(size_t aSize) { mSampleBelowSize.mActual = aSize; }
};
static Options *gOptions;
@ -338,25 +318,11 @@ class MutexBase
DISALLOW_COPY_AND_ASSIGN(MutexBase);
public:
MutexBase()
{
InitializeCriticalSection(&mCS);
}
MutexBase() { InitializeCriticalSection(&mCS); }
~MutexBase() { DeleteCriticalSection(&mCS); }
~MutexBase()
{
DeleteCriticalSection(&mCS);
}
void Lock()
{
EnterCriticalSection(&mCS);
}
void Unlock()
{
LeaveCriticalSection(&mCS);
}
void Lock() { EnterCriticalSection(&mCS); }
void Unlock() { LeaveCriticalSection(&mCS); }
};
#else
@ -371,20 +337,10 @@ class MutexBase
DISALLOW_COPY_AND_ASSIGN(MutexBase);
public:
MutexBase()
{
pthread_mutex_init(&mMutex, nullptr);
}
MutexBase() { pthread_mutex_init(&mMutex, nullptr); }
void Lock()
{
pthread_mutex_lock(&mMutex);
}
void Unlock()
{
pthread_mutex_unlock(&mMutex);
}
void Lock() { pthread_mutex_lock(&mMutex); }
void Unlock() { pthread_mutex_unlock(&mMutex); }
};
#endif
@ -414,10 +370,7 @@ public:
MutexBase::Unlock();
}
bool IsLocked()
{
return mIsLocked;
}
bool IsLocked() { return mIsLocked; }
};
// This lock must be held while manipulating global state, such as
@ -429,14 +382,8 @@ class AutoLockState
DISALLOW_COPY_AND_ASSIGN(AutoLockState);
public:
AutoLockState()
{
gStateLock->Lock();
}
~AutoLockState()
{
gStateLock->Unlock();
}
AutoLockState() { gStateLock->Lock(); }
~AutoLockState() { gStateLock->Unlock(); }
};
class AutoUnlockState
@ -444,14 +391,8 @@ class AutoUnlockState
DISALLOW_COPY_AND_ASSIGN(AutoUnlockState);
public:
AutoUnlockState()
{
gStateLock->Unlock();
}
~AutoUnlockState()
{
gStateLock->Lock();
}
AutoUnlockState() { gStateLock->Unlock(); }
~AutoUnlockState() { gStateLock->Lock(); }
};
//---------------------------------------------------------------------------
@ -514,10 +455,7 @@ public:
return mBlockIntercepts = false;
}
bool InterceptsAreBlocked() const
{
return mBlockIntercepts;
}
bool InterceptsAreBlocked() const { return mBlockIntercepts; }
};
/* static */ Thread*
@ -563,10 +501,7 @@ public:
class StringTable
{
public:
StringTable()
{
(void)mSet.init(64);
}
StringTable() { (void)mSet.init(64); }
const char*
Intern(const char* aString)
@ -618,13 +553,11 @@ private:
class StringAlloc
{
public:
static char*
copy(const char* aString)
static char* copy(const char* aString)
{
return InfallibleAllocPolicy::strdup_(aString);
}
static void
free(char* aString)
static void free(char* aString)
{
InfallibleAllocPolicy::free_(aString);
}
@ -1278,8 +1211,7 @@ Options::Options(const char* aDMDEnvVar)
: mDMDEnvVar(InfallibleAllocPolicy::strdup_(aDMDEnvVar)),
mSampleBelowSize(4093, 100 * 100 * 1000),
mMaxFrames(StackTrace::MaxFrames, StackTrace::MaxFrames),
mShowDumpStats(false),
mMode(Normal)
mShowDumpStats(false)
{
char* e = mDMDEnvVar;
if (strcmp(e, "1") != 0) {
@ -1314,11 +1246,6 @@ Options::Options(const char* aDMDEnvVar)
} else if (GetBool(arg, "--show-dump-stats", &myBool)) {
mShowDumpStats = myBool;
} else if (strcmp(arg, "--mode=normal") == 0) {
mMode = Options::Normal;
} else if (strcmp(arg, "--mode=test") == 0) {
mMode = Options::Test;
} else if (strcmp(arg, "") == 0) {
// This can only happen if there is trailing whitespace. Ignore.
MOZ_ASSERT(isEnd);
@ -1354,7 +1281,6 @@ Options::BadArg(const char* aArg)
int(mMaxFrames.mMax),
int(mMaxFrames.mDefault));
StatusMsg(" --show-dump-stats=<yes|no> Show stats about dumps? [no]\n");
StatusMsg(" --mode=<normal|test> Mode of operation [normal]\n");
StatusMsg("\n");
exit(1);
}
@ -1371,21 +1297,6 @@ NopStackWalkCallback(uint32_t aFrameNumber, void* aPc, void* aSp,
}
#endif
// Note that fopen() can allocate.
static FILE*
OpenOutputFile(const char* aFilename)
{
FILE* fp = fopen(aFilename, "w");
if (!fp) {
StatusMsg("can't create %s file: %s\n", aFilename, strerror(errno));
exit(1);
}
return fp;
}
static void RunTestMode(UniquePtr<FpWriteFunc> aF1, UniquePtr<FpWriteFunc> aF2,
UniquePtr<FpWriteFunc> aF3, UniquePtr<FpWriteFunc> aF4);
// WARNING: this function runs *very* early -- before all static initializers
// have run. For this reason, non-scalar globals such as gStateLock and
// gStackTraceTable are allocated dynamically (so we can guarantee their
@ -1439,31 +1350,7 @@ Init(const malloc_table_t* aMallocTable)
gBlockTable->init(8192);
}
if (gOptions->IsTestMode()) {
// Do all necessary allocations before setting gIsDMDRunning so those
// allocations don't show up in our results. Once gIsDMDRunning is set we
// are intercepting malloc et al. in earnest.
//
// These files are written to $CWD. It would probably be better to write
// them to "TmpD" using the directory service, but that would require
// linking DMD with XPCOM.
auto f1 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-empty.json"));
auto f2 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-unsampled1.json"));
auto f3 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-unsampled2.json"));
auto f4 = MakeUnique<FpWriteFunc>(OpenOutputFile("full-sampled.json"));
gIsDMDRunning = true;
StatusMsg("running test mode...\n");
RunTestMode(Move(f1), Move(f2), Move(f3), Move(f4));
StatusMsg("finished test mode; DMD is now disabled again\n");
// Continue running so that the xpcshell test can complete, but DMD no
// longer needs to be running.
gIsDMDRunning = false;
} else {
gIsDMDRunning = true;
}
gIsDMDRunning = true;
}
//---------------------------------------------------------------------------
@ -1850,260 +1737,17 @@ AnalyzeReports(JSONWriter& aWriter)
// Testing
//---------------------------------------------------------------------------
// This function checks that heap blocks that have the same stack trace but
// different (or no) reporters get aggregated separately.
void Foo(int aSeven)
MOZ_EXPORT void
SetSampleBelowSize(size_t aSize)
{
char* a[6];
for (int i = 0; i < aSeven - 1; i++) {
a[i] = (char*) replace_malloc(128 - 16*i);
}
for (int i = 0; i < aSeven - 5; i++) {
Report(a[i]); // reported
}
Report(a[2]); // reported
Report(a[3]); // reported
// a[4], a[5] unreported
gOptions->SetSampleBelowSize(aSize);
}
// This stops otherwise-unused variables from being optimized away.
static void
UseItOrLoseIt(void* aPtr, int aSeven)
MOZ_EXPORT void
ClearBlocks()
{
char buf[64];
int n = sprintf(buf, "%p\n", aPtr);
if (n == 20 + aSeven) {
fprintf(stderr, "well, that is surprising");
}
}
// The output from this function feeds into DMD's xpcshell test.
static void
RunTestMode(UniquePtr<FpWriteFunc> aF1, UniquePtr<FpWriteFunc> aF2,
UniquePtr<FpWriteFunc> aF3, UniquePtr<FpWriteFunc> aF4)
{
// This test relies on the compiler not doing various optimizations, such as
// eliding unused replace_malloc() calls or unrolling loops with fixed
// iteration counts. So we want a constant value that the compiler can't
// determine statically, and we use that in various ways to prevent the above
// optimizations from happening.
//
// This code always sets |seven| to the value 7. It works because we know
// that "--mode=test" must be within the DMD environment variable if we reach
// here, but the compiler almost certainly does not.
//
char* env = getenv("DMD");
char* p1 = strstr(env, "--mode=t");
char* p2 = strstr(p1, "test");
int seven = p2 - p1;
// The first part of this test requires sampling to be disabled.
gOptions->SetSampleBelowSize(1);
//---------
// AnalyzeReports 1. Zero for everything.
JSONWriter writer1(Move(aF1));
AnalyzeReports(writer1);
//---------
// AnalyzeReports 2: 1 freed, 9 out of 10 unreported.
// AnalyzeReports 3: still present and unreported.
int i;
char* a = nullptr;
for (i = 0; i < seven + 3; i++) {
a = (char*) replace_malloc(100);
UseItOrLoseIt(a, seven);
}
replace_free(a);
// Note: 8 bytes is the smallest requested size that gives consistent
// behaviour across all platforms with jemalloc.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: thrice-reported.
char* a2 = (char*) replace_malloc(8);
Report(a2);
// AnalyzeReports 2: reported.
// AnalyzeReports 3: reportedness carries over, due to ReportOnAlloc.
char* b = (char*) replace_malloc(10);
ReportOnAlloc(b);
// ReportOnAlloc, then freed.
// AnalyzeReports 2: freed, irrelevant.
// AnalyzeReports 3: freed, irrelevant.
char* b2 = (char*) replace_malloc(1);
ReportOnAlloc(b2);
replace_free(b2);
// AnalyzeReports 2: reported 4 times.
// AnalyzeReports 3: freed, irrelevant.
char* c = (char*) replace_calloc(10, 3);
Report(c);
for (int i = 0; i < seven - 4; i++) {
Report(c);
}
// AnalyzeReports 2: ignored.
// AnalyzeReports 3: irrelevant.
Report((void*)(intptr_t)i);
// jemalloc rounds this up to 8192.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: freed.
char* e = (char*) replace_malloc(4096);
e = (char*) replace_realloc(e, 4097);
Report(e);
// First realloc is like malloc; second realloc is shrinking.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: re-reported.
char* e2 = (char*) replace_realloc(nullptr, 1024);
e2 = (char*) replace_realloc(e2, 512);
Report(e2);
// First realloc is like malloc; second realloc creates a min-sized block.
// XXX: on Windows, second realloc frees the block.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: freed, irrelevant.
char* e3 = (char*) replace_realloc(nullptr, 1023);
//e3 = (char*) replace_realloc(e3, 0);
MOZ_ASSERT(e3);
Report(e3);
// AnalyzeReports 2: freed, irrelevant.
// AnalyzeReports 3: freed, irrelevant.
char* f = (char*) replace_malloc(64);
replace_free(f);
// AnalyzeReports 2: ignored.
// AnalyzeReports 3: irrelevant.
Report((void*)(intptr_t)0x0);
// AnalyzeReports 2: mixture of reported and unreported.
// AnalyzeReports 3: all unreported.
Foo(seven);
Foo(seven);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: twice-reported.
char* g1 = (char*) replace_malloc(77);
ReportOnAlloc(g1);
ReportOnAlloc(g1);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: once-reported.
char* g2 = (char*) replace_malloc(78);
Report(g2);
ReportOnAlloc(g2);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: once-reported.
char* g3 = (char*) replace_malloc(79);
ReportOnAlloc(g3);
Report(g3);
// All the odd-ball ones.
// AnalyzeReports 2: all unreported.
// AnalyzeReports 3: all freed, irrelevant.
// XXX: no memalign on Mac
//void* x = memalign(64, 65); // rounds up to 128
//UseItOrLoseIt(x, seven);
// XXX: posix_memalign doesn't work on B2G
//void* y;
//posix_memalign(&y, 128, 129); // rounds up to 256
//UseItOrLoseIt(y, seven);
// XXX: valloc doesn't work on Windows.
//void* z = valloc(1); // rounds up to 4096
//UseItOrLoseIt(z, seven);
//aligned_alloc(64, 256); // XXX: C11 only
// AnalyzeReports 2.
JSONWriter writer2(Move(aF2));
AnalyzeReports(writer2);
//---------
Report(a2);
Report(a2);
replace_free(c);
replace_free(e);
Report(e2);
replace_free(e3);
//replace_free(x);
//replace_free(y);
//replace_free(z);
// AnalyzeReports 3.
JSONWriter writer3(Move(aF3));
AnalyzeReports(writer3);
//---------
// Clear all knowledge of existing blocks to give us a clean slate.
gBlockTable->clear();
gOptions->SetSampleBelowSize(128);
char* s;
// This equals the sample size, and so is reported exactly. It should be
// listed before records of the same size that are sampled.
s = (char*) replace_malloc(128);
UseItOrLoseIt(s, seven);
// This exceeds the sample size, and so is reported exactly.
s = (char*) replace_malloc(144);
UseItOrLoseIt(s, seven);
// These together constitute exactly one sample.
for (int i = 0; i < seven + 9; i++) {
s = (char*) replace_malloc(8);
UseItOrLoseIt(s, seven);
}
MOZ_ASSERT(gSmallBlockActualSizeCounter == 0);
// These fall 8 bytes short of a full sample.
for (int i = 0; i < seven + 8; i++) {
s = (char*) replace_malloc(8);
UseItOrLoseIt(s, seven);
}
MOZ_ASSERT(gSmallBlockActualSizeCounter == 120);
// This exceeds the sample size, and so is recorded exactly.
s = (char*) replace_malloc(256);
UseItOrLoseIt(s, seven);
MOZ_ASSERT(gSmallBlockActualSizeCounter == 120);
// This gets more than to a full sample from the |i < 15| loop above.
s = (char*) replace_malloc(96);
UseItOrLoseIt(s, seven);
MOZ_ASSERT(gSmallBlockActualSizeCounter == 88);
// This gets to another full sample.
for (int i = 0; i < seven - 2; i++) {
s = (char*) replace_malloc(8);
UseItOrLoseIt(s, seven);
}
MOZ_ASSERT(gSmallBlockActualSizeCounter == 0);
// This allocates 16, 32, ..., 128 bytes, which results in a heap block
// record that contains a mix of sample and non-sampled blocks, and so should
// be printed with '~' signs.
for (int i = 1; i <= seven + 1; i++) {
s = (char*) replace_malloc(i * 16);
UseItOrLoseIt(s, seven);
}
MOZ_ASSERT(gSmallBlockActualSizeCounter == 64);
// At the end we're 64 bytes into the current sample so we report ~1,424
// bytes of allocation overall, which is 64 less than the real value 1,488.
// AnalyzeReports 4.
JSONWriter writer4(Move(aF4));
AnalyzeReports(writer4);
gSmallBlockActualSizeCounter = 0;
}
} // namespace dmd

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

@ -147,6 +147,14 @@ StatusMsg(const char* aFmt, ...);
MOZ_EXPORT bool
IsRunning();
// Sets the sample-below size. Only used for testing purposes.
MOZ_EXPORT void
SetSampleBelowSize(size_t aSize);
// Clears all records of live allocations. Only used for testing purposes.
MOZ_EXPORT void
ClearBlocks();
} // namespace mozilla
} // namespace dmd

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

@ -1,4 +1,4 @@
#! /usr/bin/python
#! /usr/bin/env python
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -58,14 +58,73 @@ allocatorFns = [
]
class Record(object):
'''A record is an aggregation of heap blocks that have identical stack
traces. It can also be used to represent the difference between two
records.'''
def __init__(self):
self.numBlocks = 0
self.reqSize = 0
self.slopSize = 0
self.usableSize = 0
self.isSampled = False
self.allocatedAtDesc = None
self.reportedAtDescs = []
self.usableSizes = collections.defaultdict(int)
def isZero(self, args):
return self.numBlocks == 0 and \
self.reqSize == 0 and \
self.slopSize == 0 and \
self.usableSize == 0 and \
len(self.usableSizes) == 0
def negate(self):
self.numBlocks = -self.numBlocks
self.reqSize = -self.reqSize
self.slopSize = -self.slopSize
self.usableSize = -self.usableSize
negatedUsableSizes = collections.defaultdict(int)
for (usableSize, isSampled), count in self.usableSizes.items():
negatedUsableSizes[(-usableSize, isSampled)] = count
self.usableSizes = negatedUsableSizes
def subtract(self, r):
# We should only be calling this on records with matching stack traces.
# Check this.
assert self.allocatedAtDesc == r.allocatedAtDesc
assert self.reportedAtDescs == r.reportedAtDescs
self.numBlocks -= r.numBlocks
self.reqSize -= r.reqSize
self.slopSize -= r.slopSize
self.usableSize -= r.usableSize
self.isSampled = self.isSampled or r.isSampled
usableSizes1 = self.usableSizes
usableSizes2 = r.usableSizes
usableSizes3 = collections.defaultdict(int)
for usableSize, isSampled in usableSizes1:
counts1 = usableSizes1[usableSize, isSampled]
if (usableSize, isSampled) in usableSizes2:
counts2 = usableSizes2[usableSize, isSampled]
del usableSizes2[usableSize, isSampled]
counts3 = counts1 - counts2
if counts3 != 0:
if counts3 < 0:
usableSize = -usableSize
counts3 = -counts3
usableSizes3[usableSize, isSampled] = counts3
else:
usableSizes3[usableSize, isSampled] = counts1
for usableSize, isSampled in usableSizes2:
usableSizes3[-usableSize, isSampled] = \
usableSizes2[usableSize, isSampled]
self.usableSizes = usableSizes3
@staticmethod
def cmpByIsSampled(r1, r2):
# Treat sampled as smaller than non-sampled.
@ -74,17 +133,20 @@ class Record(object):
@staticmethod
def cmpByUsableSize(r1, r2):
# Sort by usable size, then req size, then by isSampled.
return cmp(r1.usableSize, r2.usableSize) or Record.cmpByReqSize(r1, r2)
return cmp(abs(r1.usableSize), abs(r2.usableSize)) or \
Record.cmpByReqSize(r1, r2)
@staticmethod
def cmpByReqSize(r1, r2):
# Sort by req size, then by isSampled.
return cmp(r1.reqSize, r2.reqSize) or Record.cmpByIsSampled(r1, r2)
return cmp(abs(r1.reqSize), abs(r2.reqSize)) or \
Record.cmpByIsSampled(r1, r2)
@staticmethod
def cmpBySlopSize(r1, r2):
# Sort by slop size, then by isSampled.
return cmp(r1.slopSize, r2.slopSize) or Record.cmpByIsSampled(r1, r2)
return cmp(abs(r1.slopSize), abs(r2.slopSize)) or \
Record.cmpByIsSampled(r1, r2)
sortByChoices = {
@ -105,7 +167,9 @@ def parseCommandLine():
description = '''
Analyze heap data produced by DMD.
If no files are specified, read from stdin; input can be gzipped.
If one file is specified, analyze it; if two files are specified, analyze the
difference.
Input files can be gzipped.
Write to stdout unless -o/--output is specified.
Stack traces are fixed to show function names, filenames and line numbers
unless --no-fix-stacks is specified; stack fixing modifies the original file
@ -131,16 +195,17 @@ variable is used to find breakpad symbols for stack fixing.
p.add_argument('-a', '--ignore-alloc-fns', action='store_true',
help='ignore allocation functions at the start of traces')
p.add_argument('-b', '--show-all-block-sizes', action='store_true',
help='show individual block sizes for each record')
p.add_argument('--no-fix-stacks', action='store_true',
help='do not fix stacks')
p.add_argument('--filter-stacks-for-testing', action='store_true',
help='filter stack traces; only useful for testing purposes')
p.add_argument('input_file')
p.add_argument('input_file',
help='a file produced by DMD')
p.add_argument('input_file2', nargs='?',
help='a file produced by DMD; if present, it is diff\'d with input_file')
return p.parse_args(sys.argv[1:])
@ -195,18 +260,16 @@ def fixStackTraces(inputFilename, isZipped, opener):
shutil.move(tmpFilename, inputFilename)
def main():
args = parseCommandLine()
def getDigestFromFile(args, inputFile):
# Handle gzipped input if necessary.
isZipped = args.input_file.endswith('.gz')
isZipped = inputFile.endswith('.gz')
opener = gzip.open if isZipped else open
# Fix stack traces unless otherwise instructed.
if not args.no_fix_stacks:
fixStackTraces(args.input_file, isZipped, opener)
fixStackTraces(inputFile, isZipped, opener)
with opener(args.input_file, 'rb') as f:
with opener(inputFile, 'rb') as f:
j = json.load(f)
if j['version'] != outputVersion:
@ -245,6 +308,31 @@ def main():
if len(frameKeys) > args.max_frames:
traceTable[traceKey] = frameKeys[:args.max_frames]
def buildTraceDescription(traceTable, frameTable, traceKey):
frameKeys = traceTable[traceKey]
fmt = ' #{:02d}{:}'
if args.filter_stacks_for_testing:
# When running SmokeDMD.cpp, every stack trace should contain at
# least one frame that contains 'DMD.cpp', from either |DMD.cpp| or
# |SmokeDMD.cpp|. (Or 'dmd.cpp' on Windows.) If we see such a
# frame, we replace the entire stack trace with a single,
# predictable frame. There is too much variation in the stack
# traces across different machines and platforms to do more precise
# matching, but this level of matching will result in failure if
# stack fixing fails completely.
for frameKey in frameKeys:
frameDesc = frameTable[frameKey]
if 'DMD.cpp' in frameDesc or 'dmd.cpp' in frameDesc:
return [fmt.format(1, ': ... DMD.cpp ...')]
# The frame number is always '#00' (see DMD.h for why), so we have to
# replace that with the correct frame number.
desc = []
for n, frameKey in enumerate(traceTable[traceKey], start=1):
desc.append(fmt.format(n, frameTable[frameKey][3:]))
return desc
# Aggregate blocks into records. All sufficiently similar blocks go into a
# single record.
@ -264,24 +352,33 @@ def main():
# derived from the block's 'alloc' and 'reps' (if present) stack
# traces.
#
# Each stack trace has a key in the JSON file. But we don't use that
# key to construct |recordKey|; instead we use the frame keys.
# This is because the stack trimming done for --max-frames can cause
# stack traces with distinct trace keys to end up with the same frame
# keys, and these should be considered equivalent. E.g. if we have
# distinct traces T1:[A,B,C] and T2:[A,B,D] and we trim the final frame
# of each they should be considered equivalent.
allocatedAt = block['alloc']
# We use frame descriptions (e.g. "#00: foo (X.cpp:99)") when comparing
# traces for equality. We can't use trace keys or frame keys because
# they're not comparable across different DMD runs (which is relevant
# when doing diffs).
#
# Using frame descriptions also fits in with the stack trimming done
# for --max-frames, which requires that stack traces with common
# beginnings but different endings to be considered equivalent. E.g. if
# we have distinct traces T1:[A:D1,B:D2,C:D3] and T2:[X:D1,Y:D2,Z:D4]
# and we trim the final frame of each they should be considered
# equivalent because the untrimmed frame descriptions (D1 and D2)
# match.
def makeRecordKeyPart(traceKey):
return str(map(lambda frameKey: frameTable[frameKey],
traceTable[traceKey]))
allocatedAtTraceKey = block['alloc']
if args.ignore_reports:
recordKey = str(traceTable[allocatedAt])
recordKey = makeRecordKeyPart(allocatedAtTraceKey)
records = liveRecords
else:
recordKey = str(traceTable[allocatedAt])
recordKey = makeRecordKeyPart(allocatedAtTraceKey)
if 'reps' in block:
reportedAts = block['reps']
for reportedAt in reportedAts:
recordKey += str(traceTable[reportedAt])
if len(reportedAts) == 1:
reportedAtTraceKeys = block['reps']
for reportedAtTraceKey in reportedAtTraceKeys:
recordKey += makeRecordKeyPart(reportedAtTraceKey)
if len(reportedAtTraceKeys) == 1:
records = onceReportedRecords
else:
records = twiceReportedRecords
@ -312,15 +409,92 @@ def main():
record.slopSize += slopSize
record.usableSize += usableSize
record.isSampled = record.isSampled or isSampled
record.allocatedAt = block['alloc']
if record.allocatedAtDesc == None:
record.allocatedAtDesc = \
buildTraceDescription(traceTable, frameTable,
allocatedAtTraceKey)
if args.ignore_reports:
pass
else:
if 'reps' in block:
record.reportedAts = block['reps']
if 'reps' in block and record.reportedAtDescs == []:
f = lambda k: buildTraceDescription(traceTable, frameTable, k)
record.reportedAtDescs = map(f, reportedAtTraceKeys)
record.usableSizes[(usableSize, isSampled)] += 1
# Print records.
# All the processed data for a single DMD file is called a "digest".
digest = {}
digest['dmdEnvVar'] = dmdEnvVar
digest['sampleBelowSize'] = sampleBelowSize
digest['heapUsableSize'] = heapUsableSize
digest['heapBlocks'] = heapBlocks
digest['heapIsSampled'] = heapIsSampled
if args.ignore_reports:
digest['liveRecords'] = liveRecords
else:
digest['unreportedRecords'] = unreportedRecords
digest['onceReportedRecords'] = onceReportedRecords
digest['twiceReportedRecords'] = twiceReportedRecords
return digest
def diffRecords(args, records1, records2):
records3 = {}
# Process records1.
for k in records1:
r1 = records1[k]
if k in records2:
# This record is present in both records1 and records2.
r2 = records2[k]
del records2[k]
r2.subtract(r1)
if not r2.isZero(args):
records3[k] = r2
else:
# This record is present only in records1.
r1.negate()
records3[k] = r1
for k in records2:
# This record is present only in records2.
records3[k] = records2[k]
return records3
def diffDigests(args, d1, d2):
d3 = {}
d3['dmdEnvVar'] = (d1['dmdEnvVar'], d2['dmdEnvVar'])
d3['sampleBelowSize'] = (d1['sampleBelowSize'], d2['sampleBelowSize'])
d3['heapUsableSize'] = d2['heapUsableSize'] - d1['heapUsableSize']
d3['heapBlocks'] = d2['heapBlocks'] - d1['heapBlocks']
d3['heapIsSampled'] = d2['heapIsSampled'] or d1['heapIsSampled']
if args.ignore_reports:
d3['liveRecords'] = diffRecords(args, d1['liveRecords'],
d2['liveRecords'])
else:
d3['unreportedRecords'] = diffRecords(args, d1['unreportedRecords'],
d2['unreportedRecords'])
d3['onceReportedRecords'] = diffRecords(args, d1['onceReportedRecords'],
d2['onceReportedRecords'])
d3['twiceReportedRecords'] = diffRecords(args, d1['twiceReportedRecords'],
d2['twiceReportedRecords'])
return d3
def printDigest(args, digest):
dmdEnvVar = digest['dmdEnvVar']
sampleBelowSize = digest['sampleBelowSize']
heapUsableSize = digest['heapUsableSize']
heapIsSampled = digest['heapIsSampled']
heapBlocks = digest['heapBlocks']
if args.ignore_reports:
liveRecords = digest['liveRecords']
else:
unreportedRecords = digest['unreportedRecords']
onceReportedRecords = digest['onceReportedRecords']
twiceReportedRecords = digest['twiceReportedRecords']
separator = '#' + '-' * 65 + '\n'
@ -339,27 +513,9 @@ def main():
def out(*arguments, **kwargs):
print(*arguments, file=args.output, **kwargs)
def printStack(traceTable, frameTable, traceKey):
frameKeys = traceTable[traceKey]
fmt = ' #{:02d}{:}'
if args.filter_stacks_for_testing:
# If any frame has "DMD.cpp" or "replace_malloc.c" in its
# description -- as should be the case for every stack trace when
# running DMD in test mode -- we replace the entire trace with a
# single, predictable frame. There is too much variation in the
# stack traces across different machines and platforms to do more
# specific matching.
for frameKey in frameKeys:
frameDesc = frameTable[frameKey]
if 'DMD.cpp' in frameDesc or 'replace_malloc.c' in frameDesc:
out(fmt.format(1, ': ... DMD.cpp ...'))
return
# The frame number is always '#00' (see DMD.h for why), so we have to
# replace that with the correct frame number.
for n, frameKey in enumerate(traceTable[traceKey], start=1):
out(fmt.format(n, frameTable[frameKey][3:]))
def printStack(traceDesc):
for frameDesc in traceDesc:
out(frameDesc)
def printRecords(recordKind, records, heapUsableSize):
RecordKind = recordKind.capitalize()
@ -400,6 +556,30 @@ def main():
format(number(record.usableSize, isSampled),
number(record.reqSize, isSampled),
number(record.slopSize, isSampled)))
abscmp = lambda ((usableSize1, _1a), _1b), \
((usableSize2, _2a), _2b): \
cmp(abs(usableSize1), abs(usableSize2))
usableSizes = sorted(record.usableSizes.items(), cmp=abscmp,
reverse=True)
hasSingleBlock = len(usableSizes) == 1 and usableSizes[0][1] == 1
if not hasSingleBlock:
out(' Individual block sizes: ', end='')
if len(usableSizes) == 0:
out('(no change)', end='')
else:
isFirst = True
for (usableSize, isSampled), count in usableSizes:
if not isFirst:
out('; ', end='')
out('{:}'.format(number(usableSize, isSampled)), end='')
if count > 1:
out(' x {:,d}'.format(count), end='')
isFirst = False
out()
out(' {:4.2f}% of the heap ({:4.2f}% cumulative)'.
format(perc(record.usableSize, heapUsableSize),
perc(kindCumulativeUsableSize, heapUsableSize)))
@ -410,44 +590,39 @@ def main():
format(perc(record.usableSize, kindUsableSize),
recordKind,
perc(kindCumulativeUsableSize, kindUsableSize)))
if args.show_all_block_sizes:
usableSizes = sorted(record.usableSizes.items(), reverse=True)
out(' Individual block sizes: ', end='')
isFirst = True
for (usableSize, isSampled), count in usableSizes:
if not isFirst:
out('; ', end='')
out('{:}'.format(number(usableSize, isSampled)), end='')
if count > 1:
out(' x {:,d}'.format(count), end='')
isFirst = False
out()
out(' Allocated at {')
printStack(traceTable, frameTable, record.allocatedAt)
printStack(record.allocatedAtDesc)
out(' }')
if args.ignore_reports:
pass
else:
if hasattr(record, 'reportedAts'):
for n, reportedAt in enumerate(record.reportedAts):
again = 'again ' if n > 0 else ''
out(' Reported {:}at {{'.format(again))
printStack(traceTable, frameTable, reportedAt)
out(' }')
for n, reportedAtDesc in enumerate(record.reportedAtDescs):
again = 'again ' if n > 0 else ''
out(' Reported {:}at {{'.format(again))
printStack(reportedAtDesc)
out(' }')
out('}\n')
return (kindUsableSize, kindBlocks)
# Print header.
out(separator)
out('Invocation {')
out(' $DMD = \'' + dmdEnvVar + '\'')
out(' Sample-below size = ' + str(sampleBelowSize))
out('}\n')
def printInvocation(n, dmdEnvVar, sampleBelowSize):
out('Invocation{:} {{'.format(n))
out(' $DMD = \'' + dmdEnvVar + '\'')
out(' Sample-below size = ' + str(sampleBelowSize))
out('}\n')
# Print command line. Strip dirs so the output is deterministic, which is
# needed for testing.
out(separator, end='')
out('# ' + ' '.join(map(os.path.basename, sys.argv)) + '\n')
# Print invocation(s).
if type(dmdEnvVar) is not tuple:
printInvocation('', dmdEnvVar, sampleBelowSize)
else:
printInvocation(' 1', dmdEnvVar[0], sampleBelowSize[0])
printInvocation(' 2', dmdEnvVar[1], sampleBelowSize[1])
# Print records.
if args.ignore_reports:
@ -458,10 +633,10 @@ def main():
printRecords('twice-reported', twiceReportedRecords, heapUsableSize)
unreportedUsableSize, unreportedBlocks = \
printRecords('unreported', unreportedRecords, heapUsableSize)
printRecords('unreported', unreportedRecords, heapUsableSize)
onceReportedUsableSize, onceReportedBlocks = \
printRecords('once-reported', onceReportedRecords, heapUsableSize)
printRecords('once-reported', onceReportedRecords, heapUsableSize)
# Print summary.
out(separator)
@ -499,5 +674,15 @@ def main():
out('}\n')
def main():
args = parseCommandLine()
digest = getDigestFromFile(args, args.input_file)
if args.input_file2:
digest2 = getDigestFromFile(args, args.input_file2)
digest = diffDigests(args, digest, digest2)
printDigest(args, digest)
if __name__ == '__main__':
main()

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

@ -33,7 +33,5 @@ if CONFIG['OS_ARCH'] == 'WINNT':
'dbghelp',
]
XPCSHELL_TESTS_MANIFESTS += [
'test/xpcshell.ini',
]
TEST_DIRS += ['test']

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

@ -0,0 +1,335 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// This program is used by the DMD xpcshell test. It is run under DMD and
// produces some output. The xpcshell test then post-processes and checks this
// output.
//
// Note that this file does not have "Test" or "test" in its name, because that
// will cause the build system to not record breakpad symbols for it, which
// will stop the post-processing (which includes stack fixing) from working
// correctly.
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "mozilla/Assertions.h"
#include "mozilla/JSONWriter.h"
#include "mozilla/UniquePtr.h"
#include "DMD.h"
using mozilla::JSONWriter;
using mozilla::MakeUnique;
using namespace mozilla::dmd;
class FpWriteFunc : public mozilla::JSONWriteFunc
{
public:
explicit FpWriteFunc(const char* aFilename)
{
mFp = fopen(aFilename, "w");
if (!mFp) {
fprintf(stderr, "SmokeDMD: can't create %s file: %s\n",
aFilename, strerror(errno));
exit(1);
}
}
~FpWriteFunc() { fclose(mFp); }
void Write(const char* aStr) { fputs(aStr, mFp); }
private:
FILE* mFp;
};
// This stops otherwise-unused variables from being optimized away.
static void
UseItOrLoseIt(void* aPtr, int aSeven)
{
char buf[64];
int n = sprintf(buf, "%p\n", aPtr);
if (n == 20 + aSeven) {
fprintf(stderr, "well, that is surprising");
}
}
// This function checks that heap blocks that have the same stack trace but
// different (or no) reporters get aggregated separately.
void Foo(int aSeven)
{
char* a[6];
for (int i = 0; i < aSeven - 1; i++) {
a[i] = (char*) malloc(128 - 16*i);
}
// Oddly, some versions of clang will cause identical stack traces to be
// generated for adjacent calls to Report(), which breaks the test. Inserting
// the UseItOrLoseIt() calls in between is enough to prevent this.
Report(a[2]); // reported
UseItOrLoseIt(a[2], aSeven);
for (int i = 0; i < aSeven - 5; i++) {
Report(a[i]); // reported
}
UseItOrLoseIt(a[2], aSeven);
Report(a[3]); // reported
// a[4], a[5] unreported
}
void
RunTests()
{
// These files are written to $CWD.
auto f1 = MakeUnique<FpWriteFunc>("full-empty.json");
auto f2 = MakeUnique<FpWriteFunc>("full-unsampled1.json");
auto f3 = MakeUnique<FpWriteFunc>("full-unsampled2.json");
auto f4 = MakeUnique<FpWriteFunc>("full-sampled.json");
// This test relies on the compiler not doing various optimizations, such as
// eliding unused malloc() calls or unrolling loops with fixed iteration
// counts. So we compile it with -O0 (or equivalent), which probably prevents
// that. We also use the following variable for various loop iteration
// counts, just in case compilers might unroll very small loops even with
// -O0.
int seven = 7;
// Make sure that DMD is actually running; it is initialized on the first
// allocation.
int *x = (int*)malloc(100);
UseItOrLoseIt(x, seven);
MOZ_RELEASE_ASSERT(IsRunning());
// The first part of this test requires sampling to be disabled.
SetSampleBelowSize(1);
// The file manipulations above may have done some heap allocations.
// Clear all knowledge of existing blocks to give us a clean slate.
ClearBlocks();
//---------
// AnalyzeReports 1. Zero for everything.
JSONWriter writer1(Move(f1));
AnalyzeReports(writer1);
//---------
// AnalyzeReports 2: 1 freed, 9 out of 10 unreported.
// AnalyzeReports 3: still present and unreported.
int i;
char* a = nullptr;
for (i = 0; i < seven + 3; i++) {
a = (char*) malloc(100);
UseItOrLoseIt(a, seven);
}
free(a);
// Note: 8 bytes is the smallest requested size that gives consistent
// behaviour across all platforms with jemalloc.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: thrice-reported.
char* a2 = (char*) malloc(8);
Report(a2);
// AnalyzeReports 2: reported.
// AnalyzeReports 3: reportedness carries over, due to ReportOnAlloc.
char* b = (char*) malloc(10);
ReportOnAlloc(b);
// ReportOnAlloc, then freed.
// AnalyzeReports 2: freed, irrelevant.
// AnalyzeReports 3: freed, irrelevant.
char* b2 = (char*) malloc(1);
ReportOnAlloc(b2);
free(b2);
// AnalyzeReports 2: reported 4 times.
// AnalyzeReports 3: freed, irrelevant.
char* c = (char*) calloc(10, 3);
Report(c);
for (int i = 0; i < seven - 4; i++) {
Report(c);
}
// AnalyzeReports 2: ignored.
// AnalyzeReports 3: irrelevant.
Report((void*)(intptr_t)i);
// jemalloc rounds this up to 8192.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: freed.
char* e = (char*) malloc(4096);
e = (char*) realloc(e, 4097);
Report(e);
// First realloc is like malloc; second realloc is shrinking.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: re-reported.
char* e2 = (char*) realloc(nullptr, 1024);
e2 = (char*) realloc(e2, 512);
Report(e2);
// First realloc is like malloc; second realloc creates a min-sized block.
// XXX: on Windows, second realloc frees the block.
// AnalyzeReports 2: reported.
// AnalyzeReports 3: freed, irrelevant.
char* e3 = (char*) realloc(nullptr, 1023);
//e3 = (char*) realloc(e3, 0);
MOZ_ASSERT(e3);
Report(e3);
// AnalyzeReports 2: freed, irrelevant.
// AnalyzeReports 3: freed, irrelevant.
char* f = (char*) malloc(64);
free(f);
// AnalyzeReports 2: ignored.
// AnalyzeReports 3: irrelevant.
Report((void*)(intptr_t)0x0);
// AnalyzeReports 2: mixture of reported and unreported.
// AnalyzeReports 3: all unreported.
Foo(seven);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: twice-reported.
char* g1 = (char*) malloc(77);
ReportOnAlloc(g1);
ReportOnAlloc(g1);
// AnalyzeReports 2: mixture of reported and unreported.
// AnalyzeReports 3: all unreported.
// Nb: this Foo() call is deliberately not adjacent to the previous one. See
// the comment about adjacent calls in Foo() for more details.
Foo(seven);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: once-reported.
char* g2 = (char*) malloc(78);
Report(g2);
ReportOnAlloc(g2);
// AnalyzeReports 2: twice-reported.
// AnalyzeReports 3: once-reported.
char* g3 = (char*) malloc(79);
ReportOnAlloc(g3);
Report(g3);
// All the odd-ball ones.
// AnalyzeReports 2: all unreported.
// AnalyzeReports 3: all freed, irrelevant.
// XXX: no memalign on Mac
//void* w = memalign(64, 65); // rounds up to 128
//UseItOrLoseIt(w, seven);
// XXX: posix_memalign doesn't work on B2G
//void* x;
//posix_memalign(&y, 128, 129); // rounds up to 256
//UseItOrLoseIt(x, seven);
// XXX: valloc doesn't work on Windows.
//void* y = valloc(1); // rounds up to 4096
//UseItOrLoseIt(y, seven);
// XXX: C11 only
//void* z = aligned_alloc(64, 256);
//UseItOrLoseIt(z, seven);
// AnalyzeReports 2.
JSONWriter writer2(Move(f2));
AnalyzeReports(writer2);
//---------
Report(a2);
Report(a2);
free(c);
free(e);
Report(e2);
free(e3);
//free(w);
//free(x);
//free(y);
//free(z);
// AnalyzeReports 3.
JSONWriter writer3(Move(f3));
AnalyzeReports(writer3);
//---------
// The first part of this test requires sampling to be disabled.
SetSampleBelowSize(128);
// Clear all knowledge of existing blocks to give us a clean slate.
ClearBlocks();
char* s;
// This equals the sample size, and so is reported exactly. It should be
// listed before records of the same size that are sampled.
s = (char*) malloc(128);
UseItOrLoseIt(s, seven);
// This exceeds the sample size, and so is reported exactly.
s = (char*) malloc(144);
UseItOrLoseIt(s, seven);
// These together constitute exactly one sample.
for (int i = 0; i < seven + 9; i++) {
s = (char*) malloc(8);
UseItOrLoseIt(s, seven);
}
// These fall 8 bytes short of a full sample.
for (int i = 0; i < seven + 8; i++) {
s = (char*) malloc(8);
UseItOrLoseIt(s, seven);
}
// This exceeds the sample size, and so is recorded exactly.
s = (char*) malloc(256);
UseItOrLoseIt(s, seven);
// This gets more than to a full sample from the |i < seven + 8| loop above.
s = (char*) malloc(96);
UseItOrLoseIt(s, seven);
// This gets to another full sample.
for (int i = 0; i < seven - 2; i++) {
s = (char*) malloc(8);
UseItOrLoseIt(s, seven);
}
// This allocates 16, 32, ..., 128 bytes, which results in a heap block
// record that contains a mix of sample and non-sampled blocks, and so should
// be printed with '~' signs.
for (int i = 1; i <= seven + 1; i++) {
s = (char*) malloc(i * 16);
UseItOrLoseIt(s, seven);
}
// At the end we're 64 bytes into the current sample so we report ~1,424
// bytes of allocation overall, which is 64 less than the real value 1,488.
// AnalyzeReports 4.
JSONWriter writer4(Move(f4));
AnalyzeReports(writer4);
}
int main()
{
RunTests();
return 0;
}

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-heap-empty-actual.txt --ignore-reports full-empty.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-heap-sampled-actual.txt --ignore-reports full-sampled.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 128
}
@ -10,6 +11,7 @@ Invocation {
Live {
~4 blocks in heap block record 1 of 7
~512 bytes (~512 requested / ~0 slop)
Individual block sizes: ~128 x 3; 128
35.96% of the heap (35.96% cumulative)
Allocated at {
#01: ... DMD.cpp ...

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-heap-unsampled1-actual.txt --ignore-reports full-unsampled1.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}
@ -28,6 +29,7 @@ Live {
Live {
9 blocks in heap block record 3 of 12
1,008 bytes (900 requested / 108 slop)
Individual block sizes: 112 x 9
8.34% of the heap (84.58% cumulative)
Allocated at {
#01: ... DMD.cpp ...
@ -37,6 +39,7 @@ Live {
Live {
6 blocks in heap block record 4 of 12
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
4.37% of the heap (88.95% cumulative)
Allocated at {
#01: ... DMD.cpp ...
@ -46,6 +49,7 @@ Live {
Live {
6 blocks in heap block record 5 of 12
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
4.37% of the heap (93.32% cumulative)
Allocated at {
#01: ... DMD.cpp ...

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-heap-unsampled2-actual.txt --ignore-reports full-unsampled2.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}
@ -10,6 +11,7 @@ Invocation {
Live {
9 blocks in heap block record 1 of 9
1,008 bytes (900 requested / 108 slop)
Individual block sizes: 112 x 9
35.49% of the heap (35.49% cumulative)
Allocated at {
#01: ... DMD.cpp ...
@ -19,6 +21,7 @@ Live {
Live {
6 blocks in heap block record 2 of 9
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
18.59% of the heap (54.08% cumulative)
Allocated at {
#01: ... DMD.cpp ...
@ -28,6 +31,7 @@ Live {
Live {
6 blocks in heap block record 3 of 9
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
18.59% of the heap (72.68% cumulative)
Allocated at {
#01: ... DMD.cpp ...

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-reports-empty-actual.txt full-empty.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-reports-sampled-actual.txt full-sampled.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 128
}
@ -14,6 +15,7 @@ Invocation {
Unreported {
~4 blocks in heap block record 1 of 7
~512 bytes (~512 requested / ~0 slop)
Individual block sizes: ~128 x 3; 128
35.96% of the heap (35.96% cumulative)
35.96% of unreported (35.96% cumulative)
Allocated at {

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-reports-unsampled1-actual.txt full-unsampled1.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}
@ -76,6 +77,7 @@ Twice-reported {
Unreported {
9 blocks in heap block record 1 of 3
1,008 bytes (900 requested / 108 slop)
Individual block sizes: 112 x 9
8.34% of the heap (8.34% cumulative)
81.82% of unreported (81.82% cumulative)
Allocated at {
@ -86,6 +88,7 @@ Unreported {
Unreported {
2 blocks in heap block record 2 of 3
112 bytes (112 requested / 0 slop)
Individual block sizes: 64; 48
0.93% of the heap (9.27% cumulative)
9.09% of unreported (90.91% cumulative)
Allocated at {
@ -96,6 +99,7 @@ Unreported {
Unreported {
2 blocks in heap block record 3 of 3
112 bytes (112 requested / 0 slop)
Individual block sizes: 64; 48
0.93% of the heap (10.19% cumulative)
9.09% of unreported (100.00% cumulative)
Allocated at {
@ -147,6 +151,7 @@ Once-reported {
Once-reported {
2 blocks in heap block record 4 of 11
240 bytes (240 requested / 0 slop)
Individual block sizes: 128; 112
1.99% of the heap (82.46% cumulative)
2.27% of once-reported (94.18% cumulative)
Allocated at {
@ -160,6 +165,7 @@ Once-reported {
Once-reported {
2 blocks in heap block record 5 of 11
240 bytes (240 requested / 0 slop)
Individual block sizes: 128; 112
1.99% of the heap (84.45% cumulative)
2.27% of once-reported (96.45% cumulative)
Allocated at {

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

@ -1,7 +1,8 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o full-reports-unsampled2-actual.txt full-unsampled2.json
Invocation {
$DMD = '--mode=test'
$DMD = '1'
Sample-below size = 1
}
@ -44,6 +45,7 @@ Twice-reported {
Unreported {
9 blocks in heap block record 1 of 3
1,008 bytes (900 requested / 108 slop)
Individual block sizes: 112 x 9
35.49% of the heap (35.49% cumulative)
48.84% of unreported (48.84% cumulative)
Allocated at {
@ -54,6 +56,7 @@ Unreported {
Unreported {
6 blocks in heap block record 2 of 3
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
18.59% of the heap (54.08% cumulative)
25.58% of unreported (74.42% cumulative)
Allocated at {
@ -64,6 +67,7 @@ Unreported {
Unreported {
6 blocks in heap block record 3 of 3
528 bytes (528 requested / 0 slop)
Individual block sizes: 128; 112; 96; 80; 64; 48
18.59% of the heap (72.68% cumulative)
25.58% of unreported (100.00% cumulative)
Allocated at {

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

@ -0,0 +1,26 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SimplePrograms([
'SmokeDMD',
])
# See the comment at the top of SmokeDMD.cpp:RunTests().
if CONFIG['OS_ARCH'] == 'WINNT':
CXXFLAGS += ['-Og-']
else:
CXXFLAGS += ['-O0']
DEFINES['MOZ_NO_MOZALLOC'] = True
DISABLE_STL_WRAPPING = True
USE_LIBS += ['dmd']
XPCSHELL_TESTS_MANIFESTS += [
'xpcshell.ini',
]

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

@ -0,0 +1,127 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o script-diff-basic-actual.txt script-diff1.json script-diff2.json
Invocation 1 {
$DMD = '--sample-below=127'
Sample-below size = 127
}
Invocation 2 {
$DMD = '--sample-below=63'
Sample-below size = 63
}
#-----------------------------------------------------------------
Twice-reported {
~-1 blocks in heap block record 1 of 1
~-1,088 bytes (~-1,064 requested / ~-24 slop)
Individual block sizes: -1,024; ~-127; ~63
15.46% of the heap (15.46% cumulative)
100.00% of twice-reported (100.00% cumulative)
Allocated at {
#01: F (F.cpp:99)
}
Reported at {
#01: R1 (R1.cpp:99)
}
Reported again at {
#01: R2 (R2.cpp:99)
}
}
#-----------------------------------------------------------------
Unreported {
4 blocks in heap block record 1 of 5
16,384 bytes (16,384 requested / 0 slop)
Individual block sizes: 4,096 x 4
-232.76% of the heap (-232.76% cumulative)
371.01% of unreported (371.01% cumulative)
Allocated at {
#01: E (E.cpp:99)
}
}
Unreported {
~7 blocks in heap block record 2 of 5
~-11,968 bytes (~-12,016 requested / ~48 slop)
Individual block sizes: -15,360; 2,048; 512 x 2; 128; ~-127; 64 x 4; ~63
170.02% of the heap (-62.74% cumulative)
-271.01% of unreported (100.00% cumulative)
Allocated at {
#01: F (F.cpp:99)
}
}
Unreported {
0 blocks in heap block record 3 of 5
0 bytes (-384 requested / 384 slop)
Individual block sizes: (no change)
-0.00% of the heap (-62.74% cumulative)
0.00% of unreported (100.00% cumulative)
Allocated at {
#01: C (C.cpp:99)
}
}
Unreported {
-2 blocks in heap block record 4 of 5
0 bytes (0 requested / 0 slop)
Individual block sizes: 8,192 x 2; -4,096 x 4
-0.00% of the heap (-62.74% cumulative)
0.00% of unreported (100.00% cumulative)
Allocated at {
#01: B (B.cpp:99)
}
}
Unreported {
0 blocks in heap block record 5 of 5
0 bytes (0 requested / 0 slop)
Individual block sizes: 20,480; -16,384; -8,192; 4,096
-0.00% of the heap (-62.74% cumulative)
0.00% of unreported (100.00% cumulative)
Allocated at {
#01: G (G.cpp:99)
}
}
#-----------------------------------------------------------------
Once-reported {
-3 blocks in heap block record 1 of 2
-10,240 bytes (-10,192 requested / -48 slop)
Individual block sizes: -4,096 x 2; -2,048
145.48% of the heap (145.48% cumulative)
98.77% of once-reported (98.77% cumulative)
Allocated at {
#01: D (D.cpp:99)
}
Reported at {
#01: R1 (R1.cpp:99)
}
}
Once-reported {
~-1 blocks in heap block record 2 of 2
~-127 bytes (~-151 requested / ~24 slop)
1.80% of the heap (147.28% cumulative)
1.23% of once-reported (100.00% cumulative)
Allocated at {
#01: F (F.cpp:99)
}
Reported at {
#01: R1 (R1.cpp:99)
}
}
#-----------------------------------------------------------------
Summary {
Total: ~-7,039 bytes (100.00%) in ~4 blocks (100.00%)
Unreported: ~4,416 bytes (-62.74%) in ~9 blocks (225.00%)
Once-reported: ~-10,367 bytes (147.28%) in ~-4 blocks (-100.00%)
Twice-reported: ~-1,088 bytes ( 15.46%) in ~-1 blocks (-25.00%)
}

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

@ -0,0 +1,81 @@
#-----------------------------------------------------------------
# dmd.py --filter-stacks-for-testing -o script-diff-options-actual.txt --ignore-reports script-diff1.json script-diff2.json
Invocation 1 {
$DMD = '--sample-below=127'
Sample-below size = 127
}
Invocation 2 {
$DMD = '--sample-below=63'
Sample-below size = 63
}
#-----------------------------------------------------------------
Live {
4 blocks in heap block record 1 of 6
16,384 bytes (16,384 requested / 0 slop)
Individual block sizes: 4,096 x 4
-232.76% of the heap (-232.76% cumulative)
Allocated at {
#01: E (E.cpp:99)
}
}
Live {
~5 blocks in heap block record 2 of 6
~-13,183 bytes (~-13,231 requested / ~48 slop)
Individual block sizes: -15,360; 2,048; -1,024; 512 x 2; 128; ~-127 x 3; 64 x 4; ~63 x 2
187.29% of the heap (-45.48% cumulative)
Allocated at {
#01: F (F.cpp:99)
}
}
Live {
-3 blocks in heap block record 3 of 6
-10,240 bytes (-10,192 requested / -48 slop)
Individual block sizes: -4,096 x 2; -2,048
145.48% of the heap (100.00% cumulative)
Allocated at {
#01: D (D.cpp:99)
}
}
Live {
0 blocks in heap block record 4 of 6
0 bytes (-384 requested / 384 slop)
Individual block sizes: (no change)
-0.00% of the heap (100.00% cumulative)
Allocated at {
#01: C (C.cpp:99)
}
}
Live {
0 blocks in heap block record 5 of 6
0 bytes (0 requested / 0 slop)
Individual block sizes: 20,480; -16,384; -8,192; 4,096
-0.00% of the heap (100.00% cumulative)
Allocated at {
#01: G (G.cpp:99)
}
}
Live {
-2 blocks in heap block record 6 of 6
0 bytes (0 requested / 0 slop)
Individual block sizes: 8,192 x 2; -4,096 x 4
-0.00% of the heap (100.00% cumulative)
Allocated at {
#01: B (B.cpp:99)
}
}
#-----------------------------------------------------------------
Summary {
Total: ~-7,039 bytes in ~4 blocks
}

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