Bug 1053932: Don't let Debugger.Memory.prototype.takeCensus's result be influenced by the hash table's ordering (ByUbinodeType version). r=terrence

This commit is contained in:
Jim Blandy 2014-08-19 14:21:34 -07:00
parent cfc6e05991
commit 5280bfadfd

View File

@ -500,7 +500,7 @@ class ByObjectClass {
entries.infallibleAppend(&r.front());
qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries);
// Now build the result by iterating over the vector, not the hash table.
// Now build the result by iterating over the sorted vector.
RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
if (!obj)
return false;
@ -551,6 +551,7 @@ class ByUbinodeType {
// pointer, not just any string whose contents are correct, we can use their
// addresses as hash table keys.
typedef HashMap<const jschar *, EachType, DefaultHasher<const jschar *>, SystemAllocPolicy> Table;
typedef typename Table::Entry Entry;
Table table;
public:
@ -580,27 +581,52 @@ class ByUbinodeType {
size_t total() const { return total_; }
static int compareEntries(const void *lhsVoid, const void *rhsVoid) {
size_t lhs = (*static_cast<const Entry * const *>(lhsVoid))->value().total();
size_t rhs = (*static_cast<const Entry * const *>(rhsVoid))->value().total();
// qsort sorts in "ascending" order, so we should describe entries with
// smaller counts as being "greater than" entries with larger counts. We
// don't want to just subtract the counts, as they're unsigned.
if (lhs < rhs)
return 1;
if (lhs > rhs)
return -1;
return 0;
}
bool report(Census &census, MutableHandleValue report) {
JSContext *cx = census.cx;
// Build a vector of pointers to entries; sort by total; and then use
// that to build the result object. This makes the ordering of entries
// more interesting, and a little less non-deterministic.
mozilla::Vector<Entry *> entries;
if (!entries.reserve(table.count()))
return false;
for (typename Table::Range r = table.all(); !r.empty(); r.popFront())
entries.infallibleAppend(&r.front());
qsort(entries.begin(), entries.length(), sizeof(*entries.begin()), compareEntries);
// Now build the result by iterating over the sorted vector.
RootedObject obj(cx, NewBuiltinClassInstance(cx, &JSObject::class_));
if (!obj)
return false;
for (typename Table::Range r = table.all(); !r.empty(); r.popFront()) {
EachType &entry = r.front().value();
RootedValue entryReport(cx);
if (!entry.report(census, &entryReport))
for (Entry **entryPtr = entries.begin(); entryPtr < entries.end(); entryPtr++) {
Entry &entry = **entryPtr;
EachType &assorter = entry.value();
RootedValue assorterReport(cx);
if (!assorter.report(census, &assorterReport))
return false;
const jschar *name = r.front().key();
const jschar *name = entry.key();
MOZ_ASSERT(name);
JSAtom *atom = AtomizeChars(cx, name, js_strlen(name));
if (!atom)
return false;
RootedId entryId(cx, AtomToId(atom));
if (!JSObject::defineGeneric(cx, obj, entryId, entryReport))
if (!JSObject::defineGeneric(cx, obj, entryId, assorterReport))
return false;
}