// |jit-test| skip-if: !getBuildConfiguration("moz-memory") // 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. // Check JS::ubi::Node::size results for BigInts. // 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. const pointerByteSize = getBuildConfiguration("pointer-byte-size"); assertEq(pointerByteSize === 4 || pointerByteSize === 8, true); const m32 = pointerByteSize === 4; // 32-bit: sizeof(CellWithLengthAndFlags) + 2 * sizeof(BigInt::Digit) = 8 + 2 * 4 = 16 // 64-bit: sizeof(CellWithLengthAndFlags) + sizeof(BigInt::Digit) = 8 + 8 = 16 const SIZE_OF_BIGINT = 16; // sizeof(BigInt::Digit) const SIZE_OF_DIGIT = pointerByteSize; // sizeof(JS::Value) const SIZE_OF_VALUE = 8; // See Nursery::bigIntHeaderSize(). const SIZE_OF_BIGINT_HEADER = 8; const SIZE_OF_TENURED_BIGINT = SIZE_OF_BIGINT; const SIZE_OF_NURSERY_BIGINT = SIZE_OF_BIGINT + SIZE_OF_BIGINT_HEADER; function nurseryDigitSize(length) { // See for why we currently // overallocate on 32-bit. if (m32) { length += (length & 1); } return length * SIZE_OF_DIGIT; } function mallocDigitSize(length) { // See for why we currently // overallocate on 32-bit. if (m32) { length += (length & 1); } // Malloc buffer sizes are always a power of two. return 1 << Math.ceil(Math.log2(length * SIZE_OF_DIGIT)); } // Constant BigInts (tenured, inline digits). assertEq(byteSize(10n), SIZE_OF_TENURED_BIGINT); assertEq(byteSize(0xffff_ffff_ffff_ffffn), SIZE_OF_TENURED_BIGINT); // Constant BigInt (tenured, heap digits). assertEq(byteSize(0x1_0000_0000_0000_0000n), SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 3 : 2)); assertEq(byteSize(0x1_0000_0000_0000_0000_0000_0000n), SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 4 : 2)); assertEq(byteSize(0x1_0000_0000_0000_0000_0000_0000_0000_0000n), SIZE_OF_TENURED_BIGINT + mallocDigitSize(m32 ? 5 : 3)); /////////////////////////////////////////////////////////////////////////////// // Nursery BigInt tests below this point. // /////////////////////////////////////////////////////////////////////////////// // Hack to skip this test if BigInts are not allocated in the nursery. { const sample_nursery = BigInt(123456789); const before = byteSize(sample_nursery); gc(); const after = byteSize(sample_nursery); let nursery_disabled = before == after; if (nursery_disabled) { printErr("nursery BigInts appear to be disabled"); quit(0); } } // Convert an input BigInt, which is probably tenured because it's a literal in // the source text, to a nursery-allocated BigInt with the same contents. function copyBigInt(bi) { var plusOne = bi + 1n; return plusOne - 1n; } // Return the nursery byte size of |bi|. function nByteSize(bi) { // BigInts that appear in the source will always be tenured. return byteSize(copyBigInt(bi)); } // BigInts (nursery, inline digits). assertEq(nByteSize(10n), SIZE_OF_NURSERY_BIGINT); assertEq(nByteSize(0xffff_ffff_ffff_ffffn), SIZE_OF_NURSERY_BIGINT); // BigInt (nursery, nursery heap digits). // // This assumes small nursery buffer allocations always succeed. assertEq(nByteSize(0x1_0000_0000_0000_0000n), SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 3 : 2)); assertEq(nByteSize(0x1_0000_0000_0000_0000_0000_0000n), SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 4 : 2)); assertEq(nByteSize(0x1_0000_0000_0000_0000_0000_0000_0000_0000n), SIZE_OF_NURSERY_BIGINT + nurseryDigitSize(m32 ? 5 : 3)); // BigInt (nursery, malloc heap digits). // // |Nursery::MaxNurseryBufferSize| is 1024, so when // |BigInt::digitLength * sizeof(BigInt::Digit)| exceeds 1024, the digits buffer // should be malloc'ed. Pick a larger number to be future-proof. assertEq(nByteSize(2n ** (64n * 1000n)), SIZE_OF_NURSERY_BIGINT + mallocDigitSize(m32 ? 2002 : 1001));