From d8bbc7858622b6d9c278469aab701ca0b609cddf Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 15 May 2024 05:35:49 +0200 Subject: Merging upstream version 126.0. Signed-off-by: Daniel Baumann --- .../tests/heap-analysis/byteSize-of-string.js | 87 +++++++++++++++++----- 1 file changed, 70 insertions(+), 17 deletions(-) (limited to 'js/src/jit-test/tests/heap-analysis') diff --git a/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js b/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js index aaac0c4f1f..b4cfdffb04 100644 --- a/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js +++ b/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js @@ -12,6 +12,7 @@ // stable. gczeal(0); // Need to control when tenuring happens +gcparam('semispaceNurseryEnabled', 0); // Hack to skip this test if strings are not allocated in the nursery. { @@ -75,16 +76,20 @@ function tByteSize(str) { // JSExternalString - limited by MaxStringLength - E // JSThinInlineString 8 4 16 8 T // JSFatInlineString 24 12 24 12 F +// ThinInlineAtom 12 6 20 10 T +// FatInlineAtom 20 10 20 10 F // JSExtensibleString - limited by MaxStringLength - X // Notes: // - labels are suffixed with A for atoms and N for non-atoms -// - atoms are 8 bytes larger than non-atoms, to store the atom's hash code. +// - atoms store a 4 byte hash code, and some add to the size to adjust // - Nursery-allocated strings require a header that stores the zone. // Expected sizes based on type of string const m32 = (getBuildConfiguration("pointer-byte-size") == 4); -const TA = m32 ? 24 : 32; // ThinInlineString atom, includes a hash value +const TA = m32 ? 24 : 32; // ThinInlineAtom (includes a hash value) +const FA = m32 ? 32 : 32; // FatInlineAtom (includes a hash value) +const NA = m32 ? 24 : 32; // NormalAtom const TN = m32 ? 16 : 24; // ThinInlineString const FN = m32 ? 32 : 32; // FatInlineString const XN = m32 ? 16 : 24; // ExtensibleString, has additional storage buffer @@ -95,8 +100,8 @@ const EN = m32 ? 16 : 24; // ExternalString // A function that pads out a tenured size to the nursery size. We store a zone // pointer in the nursery just before the string (4 bytes on 32-bit, 8 bytes on // 64-bit), and the string struct itself must be 8-byte aligned (resulting in -// +4 bytes on 32-bit, +0 bytes on 64-bit). The end result? Nursery strings are -// 8 bytes larger. +// +4 bytes on 32-bit, +0 bytes on 64-bit). The end result is that nursery +// strings are 8 bytes larger. const Nursery = m32 ? s => s + 4 + 4 : s => s + 8 + 0; // Latin-1 @@ -130,6 +135,23 @@ assertEq(nByteSize("123456789.123456789.123456789.1"), s(Nursery( assertEq(nByteSize("123456789.123456789.123456789.12"), s(Nursery(XN)+32,Nursery(XN)+32)); assertEq(nByteSize("123456789.123456789.123456789.123"), s(Nursery(XN)+64,Nursery(XN)+64)); +function Atom(s) { return Object.keys({ [s]: true })[0]; } +assertEq(byteSize(Atom("1234567")), s(TA, TA)); +assertEq(byteSize(Atom("12345678")), s(TA, FA)); +assertEq(byteSize(Atom("123456789.12")), s(TA, FA)); +assertEq(byteSize(Atom("123456789.123")), s(FA, FA)); +assertEq(byteSize(Atom("123456789.12345")), s(FA, FA)); +assertEq(byteSize(Atom("123456789.123456")), s(FA, FA)); +assertEq(byteSize(Atom("123456789.1234567")), s(FA, FA)); +assertEq(byteSize(Atom("123456789.123456789.")), s(FA, FA)); +assertEq(byteSize(Atom("123456789.123456789.1")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.123")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.1234")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.12345")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.123456789.1")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.123456789.12")), s(NA+32, NA+32)); +assertEq(byteSize(Atom("123456789.123456789.123456789.123")), s(NA+48, NA+48)); + // Inline char16_t atoms. // "Impassionate gods have never seen the red that is the Tatsuta River." // - Ariwara no Narihira @@ -183,20 +205,43 @@ assertEq(byteSize(rope8), s(Nurser minorgc(); assertEq(byteSize(rope8), s(RN, RN)); var matches8 = rope8.match(/(de cuyo nombre no quiero acordarme)/); -assertEq(byteSize(rope8), s(XN + 65536, XN + 65536)); +assertEq(byteSize(rope8), s(XN + 64 * 1024, XN + 64 * 1024)); +var ext8 = rope8; // Stop calling it what it's not (though it'll change again soon.) // 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 +// Flattening that should turn the original rope into a dependent string, and // yield a new linear string, of the same size as the original. -rope8a = rope8 + fragment8; +var rope8a = ext8 + fragment8; assertEq(byteSize(rope8a), s(Nursery(RN), Nursery(RN))); rope8a.match(/x/, function() { assertEq(true, false); }); assertEq(byteSize(rope8a), s(Nursery(XN) + 65536, Nursery(XN) + 65536)); +assertEq(byteSize(ext8), s(DN, DN)); + +// Latin-1 dependent strings in the nursery. +assertEq(byteSize(ext8.substr(1000, 2000)), s(Nursery(DN), Nursery(DN))); +assertEq(byteSize(matches8[0]), s(Nursery(DN), Nursery(DN))); +assertEq(byteSize(matches8[1]), s(Nursery(DN), Nursery(DN))); + +// Tenure everything and do it again. +ext8 = copyString(ext8); +rope8a = ext8 + fragment8; +minorgc(); +assertEq(byteSize(rope8a), s(RN, RN)); +rope8a.match(/x/, function() { assertEq(true, false); }); +assertEq(byteSize(rope8a), s(XN + 65536, XN + 65536)); assertEq(byteSize(rope8), s(RN, RN)); +// Latin-1 tenured dependent strings. +function tenure(s) { + minorgc(); + return s; +} +assertEq(byteSize(tenure(rope8.substr(1000, 2000))), s(DN, DN)); +assertEq(byteSize(matches8[0]), s(DN, DN)); +assertEq(byteSize(matches8[1]), s(DN, DN)); // A char16_t rope. This changes size when flattened. // "From the Heliconian Muses let us begin to sing" @@ -207,13 +252,11 @@ for (var i = 0; i < 10; i++) // 1024 repetitions rope16 = rope16 + rope16; assertEq(byteSize(rope16), s(Nursery(RN), Nursery(RN))); let matches16 = rope16.match(/(Ἑλικωνιάδων ἀρχώμεθ᾽)/); -assertEq(byteSize(rope16), s(Nursery(RN) + 131072, Nursery(RN) + 131072)); +assertEq(byteSize(rope16), s(Nursery(XN) + 128 * 1024, Nursery(XN) + 128 * 1024)); +var ext16 = rope16; -// Latin-1 and char16_t dependent strings. -assertEq(byteSize(rope8.substr(1000, 2000)), s(Nursery(DN), Nursery(DN))); -assertEq(byteSize(rope16.substr(1000, 2000)), s(Nursery(DN), Nursery(DN))); -assertEq(byteSize(matches8[0]), s(Nursery(DN), Nursery(DN))); -assertEq(byteSize(matches8[1]), s(Nursery(DN), Nursery(DN))); +// char16_t dependent strings in the nursery. +assertEq(byteSize(ext16.substr(1000, 2000)), s(Nursery(DN), Nursery(DN))); assertEq(byteSize(matches16[0]), s(Nursery(DN), Nursery(DN))); assertEq(byteSize(matches16[1]), s(Nursery(DN), Nursery(DN))); @@ -221,13 +264,23 @@ assertEq(byteSize(matches16[1]), s(Nurser // // Appending another copy of the fragment should yield another rope. // -// Flatting that should turn the original rope into a dependent string, and +// Flattening 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; +rope16a = ext16 + fragment16; assertEq(byteSize(rope16a), s(Nursery(RN), Nursery(RN))); rope16a.match(/x/, function() { assertEq(true, false); }); -assertEq(byteSize(rope16a), s(Nursery(XN) + 131072, Nursery(XN) + 131072)); -assertEq(byteSize(rope16), s(Nursery(XN), Nursery(XN))); +assertEq(byteSize(rope16a), s(Nursery(XN) + 128 * 1024, Nursery(XN) + 128 * 1024)); +assertEq(byteSize(ext16), s(Nursery(DN), Nursery(DN))); + +// Tenure everything and try again. This time it should steal the extensible +// characters and convert the root into an extensible string using them. +ext16 = copyString(ext16); +rope16a = ext16 + fragment16; +minorgc(); +assertEq(byteSize(rope16a), s(RN, RN)); +rope16a.match(/x/, function() { assertEq(true, false); }); +assertEq(byteSize(rope16a), s(XN + 128 * 1024, XN + 128 * 1024)); +assertEq(byteSize(ext16), s(RN, RN)); // Test external strings. // -- cgit v1.2.3