mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1063257: Implement JS::ubi::Node::size for JSString. r=sfink
This commit is contained in:
parent
325a4f495b
commit
8f394b568c
@ -567,7 +567,6 @@ class TracerConcreteWithCompartment : public TracerConcrete<Referent> {
|
||||
|
||||
// Define specializations for some commonly-used public JSAPI types.
|
||||
// These can use the generic templates above.
|
||||
template<> struct Concrete<JSString> : TracerConcrete<JSString> { };
|
||||
template<> struct Concrete<JS::Symbol> : TracerConcrete<JS::Symbol> { };
|
||||
template<> struct Concrete<JSScript> : TracerConcreteWithCompartment<JSScript> { };
|
||||
|
||||
@ -586,6 +585,17 @@ class Concrete<JSObject> : public TracerConcreteWithCompartment<JSObject> {
|
||||
}
|
||||
};
|
||||
|
||||
// For JSString, we extend the generic template with a 'size' implementation.
|
||||
template<> struct Concrete<JSString> : TracerConcrete<JSString> {
|
||||
size_t size(mozilla::MallocSizeOf mallocSizeOf) const override;
|
||||
|
||||
protected:
|
||||
explicit Concrete(JSString *ptr) : TracerConcrete<JSString>(ptr) { }
|
||||
|
||||
public:
|
||||
static void construct(void *storage, JSString *ptr) { new (storage) Concrete(ptr); }
|
||||
};
|
||||
|
||||
// The ubi::Node null pointer. Any attempt to operate on a null ubi::Node asserts.
|
||||
template<>
|
||||
class Concrete<void> : public Base {
|
||||
|
@ -26,7 +26,7 @@ function tenure(obj) {
|
||||
// being tenured. (We use 'survives a GC' as an approximation for 'tenuring'.)
|
||||
function tByteSize(obj) {
|
||||
var size = byteSize(obj);
|
||||
gc();
|
||||
minorgc();
|
||||
if (size != byteSize(obj))
|
||||
return 0;
|
||||
return size;
|
||||
|
131
js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
Normal file
131
js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
Normal file
@ -0,0 +1,131 @@
|
||||
// Check JS::ubi::Node::size results for strings.
|
||||
|
||||
// We actually hard-code specific sizes into this test, even though they're
|
||||
// implementation details, because in practice there are only two architecture
|
||||
// variants to consider (32-bit and 64-bit), and if these sizes change, that's
|
||||
// something SpiderMonkey hackers really want to know; they're supposed to be
|
||||
// stable.
|
||||
|
||||
// Run this test only if we're using jemalloc. Other malloc implementations
|
||||
// exhibit surprising behaviors. For example, 32-bit Fedora builds have
|
||||
// non-deterministic allocation sizes.
|
||||
var config = getBuildConfiguration();
|
||||
if (!config['moz-memory'])
|
||||
quit(0);
|
||||
|
||||
if (config['pointer-byte-size'] == 4)
|
||||
var s = (s32, s64) => s32
|
||||
else
|
||||
var s = (s32, s64) => s64
|
||||
|
||||
// Return the byte size of |obj|, ensuring that the size is not affected by
|
||||
// being tenured. (We use 'survives a GC' as an approximation for 'tenuring'.)
|
||||
function tByteSize(obj) {
|
||||
var nurserySize = byteSize(obj);
|
||||
minorgc();
|
||||
var tenuredSize = byteSize(obj);
|
||||
if (nurserySize != tenuredSize) {
|
||||
print("nursery size: " + nurserySize + " tenured size: " + tenuredSize);
|
||||
return -1; // make the stack trace point at the real test
|
||||
}
|
||||
|
||||
return tenuredSize;
|
||||
}
|
||||
|
||||
// There are four representations of flat strings, with the following capacities
|
||||
// (excluding a terminating null character):
|
||||
//
|
||||
// 32-bit 64-bit test
|
||||
// representation Latin-1 char16_t Latin-1 char16_t label
|
||||
// ========================================================================
|
||||
// JSExternalString (cannot be tested in shell) -
|
||||
// JSThinInlineString 7 3 15 7 T
|
||||
// JSFatInlineString 23 11 23 11 F
|
||||
// JSExtensibleString - limited by available memory - X
|
||||
// JSUndependedString - same as JSExtensibleString -
|
||||
|
||||
// Latin-1
|
||||
assertEq(tByteSize(""), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("1"), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("1234567"), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("12345678"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("123456789.12345"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("123456789.123456"), s(32, 32)); // F, F
|
||||
assertEq(tByteSize("123456789.123456789.123"), s(32, 32)); // F, F
|
||||
assertEq(tByteSize("123456789.123456789.1234"), s(48, 56)); // X, X
|
||||
assertEq(tByteSize("123456789.123456789.123456789.1"), s(48, 56)); // X, X
|
||||
assertEq(tByteSize("123456789.123456789.123456789.12"), s(64, 72)); // X, X
|
||||
|
||||
// Inline char16_t atoms.
|
||||
// "Impassionate gods have never seen the red that is the Tatsuta River."
|
||||
// - Ariwara no Narihira
|
||||
assertEq(tByteSize("千"), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("千早"), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("千早ぶ"), s(16, 24)); // T, T
|
||||
assertEq(tByteSize("千早ぶる"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("千早ぶる神"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("千早ぶる神代"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("千早ぶる神代も"), s(32, 24)); // F, T
|
||||
assertEq(tByteSize("千早ぶる神代もき"), s(32, 32)); // F, F
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍"), s(32, 32)); // F, F
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田"), s(48, 56)); // X, X
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田川 か"), s(48, 56)); // X, X
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田川 から"), s(64, 72)); // X, X
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水く"), s(64, 72)); // X, X
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水くく"), s(80, 88)); // X, X
|
||||
assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水くくるとは"), s(80, 88)); // X, X
|
||||
|
||||
// A Latin-1 rope. This changes size when flattened.
|
||||
// "In a village of La Mancha, the name of which I have no desire to call to mind"
|
||||
// - Miguel de Cervantes, Don Quixote
|
||||
var fragment8 = "En un lugar de la Mancha, de cuyo nombre no quiero acordarme"; // 60 characters
|
||||
var rope8 = fragment8;
|
||||
for (var i = 0; i < 10; i++) // 1024 repetitions
|
||||
rope8 = rope8 + rope8;
|
||||
assertEq(tByteSize(rope8), s(16, 24));
|
||||
var matches8 = rope8.match(/(de cuyo nombre no quiero acordarme)/);
|
||||
assertEq(tByteSize(rope8), s(16 + 65536, 24 + 65536));
|
||||
|
||||
// Test extensible strings.
|
||||
//
|
||||
// Appending another copy of the fragment should yield another rope.
|
||||
//
|
||||
// Flatting that should turn the original rope into a dependent string, and
|
||||
// yield a new linear string, of the some size as the original.
|
||||
rope8a = rope8 + fragment8;
|
||||
assertEq(tByteSize(rope8a), s(16, 24));
|
||||
rope8a.match(/x/, function() { assertEq(true, false); });
|
||||
assertEq(tByteSize(rope8a), s(16 + 65536, 24 + 65536));
|
||||
assertEq(tByteSize(rope8), s(16, 24));
|
||||
|
||||
|
||||
// A char16_t rope. This changes size when flattened.
|
||||
// "From the Heliconian Muses let us begin to sing"
|
||||
// --- Hesiod, Theogony
|
||||
var fragment16 = "μουσάων Ἑλικωνιάδων ἀρχώμεθ᾽ ἀείδειν";
|
||||
var rope16 = fragment16;
|
||||
for (var i = 0; i < 10; i++) // 1024 repetitions
|
||||
rope16 = rope16 + rope16;
|
||||
assertEq(tByteSize(rope16), s(16, 24));
|
||||
let matches16 = rope16.match(/(Ἑλικωνιάδων ἀρχώμεθ᾽)/);
|
||||
assertEq(tByteSize(rope16), s(16 + 131072, 24 + 131072));
|
||||
|
||||
// Latin-1 and char16_t dependent strings.
|
||||
assertEq(tByteSize(rope8.substr(1000, 2000)), s(16, 24));
|
||||
assertEq(tByteSize(rope16.substr(1000, 2000)), s(16, 24));
|
||||
assertEq(tByteSize(matches8[0]), s(16, 24));
|
||||
assertEq(tByteSize(matches8[1]), s(16, 24));
|
||||
assertEq(tByteSize(matches16[0]), s(16, 24));
|
||||
assertEq(tByteSize(matches16[1]), s(16, 24));
|
||||
|
||||
// Test extensible strings.
|
||||
//
|
||||
// Appending another copy of the fragment should yield another rope.
|
||||
//
|
||||
// Flatting that should turn the original rope into a dependent string, and
|
||||
// yield a new linear string, of the some size as the original.
|
||||
rope16a = rope16 + fragment16;
|
||||
assertEq(tByteSize(rope16a), s(16, 24));
|
||||
rope16a.match(/x/, function() { assertEq(true, false); });
|
||||
assertEq(tByteSize(rope16a), s(16 + 131072, 24 + 131072));
|
||||
assertEq(tByteSize(rope16), s(16, 24));
|
@ -13,6 +13,7 @@
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#include "gc/Marking.h"
|
||||
#include "js/UbiNode.h"
|
||||
|
||||
#include "jscntxtinlines.h"
|
||||
#include "jscompartmentinlines.h"
|
||||
@ -66,6 +67,23 @@ JSString::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
: mallocSizeOf(flat.rawTwoByteChars());
|
||||
}
|
||||
|
||||
size_t
|
||||
JS::ubi::Concrete<JSString>::size(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
JSString &str = get();
|
||||
size_t size = str.isFatInline() ? sizeof(JSFatInlineString) : sizeof(JSString);
|
||||
|
||||
// We can't use mallocSizeof on things in the nursery. At the moment,
|
||||
// strings are never in the nursery, but that may change.
|
||||
MOZ_ASSERT(!IsInsideNursery(&str));
|
||||
size += str.sizeOfExcludingThis(mallocSizeOf);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
template<> const char16_t JS::ubi::TracerConcrete<JSString>::concreteTypeName[] =
|
||||
MOZ_UTF16("JSString");
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
template <typename CharT>
|
||||
|
@ -228,8 +228,6 @@ Concrete<JSObject>::jsObjectClassName() const
|
||||
return Concrete::get().getClass()->name;
|
||||
}
|
||||
|
||||
template<> const char16_t TracerConcrete<JSString>::concreteTypeName[] =
|
||||
MOZ_UTF16("JSString");
|
||||
template<> const char16_t TracerConcrete<JS::Symbol>::concreteTypeName[] =
|
||||
MOZ_UTF16("JS::Symbol");
|
||||
template<> const char16_t TracerConcrete<JSScript>::concreteTypeName[] =
|
||||
|
Loading…
Reference in New Issue
Block a user