byteSize-of-bigint.js (4379B)
1 // |jit-test| skip-if: !getBuildConfiguration("moz-memory") 2 // Run this test only if we're using jemalloc. Other malloc implementations 3 // exhibit surprising behaviors. For example, 32-bit Fedora builds have 4 // non-deterministic allocation sizes. 5 6 // Check JS::ubi::Node::size results for BigInts. 7 8 // We actually hard-code specific sizes into this test, even though they're 9 // implementation details, because in practice there are only two architecture 10 // variants to consider (32-bit and 64-bit), and if these sizes change, that's 11 // something SpiderMonkey hackers really want to know; they're supposed to be 12 // stable. 13 14 const pointerByteSize = getBuildConfiguration("pointer-byte-size"); 15 assertEq(pointerByteSize === 4 || pointerByteSize === 8, true); 16 17 const m32 = pointerByteSize === 4; 18 19 // 32-bit: sizeof(CellWithLengthAndFlags) + 2 * sizeof(BigInt::Digit) = 8 + 2 * 4 = 16 20 // 64-bit: sizeof(CellWithLengthAndFlags) + sizeof(BigInt::Digit) = 8 + 8 = 16 21 const SIZE_OF_BIGINT = 16; 22 23 // sizeof(BigInt::Digit) 24 const SIZE_OF_DIGIT = pointerByteSize; 25 26 // sizeof(JS::Value) 27 const SIZE_OF_VALUE = 8; 28 29 // See Nursery::bigIntHeaderSize(). 30 const SIZE_OF_BIGINT_HEADER = 8; 31 32 const SIZE_OF_TENURED_BIGINT = SIZE_OF_BIGINT; 33 const SIZE_OF_NURSERY_BIGINT = SIZE_OF_BIGINT + SIZE_OF_BIGINT_HEADER; 34 35 function nurseryDigitSize(length) { 36 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=1607186> for why we currently 37 // overallocate on 32-bit. 38 if (m32) { 39 length += (length & 1); 40 } 41 return length * SIZE_OF_DIGIT; 42 } 43 44 function mallocDigitSize(length) { 45 // See <https://bugzilla.mozilla.org/show_bug.cgi?id=1607186> for why we currently 46 // overallocate on 32-bit. 47 if (m32) { 48 length += (length & 1); 49 } 50 51 // Malloc buffer sizes are always a power of two. 52 return 1 << Math.ceil(Math.log2(length * SIZE_OF_DIGIT)); 53 } 54 55 // Constant BigInts (tenured, inline digits). 56 assertEq(byteSize(10n), SIZE_OF_TENURED_BIGINT); 57 assertEq(byteSize(0xffff_ffff_ffff_ffffn), SIZE_OF_TENURED_BIGINT); 58 59 // Constant BigInt (tenured, heap digits). 60 assertEq(byteSize(0x1_0000_0000_0000_0000n), 61 SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 3 : 2)); 62 assertEq(byteSize(0x1_0000_0000_0000_0000_0000_0000n), 63 SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 4 : 2)); 64 assertEq(byteSize(0x1_0000_0000_0000_0000_0000_0000_0000_0000n), 65 SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 5 : 3)); 66 67 68 /////////////////////////////////////////////////////////////////////////////// 69 // Nursery BigInt tests below this point. // 70 /////////////////////////////////////////////////////////////////////////////// 71 72 // Hack to skip this test if BigInts are not allocated in the nursery. 73 { 74 const sample_nursery = BigInt(123456789); 75 76 const before = byteSize(sample_nursery); 77 gc(); 78 const after = byteSize(sample_nursery); 79 80 let nursery_disabled = before == after; 81 if (nursery_disabled) { 82 printErr("nursery BigInts appear to be disabled"); 83 quit(0); 84 } 85 } 86 87 // Convert an input BigInt, which is probably tenured because it's a literal in 88 // the source text, to a nursery-allocated BigInt with the same contents. 89 function copyBigInt(bi) { 90 var plusOne = bi + 1n; 91 return plusOne - 1n; 92 } 93 94 // Return the nursery byte size of |bi|. 95 function nByteSize(bi) { 96 // BigInts that appear in the source will always be tenured. 97 return byteSize(copyBigInt(bi)); 98 } 99 100 // BigInts (nursery, inline digits). 101 assertEq(nByteSize(10n), SIZE_OF_NURSERY_BIGINT); 102 assertEq(nByteSize(0xffff_ffff_ffff_ffffn), SIZE_OF_NURSERY_BIGINT); 103 104 // BigInt (nursery, nursery heap digits). 105 // 106 // This assumes small nursery buffer allocations always succeed. 107 assertEq(nByteSize(0x1_0000_0000_0000_0000n), 108 SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 3 : 2)); 109 assertEq(nByteSize(0x1_0000_0000_0000_0000_0000_0000n), 110 SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 4 : 2)); 111 assertEq(nByteSize(0x1_0000_0000_0000_0000_0000_0000_0000_0000n), 112 SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 5 : 3)); 113 114 // BigInt (nursery, malloc heap digits). 115 // 116 // |Nursery::MaxNurseryBufferSize| is 1024, so when 117 // |BigInt::digitLength * sizeof(BigInt::Digit)| exceeds 1024, the digits buffer 118 // should be malloc'ed. Pick a larger number to be future-proof. 119 assertEq(nByteSize(2n ** (64n * 1000n)), 120 SIZE_OF_NURSERY_BIGINT + mallocDigitSize(m32 ? 2002 : 1001));