mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1060567: Debugger.Memory.prototype.takeCensus: provide byte counts on request. r=fitzgen
This commit is contained in:
parent
048f2b5f03
commit
76347c9f12
@ -6,9 +6,27 @@ var Pattern = Match.Pattern;
|
||||
var g = newGlobal();
|
||||
var dbg = new Debugger(g);
|
||||
|
||||
Pattern({ count: Pattern.NATURAL })
|
||||
Pattern({ count: Pattern.NATURAL,
|
||||
bytes: Pattern.NATURAL })
|
||||
.assert(dbg.memory.takeCensus({ breakdown: { by: 'count' } }));
|
||||
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: false } });
|
||||
assertEq('count' in census, false);
|
||||
assertEq('bytes' in census, false);
|
||||
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: false } });
|
||||
assertEq('count' in census, true);
|
||||
assertEq('bytes' in census, false);
|
||||
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: false, bytes: true } });
|
||||
assertEq('count' in census, false);
|
||||
assertEq('bytes' in census, true);
|
||||
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'count', count: true, bytes: true } });
|
||||
assertEq('count' in census, true);
|
||||
assertEq('bytes' in census, true);
|
||||
|
||||
|
||||
// Pattern doesn't mind objects with extra properties, so we'll restrict this
|
||||
// list to the object classes we're pretty sure are going to stick around for
|
||||
// the forseeable future.
|
||||
|
@ -14,6 +14,20 @@ assertThrowsValue(() => {
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
dbg.memory.takeCensus({
|
||||
breakdown: { by: 'count', get count() { throw "ಠ_ಠ" } }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
assertThrowsValue(() => {
|
||||
dbg.memory.takeCensus({
|
||||
breakdown: { by: 'count', get bytes() { throw "ಠ_ಠ" } }
|
||||
});
|
||||
}, "ಠ_ಠ");
|
||||
|
||||
|
||||
|
||||
assertThrowsValue(() => {
|
||||
dbg.memory.takeCensus({
|
||||
breakdown: { by: 'objectClass', get then() { throw "ಠ_ಠ" } }
|
||||
|
57
js/src/jit-test/tests/debug/Memory-takeCensus-10.js
Normal file
57
js/src/jit-test/tests/debug/Memory-takeCensus-10.js
Normal file
@ -0,0 +1,57 @@
|
||||
// Check byte counts produced by takeCensus.
|
||||
|
||||
let g = newGlobal();
|
||||
let dbg = new Debugger(g);
|
||||
|
||||
let sizeOfAM = byteSize(allocationMarker());
|
||||
|
||||
// Allocate a single allocation marker, and check that we can find it.
|
||||
g.eval('let hold = allocationMarker();');
|
||||
let census = dbg.memory.takeCensus({ breakdown: { by: 'objectClass' } });
|
||||
assertEq(census.AllocationMarker.count, 1);
|
||||
assertEq(census.AllocationMarker.bytes, sizeOfAM);
|
||||
|
||||
g.evaluate(`
|
||||
var objs = [];
|
||||
function fnerd() {
|
||||
objs.push(allocationMarker());
|
||||
for (let i = 0; i < 10; i++)
|
||||
objs.push(allocationMarker());
|
||||
}
|
||||
`,
|
||||
{ fileName: 'J. Edgar Hoover', lineNumber: 2000 });
|
||||
|
||||
dbg.memory.allocationSamplingProbability = 1;
|
||||
dbg.memory.trackingAllocationSites = true;
|
||||
|
||||
g.hold = null;
|
||||
g.fnerd();
|
||||
|
||||
let census = dbg.memory.takeCensus({
|
||||
breakdown: { by: 'objectClass',
|
||||
then: { by: 'allocationStack' }
|
||||
}
|
||||
});
|
||||
|
||||
let seen = 0;
|
||||
census.AllocationMarker.forEach((v, k) => {
|
||||
assertEq(k.functionDisplayName, 'fnerd');
|
||||
assertEq(k.source, 'J. Edgar Hoover');
|
||||
switch (k.line) {
|
||||
case 2003:
|
||||
assertEq(v.count, 1);
|
||||
assertEq(v.bytes, sizeOfAM);
|
||||
seen++;
|
||||
break;
|
||||
|
||||
case 2005:
|
||||
assertEq(v.count, 10);
|
||||
assertEq(v.bytes, 10 * sizeOfAM);
|
||||
seen++;
|
||||
break;
|
||||
|
||||
default: assertEq(true, false);
|
||||
}
|
||||
});
|
||||
|
||||
assertEq(seen, 2);
|
@ -536,22 +536,36 @@ CountDeleter::operator()(CountBase* ptr)
|
||||
|
||||
// The simplest type: just count everything.
|
||||
class SimpleCount : public CountType {
|
||||
UniquePtr<char16_t[], JS::FreePolicy> label;
|
||||
|
||||
struct Count : CountBase {
|
||||
explicit Count(SimpleCount& count) : CountBase(count) { }
|
||||
size_t totalBytes_;
|
||||
|
||||
explicit Count(SimpleCount& count)
|
||||
: CountBase(count),
|
||||
totalBytes_(0)
|
||||
{ }
|
||||
};
|
||||
|
||||
UniquePtr<char16_t[], JS::FreePolicy> label;
|
||||
bool reportCount : 1;
|
||||
bool reportBytes : 1;
|
||||
|
||||
public:
|
||||
SimpleCount(Census& census,
|
||||
UniquePtr<char16_t[], JS::FreePolicy>& label)
|
||||
UniquePtr<char16_t[], JS::FreePolicy>& label,
|
||||
bool reportCount=true,
|
||||
bool reportBytes=true)
|
||||
: CountType(census),
|
||||
label(Move(label))
|
||||
label(Move(label)),
|
||||
reportCount(reportCount),
|
||||
reportBytes(reportBytes)
|
||||
{ }
|
||||
|
||||
explicit SimpleCount(Census& census)
|
||||
: CountType(census),
|
||||
label(nullptr)
|
||||
label(nullptr),
|
||||
reportCount(true),
|
||||
reportBytes(true)
|
||||
{ }
|
||||
|
||||
CountBasePtr makeCount() override {
|
||||
@ -568,16 +582,24 @@ class SimpleCount : public CountType {
|
||||
bool count(CountBase& countBase, const Node& node) override {
|
||||
Count& count = static_cast<Count&>(countBase);
|
||||
count.total_++;
|
||||
if (reportBytes)
|
||||
count.totalBytes_ += node.size(census.cx->runtime()->debuggerMallocSizeOf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool report(CountBase& countBase, MutableHandleValue report) override {
|
||||
Count& count = static_cast<Count&>(countBase);
|
||||
|
||||
RootedPlainObject obj(census.cx, NewBuiltinClassInstance<PlainObject>(census.cx));
|
||||
RootedValue countValue(census.cx, NumberValue(count.total_));
|
||||
if (!obj)
|
||||
return false;
|
||||
if (!DefineProperty(census.cx, obj, census.cx->names().count, countValue))
|
||||
|
||||
RootedValue countValue(census.cx, NumberValue(count.total_));
|
||||
if (reportCount && !DefineProperty(census.cx, obj, census.cx->names().count, countValue))
|
||||
return false;
|
||||
|
||||
RootedValue bytesValue(census.cx, NumberValue(count.totalBytes_));
|
||||
if (reportBytes && !DefineProperty(census.cx, obj, census.cx->names().bytes, bytesValue))
|
||||
return false;
|
||||
|
||||
if (label) {
|
||||
@ -1131,12 +1153,14 @@ class ByAllocationStack : public CountType {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count.noStack->total_ > 0) {
|
||||
RootedValue noStackReport(cx);
|
||||
if (!count.noStack->report(&noStackReport))
|
||||
return false;
|
||||
RootedValue noStack(cx, StringValue(cx->names().noStack));
|
||||
if (!MapObject::set(cx, map, noStack, noStackReport))
|
||||
return false;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(generation == count.table.generation());
|
||||
|
||||
@ -1237,6 +1261,15 @@ ParseBreakdown(Census& census, HandleValue breakdownValue)
|
||||
return nullptr;
|
||||
|
||||
if (StringEqualsAscii(by, "count")) {
|
||||
RootedValue countValue(cx), bytesValue(cx);
|
||||
if (!GetProperty(cx, breakdown, breakdown, cx->names().count, &countValue) ||
|
||||
!GetProperty(cx, breakdown, breakdown, cx->names().bytes, &bytesValue))
|
||||
return nullptr;
|
||||
|
||||
// Both 'count' and 'bytes' default to true if omitted, but ToBoolean
|
||||
// naturally treats 'undefined' as false; fix this up.
|
||||
if (countValue.isUndefined()) countValue.setBoolean(true);
|
||||
if (bytesValue.isUndefined()) bytesValue.setBoolean(true);
|
||||
|
||||
// Undocumented feature, for testing: { by: 'count' } breakdowns can have
|
||||
// a 'label' property whose value is converted to a string and included as
|
||||
@ -1253,21 +1286,24 @@ ParseBreakdown(Census& census, HandleValue breakdownValue)
|
||||
|
||||
JSFlatString* flat = labelString->ensureFlat(cx);
|
||||
if (!flat)
|
||||
return false;
|
||||
return nullptr;
|
||||
|
||||
AutoStableStringChars chars(cx);
|
||||
if (!chars.initTwoByte(cx, flat))
|
||||
return false;
|
||||
return nullptr;
|
||||
|
||||
// Since flat strings are null-terminated, and AutoStableStringChars
|
||||
// null- terminates if it needs to make a copy, we know that
|
||||
// chars.twoByteChars() is null-terminated.
|
||||
labelUnique = DuplicateString(cx, chars.twoByteChars());
|
||||
if (!labelUnique)
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CountTypePtr simple(census.new_<SimpleCount>(census, labelUnique));
|
||||
CountTypePtr simple(census.new_<SimpleCount>(census,
|
||||
labelUnique,
|
||||
ToBoolean(countValue),
|
||||
ToBoolean(bytesValue)));
|
||||
return simple;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user