From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/jit-test/tests/atomics/memcpy-fidelity.js | 181 +++++++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 js/src/jit-test/tests/atomics/memcpy-fidelity.js (limited to 'js/src/jit-test/tests/atomics/memcpy-fidelity.js') diff --git a/js/src/jit-test/tests/atomics/memcpy-fidelity.js b/js/src/jit-test/tests/atomics/memcpy-fidelity.js new file mode 100644 index 0000000000..81eb63fba2 --- /dev/null +++ b/js/src/jit-test/tests/atomics/memcpy-fidelity.js @@ -0,0 +1,181 @@ +// In order not to run afoul of C++ UB we have our own non-C++ definitions of +// operations (they are actually jitted) that can operate racily on shared +// memory, see jit/shared/AtomicOperations-shared-jit.cpp. +// +// Operations on fixed-width 1, 2, 4, and 8 byte data are adequately tested +// elsewhere. Here we specifically test our safe-when-racy replacements of +// memcpy and memmove. +// +// There are two primitives in the engine, memcpy_down and memcpy_up. These are +// equivalent except when data overlap, in which case memcpy_down handles +// overlapping copies that move from higher to lower addresses and memcpy_up +// handles ditto from lower to higher. memcpy uses memcpy_down always while +// memmove selects the one to use dynamically based on its arguments. + +// Basic memcpy algorithm to be tested: +// +// - if src and target have the same alignment +// - byte copy up to word alignment +// - block copy as much as possible +// - word copy as much as possible +// - byte copy any tail +// - else if on a platform that can deal with unaligned access +// (ie, x86, ARM64, and ARM if the proper flag is set) +// - block copy as much as possible +// - word copy as much as possible +// - byte copy any tail +// - else // on a platform that can't deal with unaligned access +// (ie ARM without the flag or x86 DEBUG builds with the +// JS_NO_UNALIGNED_MEMCPY env var) +// - block copy with byte copies +// - word copy with byte copies +// - byte copy any tail + +var target_buf = new SharedArrayBuffer(1024); +var src_buf = new SharedArrayBuffer(1024); + +/////////////////////////////////////////////////////////////////////////// +// +// Different src and target buffer, this is memcpy "move down". The same +// code is used in the engine for overlapping buffers when target addresses +// are lower than source addresses. + +fill(src_buf); + +// Basic 1K perfectly aligned copy, copies blocks only. +{ + let target = new Uint8Array(target_buf); + let src = new Uint8Array(src_buf); + clear(target_buf); + target.set(src); + check(target_buf, 0, 1024, 0); +} + +// Buffers are equally aligned but not on a word boundary and not ending on a +// word boundary either, so this will copy first some bytes, then some blocks, +// then some words, and then some bytes. +{ + let fill = 0x79; + clear(target_buf, fill); + let target = new Uint8Array(target_buf, 1, 1022); + let src = new Uint8Array(src_buf, 1, 1022); + target.set(src); + check_fill(target_buf, 0, 1, fill); + check(target_buf, 1, 1023, 1); + check_fill(target_buf, 1023, 1024, fill); +} + +// Buffers are unequally aligned, we'll copy bytes only on some platforms and +// unaligned blocks/words on others. +{ + clear(target_buf); + let target = new Uint8Array(target_buf, 0, 1023); + let src = new Uint8Array(src_buf, 1); + target.set(src); + check(target_buf, 0, 1023, 1); + check_zero(target_buf, 1023, 1024); +} + +/////////////////////////////////////////////////////////////////////////// +// +// Overlapping src and target buffer and the target addresses are always +// higher than the source addresses, this is memcpy "move up" + +// Buffers are equally aligned but not on a word boundary and not ending on a +// word boundary either, so this will copy first some bytes, then some blocks, +// then some words, and then some bytes. +{ + fill(target_buf); + let target = new Uint8Array(target_buf, 9, 999); + let src = new Uint8Array(target_buf, 1, 999); + target.set(src); + check(target_buf, 9, 1008, 1); + check(target_buf, 1008, 1024, 1008 & 255); +} + +// Buffers are unequally aligned, we'll copy bytes only on some platforms and +// unaligned blocks/words on others. +{ + fill(target_buf); + let target = new Uint8Array(target_buf, 2, 1022); + let src = new Uint8Array(target_buf, 1, 1022); + target.set(src); + check(target_buf, 2, 1024, 1); +} + +/////////////////////////////////////////////////////////////////////////// +// +// Copy 0 to 127 bytes from and to a variety of addresses to check that we +// handle limits properly in these edge cases. + +// Too slow in debug-noopt builds but we don't want to flag the test as slow, +// since that means it'll never be run. + +if (this.getBuildConfiguration && !getBuildConfiguration().debug) +{ + let t = new Uint8Array(target_buf); + for (let my_src_buf of [src_buf, target_buf]) { + for (let size=0; size < 127; size++) { + for (let src_offs=0; src_offs < 8; src_offs++) { + for (let target_offs=0; target_offs < 8; target_offs++) { + clear(target_buf, Math.random()*255); + let target = new Uint8Array(target_buf, target_offs, size); + + // Zero is boring + let bias = (Math.random() * 100 % 12) | 0; + + // Note src may overlap target partially + let src = new Uint8Array(my_src_buf, src_offs, size); + for ( let i=0; i < size; i++ ) + src[i] = i+bias; + + // We expect these values to be unchanged by the copy + let below = target_offs > 0 ? t[target_offs - 1] : 0; + let above = t[target_offs + size]; + + // Copy + target.set(src); + + // Verify + check(target_buf, target_offs, target_offs + size, bias); + if (target_offs > 0) + assertEq(t[target_offs-1], below); + assertEq(t[target_offs+size], above); + } + } + } + } +} + + +// Utilities + +function clear(buf, fill) { + let a = new Uint8Array(buf); + for ( let i=0; i < a.length; i++ ) + a[i] = fill; +} + +function fill(buf) { + let a = new Uint8Array(buf); + for ( let i=0; i < a.length; i++ ) + a[i] = i & 255 +} + +function check(buf, from, to, startingWith) { + let a = new Uint8Array(buf); + for ( let i=from; i < to; i++ ) { + assertEq(a[i], startingWith); + startingWith = (startingWith + 1) & 255; + } +} + +function check_zero(buf, from, to) { + check_fill(buf, from, to, 0); +} + +function check_fill(buf, from, to, fill) { + let a = new Uint8Array(buf); + for ( let i=from; i < to; i++ ) + assertEq(a[i], fill); +} -- cgit v1.2.3