summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
diff options
context:
space:
mode:
Diffstat (limited to 'js/src/jit-test/tests/heap-analysis/byteSize-of-string.js')
-rw-r--r--js/src/jit-test/tests/heap-analysis/byteSize-of-string.js133
1 files changed, 133 insertions, 0 deletions
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
new file mode 100644
index 000000000..251d30d86
--- /dev/null
+++ b/js/src/jit-test/tests/heap-analysis/byteSize-of-string.js
@@ -0,0 +1,133 @@
+// 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 -
+
+// Note that atoms are 8 bytes larger than non-atoms, to store the atom's hash code.
+
+// Latin-1
+assertEq(tByteSize(""), s(24, 32)); // T, T
+assertEq(tByteSize("1"), s(24, 32)); // T, T
+assertEq(tByteSize("1234567"), s(24, 32)); // T, T
+assertEq(tByteSize("12345678"), s(40, 32)); // F, T
+assertEq(tByteSize("123456789.12345"), s(40, 32)); // F, T
+assertEq(tByteSize("123456789.123456"), s(40, 40)); // F, F
+assertEq(tByteSize("123456789.123456789.123"), s(40, 40)); // F, F
+assertEq(tByteSize("123456789.123456789.1234"), s(56, 64)); // X, X
+assertEq(tByteSize("123456789.123456789.123456789.1"), s(56, 64)); // X, X
+assertEq(tByteSize("123456789.123456789.123456789.12"), s(72, 80)); // X, X
+
+// Inline char16_t atoms.
+// "Impassionate gods have never seen the red that is the Tatsuta River."
+// - Ariwara no Narihira
+assertEq(tByteSize("千"), s(24, 32)); // T, T
+assertEq(tByteSize("千早"), s(24, 32)); // T, T
+assertEq(tByteSize("千早ぶ"), s(24, 32)); // T, T
+assertEq(tByteSize("千早ぶる"), s(40, 32)); // F, T
+assertEq(tByteSize("千早ぶる神"), s(40, 32)); // F, T
+assertEq(tByteSize("千早ぶる神代"), s(40, 32)); // F, T
+assertEq(tByteSize("千早ぶる神代も"), s(40, 32)); // F, T
+assertEq(tByteSize("千早ぶる神代もき"), s(40, 40)); // F, F
+assertEq(tByteSize("千早ぶる神代もきかず龍"), s(40, 40)); // F, F
+assertEq(tByteSize("千早ぶる神代もきかず龍田"), s(56, 64)); // X, X
+assertEq(tByteSize("千早ぶる神代もきかず龍田川 か"), s(56, 64)); // X, X
+assertEq(tByteSize("千早ぶる神代もきかず龍田川 から"), s(72, 80)); // X, X
+assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水く"), s(72, 80)); // X, X
+assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水くく"), s(88, 96)); // X, X
+assertEq(tByteSize("千早ぶる神代もきかず龍田川 からくれなゐに水くくるとは"), s(88, 96)); // 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));