From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- js/src/tests/non262/extensions/typedarray.js | 657 +++++++++++++++++++++++++++ 1 file changed, 657 insertions(+) create mode 100644 js/src/tests/non262/extensions/typedarray.js (limited to 'js/src/tests/non262/extensions/typedarray.js') diff --git a/js/src/tests/non262/extensions/typedarray.js b/js/src/tests/non262/extensions/typedarray.js new file mode 100644 index 0000000000..02aaf7956e --- /dev/null +++ b/js/src/tests/non262/extensions/typedarray.js @@ -0,0 +1,657 @@ +// |reftest| skip-if(!xulRuntime.shell) +/* -*- Mode: js2; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/licenses/publicdomain/ + * Contributor: + * Vladimir Vukicevic + */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 532774; +var summary = 'js typed arrays (webgl arrays)'; +var actual = ''; +var expect = ''; + +//----------------------------------------------------------------------------- +if (typeof gczeal !== 'undefined') + gczeal(0) + +if (typeof numberToDouble !== 'function') { + var numberToDouble = SpecialPowers.Cu.getJSTestingFunctions().numberToDouble; +} + +test(); +//----------------------------------------------------------------------------- + +function test() +{ + printBugNumber(BUGNUMBER); + printStatus(summary); + + var TestPassCount = 0; + var TestFailCount = 0; + var TestTodoCount = 0; + + var TODO = 1; + + function check(fun, msg, todo) { + var thrown = null; + var success = false; + try { + success = fun(); + } catch (x) { + thrown = x; + } + + if (thrown) + success = false; + + if (todo) { + TestTodoCount++; + + if (success) { + var ex = new Error; + print ("=== TODO but PASSED? ==="); + print (ex.stack); + print ("========================"); + } + + return; + } + + if (success) { + TestPassCount++; + } else { + TestFailCount++; + + var ex = new Error; + print ("=== FAILED ==="); + if (msg) + print (msg); + print (ex.stack); + if (thrown) { + print (" threw exception:"); + print (thrown); + } + print ("=============="); + } + } + + function checkThrows(fun, type, todo) { + var thrown = false; + try { + fun(); + } catch (x) { + thrown = x; + } + + if (typeof(type) !== 'undefined') + if (thrown) { + check(() => thrown instanceof type, + "expected " + type.name + " but saw " + thrown, + todo); + } else { + check(() => thrown, "expected " + type.name + " but no exception thrown", todo); + } + else + check(() => thrown, undefined, todo); + } + + function checkThrowsTODO(fun, type) { + checkThrows(fun, type, true); + } + + function testBufferManagement() { + // Single buffer + var buffer = new ArrayBuffer(128); + buffer = null; + gc(); + + // Buffer with single view, kill the view first + buffer = new ArrayBuffer(128); + var v1 = new Uint8Array(buffer); + gc(); + v1 = null; + gc(); + buffer = null; + gc(); + + // Buffer with single view, kill the buffer first + buffer = new ArrayBuffer(128); + v1 = new Uint8Array(buffer); + gc(); + buffer = null; + gc(); + v1 = null; + gc(); + + // Buffer with multiple views, kill first view first + buffer = new ArrayBuffer(128); + v1 = new Uint8Array(buffer); + v2 = new Uint8Array(buffer); + gc(); + v1 = null; + gc(); + v2 = null; + gc(); + + // Buffer with multiple views, kill second view first + buffer = new ArrayBuffer(128); + v1 = new Uint8Array(buffer); + v2 = new Uint8Array(buffer); + gc(); + v2 = null; + gc(); + v1 = null; + gc(); + + // Buffer with multiple views, kill all possible subsets of views + buffer = new ArrayBuffer(128); + for (let order = 0; order < 16; order++) { + var views = [ new Uint8Array(buffer), + new Uint8Array(buffer), + new Uint8Array(buffer), + new Uint8Array(buffer) ]; + gc(); + + // Kill views according to the bits set in 'order' + for (let i = 0; i < 4; i++) { + if (order & (1 << i)) + views[i] = null; + } + + gc(); + + views = null; + gc(); + } + + // Similar: multiple views, kill them one at a time in every possible order + buffer = new ArrayBuffer(128); + for (let order = 0; order < 4*3*2*1; order++) { + var views = [ new Uint8Array(buffer), + new Uint8Array(buffer), + new Uint8Array(buffer), + new Uint8Array(buffer) ]; + gc(); + + var sequence = [ 0, 1, 2, 3 ]; + let groupsize = 4*3*2*1; + let o = order; + for (let i = 4; i > 0; i--) { + groupsize = groupsize / i; + let which = Math.floor(o/groupsize); + [ sequence[i-1], sequence[which] ] = [ sequence[which], sequence[i-1] ]; + o = o % groupsize; + } + + for (let i = 0; i < 4; i++) { + views[i] = null; + gc(); + } + } + + // Multiple buffers with multiple views + var views = []; + for (let numViews of [ 1, 2, 0, 3, 2, 1 ]) { + buffer = new ArrayBuffer(128); + for (let viewNum = 0; viewNum < numViews; viewNum++) { + views.push(new Int8Array(buffer)); + } + } + + if (typeof setMarkStackLimit === 'function') { + setMarkStackLimit(200); + } + var forceOverflow = [ buffer ]; + for (let i = 0; i < 1000; i++) { + forceOverflow = [ forceOverflow ]; + } + gc(); + buffer = null; + views = null; + gcslice(3); gcslice(3); gcslice(3); gcslice(3); gcslice(3); gcslice(3); gc(); + } + + var buf, buf2; + + buf = new ArrayBuffer(100); + check(() => buf); + check(() => buf.byteLength == 100); + + buf.byteLength = 50; + check(() => buf.byteLength == 100); + + var zerobuf = new ArrayBuffer(0); + check(() => zerobuf); + check(() => zerobuf.byteLength == 0); + + check(() => (new Int32Array(zerobuf)).length == 0); + checkThrows(() => new Int32Array(zerobuf, 1)); + + var zerobuf2 = new ArrayBuffer(); + check(() => zerobuf2.byteLength == 0); + + checkThrows(() => new ArrayBuffer(-100), RangeError); + // this is using js_ValueToECMAUInt32, which is giving 0 for "abc" + checkThrowsTODO(() => new ArrayBuffer("abc"), TypeError); + + var zeroarray = new Int32Array(0); + check(() => zeroarray.length == 0); + check(() => zeroarray.byteLength == 0); + check(() => zeroarray.buffer); + check(() => zeroarray.buffer.byteLength == 0); + + var zeroarray2 = new Int32Array(); + check(() => zeroarray2.length == 0); + check(() => zeroarray2.byteLength == 0); + check(() => zeroarray2.buffer); + check(() => zeroarray2.buffer.byteLength == 0); + + var a = new Int32Array(20); + check(() => a); + check(() => a.length == 20); + check(() => a.byteLength == 80); + check(() => a.byteOffset == 0); + check(() => a.buffer); + check(() => a.buffer.byteLength == 80); + + var b = new Uint8Array(a.buffer, 4, 4); + check(() => b); + check(() => b.length == 4); + check(() => b.byteLength == 4); + check(() => a.buffer == b.buffer); + + b[0] = 0xaa; + b[1] = 0xbb; + b[2] = 0xcc; + b[3] = 0xdd; + + check(() => a[0] == 0); + check(() => a[1] != 0); + check(() => a[2] == 0); + + buf = new ArrayBuffer(4); + check(() => (new Int8Array(buf)).length == 4); + check(() => (new Uint8Array(buf)).length == 4); + check(() => (new Int16Array(buf)).length == 2); + check(() => (new Uint16Array(buf)).length == 2); + check(() => (new Int32Array(buf)).length == 1); + check(() => (new Uint32Array(buf)).length == 1); + check(() => (new Float32Array(buf)).length == 1); + checkThrows(() => (new Float64Array(buf))); + buf2 = new ArrayBuffer(8); + check(() => (new Float64Array(buf2)).length == 1); + + buf = new ArrayBuffer(5); + check(() => buf); + check(() => buf.byteLength == 5); + + check(() => new Int32Array(buf, 0, 1)); + checkThrows(() => new Int32Array(buf, 0)); + check(() => new Int8Array(buf, 0)); + + check(() => (new Int8Array(buf, 3)).byteLength == 2); + checkThrows(() => new Int8Array(buf, 500)); + checkThrows(() => new Int8Array(buf, 0, 50)); + checkThrows(() => new Float32Array(buf, 500)); + checkThrows(() => new Float32Array(buf, 0, 50)); + + var sl = a.subarray(5,10); + check(() => sl.length == 5); + check(() => sl.buffer == a.buffer); + check(() => sl.byteLength == 20); + check(() => sl.byteOffset == 20); + + check(() => a.subarray(5,5).length == 0); + check(() => a.subarray(-5).length == 5); + check(() => a.subarray(-100).length == 20); + check(() => a.subarray(0, 2).length == 2); + check(() => a.subarray().length == a.length); + check(() => a.subarray(-7,-5).length == 2); + check(() => a.subarray(-5,-7).length == 0); + check(() => a.subarray(15).length == 5); + + a = new Uint8Array([0xaa, 0xbb, 0xcc]); + check(() => a.length == 3); + check(() => a.byteLength == 3); + check(() => a[1] == 0xbb); + + // not sure if this is supposed to throw or to treat "foo"" as 0. + checkThrowsTODO(() => new Int32Array([0xaa, "foo", 0xbb]), Error); + + checkThrows(() => new Int32Array(-100)); + + a = new Uint8Array(3); + // XXX these are ignored now and return undefined + //checkThrows(() => a[5000] = 0, RangeError); + //checkThrows(() => a["hello"] = 0, TypeError); + //checkThrows(() => a[-10] = 0, RangeError); + check(() => (a[0] = "10") && (a[0] == 10)); + + // check Uint8ClampedArray, which is an extension to this extension + a = new Uint8ClampedArray(4); + a[0] = 128; + a[1] = 512; + a[2] = -123.723; + a[3] = "foopy"; + + check(() => a[0] == 128); + check(() => a[1] == 255); + check(() => a[2] == 0); + check(() => a[3] == 0); + + // check handling of holes and non-numeric values + var x = Array(5); + x[0] = "hello"; + x[1] = { }; + //x[2] is a hole + x[3] = undefined; + x[4] = true; + + a = new Uint8Array(x); + check(() => a[0] == 0); + check(() => a[1] == 0); + check(() => a[2] == 0); + check(() => a[3] == 0); + check(() => a[4] == 1); + + a = new Float32Array(x); + check(() => !(a[0] == a[0])); + check(() => !(a[1] == a[1])); + check(() => !(a[2] == a[2])); + check(() => !(a[3] == a[3])); + check(() => a[4] == 1); + + // test set() + var empty = new Int32Array(0); + a = new Int32Array(9); + + empty.set([]); + empty.set([], 0); + empty.set(empty); + + checkThrows(() => empty.set([1])); + checkThrows(() => empty.set([1], 0)); + checkThrows(() => empty.set([1], 1)); + + a.set([]); + a.set([], 3); + a.set([], 9); + a.set(a); + + a.set(empty); + a.set(empty, 3); + a.set(empty, 9); + a.set(Array.prototype); + checkThrows(() => a.set(empty, 100)); + + checkThrows(() => a.set([1,2,3,4,5,6,7,8,9,10])); + checkThrows(() => a.set([1,2,3,4,5,6,7,8,9,10], 0)); + checkThrows(() => a.set([1,2,3,4,5,6,7,8,9,10], 0x7fffffff)); + checkThrows(() => a.set([1,2,3,4,5,6,7,8,9,10], 0xffffffff)); + checkThrows(() => a.set([1,2,3,4,5,6], 6)); + + checkThrows(() => a.set(new Array(0x7fffffff))); + checkThrows(() => a.set([1,2,3], 2147483647)); + + a.set(ArrayBuffer.prototype); + checkThrows(() => a.set(Int16Array.prototype), TypeError); + checkThrows(() => a.set(Int32Array.prototype), TypeError); + + a.set([1,2,3]); + a.set([4,5,6], 3); + check(() => + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 4 && a[4] == 5 && a[5] == 6 && + a[6] == 0 && a[7] == 0 && a[8] == 0); + + b = new Float32Array([7,8,9]); + a.set(b, 0); + a.set(b, 3); + check(() => + a[0] == 7 && a[1] == 8 && a[2] == 9 && + a[3] == 7 && a[4] == 8 && a[5] == 9 && + a[6] == 0 && a[7] == 0 && a[8] == 0); + a.set(a.subarray(0,3), 6); + check(() => + a[0] == 7 && a[1] == 8 && a[2] == 9 && + a[3] == 7 && a[4] == 8 && a[5] == 9 && + a[6] == 7 && a[7] == 8 && a[8] == 9); + + a.set([1,2,3,4,5,6,7,8,9]); + a.set(a.subarray(0,6), 3); + check(() => + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 1 && a[4] == 2 && a[5] == 3 && + a[6] == 4 && a[7] == 5 && a[8] == 6); + + a.set(a.subarray(3,9), 0); + check(() => + a[0] == 1 && a[1] == 2 && a[2] == 3 && + a[3] == 4 && a[4] == 5 && a[5] == 6 && + a[6] == 4 && a[7] == 5 && a[8] == 6); + + // verify that subarray() returns a new view that + // references the same buffer + a.subarray(0,3).set(a.subarray(3,6), 0); + check(() => + a[0] == 4 && a[1] == 5 && a[2] == 6 && + a[3] == 4 && a[4] == 5 && a[5] == 6 && + a[6] == 4 && a[7] == 5 && a[8] == 6); + + a = new ArrayBuffer(0x10); + checkThrows(() => new Uint32Array(buffer, 4, 0x3FFFFFFF)); + + check(() => new Float32Array(null).length === 0); + + a = new Uint8Array(0x100); + b = Uint32Array.prototype.subarray.apply(a, [0, 0x100]); + check(() => Object.prototype.toString.call(b) === "[object Uint8Array]"); + check(() => b.buffer === a.buffer); + check(() => b.length === a.length); + check(() => b.byteLength === a.byteLength); + check(() => b.byteOffset === a.byteOffset); + check(() => b.BYTES_PER_ELEMENT === a.BYTES_PER_ELEMENT); + + // webidl section 4.4.6, getter bullet point 2.2: prototypes are not + // platform objects, and calling the getter of any attribute defined on the + // interface should throw a TypeError according to + checkThrows(() => ArrayBuffer.prototype.byteLength, TypeError); + checkThrows(() => Int32Array.prototype.length, TypeError); + checkThrows(() => Int32Array.prototype.byteLength, TypeError); + checkThrows(() => Int32Array.prototype.byteOffset, TypeError); + checkThrows(() => Float64Array.prototype.length, TypeError); + checkThrows(() => Float64Array.prototype.byteLength, TypeError); + checkThrows(() => Float64Array.prototype.byteOffset, TypeError); + + // webidl 4.4.6: a readonly attribute's setter is undefined. From + // observation, that seems to mean it silently does nothing, and returns + // the value that you tried to set it to. + check(() => Int32Array.prototype.length = true); + check(() => Float64Array.prototype.length = true); + check(() => Int32Array.prototype.byteLength = true); + check(() => Float64Array.prototype.byteLength = true); + check(() => Int32Array.prototype.byteOffset = true); + check(() => Float64Array.prototype.byteOffset = true); + + // ArrayBuffer, Int32Array and Float64Array are native functions and have a + // .length, so none of these should throw: + check(() => (new Int32Array(ArrayBuffer)).length >= 0); + check(() => (new Int32Array(Int32Array)).length >= 0); + check(() => (new Int32Array(Float64Array)).length >= 0); + + // webidl 4.4.6, under getters: "The value of the Function object’s + // 'length' property is the Number value 0" + // + // Except this fails in getOwnPropertyDescriptor, I think because + // Int32Array.prototype does not provide a lookup hook, and the fallback + // case ends up calling the getter. Which seems odd to me, but much of this + // stuff baffles me. It does seem strange that there's no way to do + // getOwnPropertyDescriptor on any of these attributes. + // + //check(Object.getOwnPropertyDescriptor(Int32Array.prototype, 'byteOffset')['get'].length == 0); + + check(() => Int32Array.BYTES_PER_ELEMENT == 4); + check(() => (new Int32Array(4)).BYTES_PER_ELEMENT == 4); + check(() => (new Int32Array()).BYTES_PER_ELEMENT == 4); + check(() => (new Int32Array(0)).BYTES_PER_ELEMENT == 4); + check(() => Int16Array.BYTES_PER_ELEMENT == Uint16Array.BYTES_PER_ELEMENT); + + // test various types of args; numberToDouble(2) is used to ensure that the + // function gets a double, and not a demoted int + check(() => (new Float32Array(numberToDouble(2))).length == 2); + check(() => (new Float32Array({ length: 10 })).length == 10); + check(() => (new Float32Array({})).length == 0); + check(() => new Float32Array("3").length === 3); + check(() => new Float32Array(null).length === 0); + check(() => new Float32Array(undefined).length === 0); + + // check that NaN conversions happen correctly with array conversions + check(() => (new Int32Array([NaN])[0]) == 0); + check(() => { var q = new Float32Array([NaN])[0]; return q != q; }); + + // check that setting and reading arbitrary properties works + // this is not something that will be done in real world + // situations, but it should work when done just like in + // regular objects + buf = new ArrayBuffer(128); + a = new Uint32Array(buf, 0, 4); + check(() => a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0); + buf.a = 42; + buf.b = "abcdefgh"; + buf.c = {a:'literal'}; + check(() => a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0); + + check(() => buf.a == 42); + delete buf.a; + check(() => !buf.a); + + // check edge cases for small arrays + // 16 reserved slots + a = new Uint8Array(120); + check(() => a.byteLength == 120); + check(() => a.length == 120); + for (var i = 0; i < a.length; i++) + check(() => a[i] == 0) + + a = new Uint8Array(121); + check(() => a.byteLength == 121); + check(() => a.length == 121); + for (var i = 0; i < a.length; i++) + check(() => a[i] == 0) + + // check that TM generated byte offset is right (requires run with -j) + a = new Uint8Array(100); + a[99] = 5; + b = new Uint8Array(a.buffer, 9); // force a offset + // use a loop to invoke the TM + for (var i = 0; i < b.length; i++) + check(() => b[90] == 5) + + // Protos and proxies, oh my! + var alien = newGlobal({newCompartment: true}); + + var alien_view = alien.eval('view = new Uint8Array(7)'); + var alien_buffer = alien.eval('buffer = view.buffer'); + + // when creating a view of a buffer in a different compartment, the view + // itself should be created in the other compartment and wrapped for use in + // this compartment. (There should never be a compartment boundary between + // an ArrayBufferView and its ArrayBuffer.) + var view = new Int8Array(alien_buffer); + + // First make sure they're looking at the same data + alien_view[3] = 77; + check(() => view[3] == 77); + + // Now check that the proxy setup is as expected in the cross-compartment + // case. + if (isProxy(alien)) { + check(() => isProxy(alien_view)); + check(() => isProxy(alien_buffer)); + check(() => isProxy(view)); // the real test + } + + // cross-realm property access + check(() => alien_buffer.byteLength == 7); + check(() => alien_view.byteLength == 7); + check(() => view.byteLength == 7); + + // typed array protos should be equal + simple = new Int8Array(12); + check(() => Object.getPrototypeOf(view) == Object.getPrototypeOf(simple)); + check(() => Object.getPrototypeOf(view) == Int8Array.prototype); + + // Most named properties are defined on %TypedArray%.prototype. + check(() => !simple.hasOwnProperty('byteLength')); + check(() => !Int8Array.prototype.hasOwnProperty('byteLength')); + check(() => Object.getPrototypeOf(Int8Array.prototype).hasOwnProperty('byteLength')); + + check(() => !simple.hasOwnProperty("BYTES_PER_ELEMENT")); + check(() => Int8Array.prototype.hasOwnProperty("BYTES_PER_ELEMENT")); + check(() => !Object.getPrototypeOf(Int8Array.prototype).hasOwnProperty("BYTES_PER_ELEMENT")); + + // crazy as it sounds, the named properties are configurable per WebIDL. + // But we are currently discussing the situation, and typed arrays may be + // pulled into the ES spec, so for now this is disallowed. + if (false) { + check(() => simple.byteLength == 12); + getter = Object.getOwnPropertyDescriptor(Int8Array.prototype, 'byteLength').get; + Object.defineProperty(Int8Array.prototype, 'byteLength', { get: function () { return 1 + getter.apply(this) } }); + check(() => simple.byteLength == 13); + } + + // test copyWithin() + var numbers = [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]; + + function tastring(tarray) { + return [...tarray].toString(); + } + + function checkCopyWithin(offset, start, end, dest, want) { + var numbers_buffer = new Uint8Array(numbers).buffer; + var view = new Int8Array(numbers_buffer, offset); + view.copyWithin(dest, start, end); + check(() => tastring(view) == want.toString()); + if (tastring(view) != want.toString()) { + print("Wanted: " + want.toString()); + print("Got : " + tastring(view)); + } + } + + // basic copyWithin [2,5) -> 4 + checkCopyWithin(0, 2, 5, 4, [ 0, 1, 2, 3, 2, 3, 4, 7, 8 ]); + + // negative values should count from end + checkCopyWithin(0, -7, 5, 4, [ 0, 1, 2, 3, 2, 3, 4, 7, 8 ]); + checkCopyWithin(0, 2, -4, 4, [ 0, 1, 2, 3, 2, 3, 4, 7, 8 ]); + checkCopyWithin(0, 2, 5, -5, [ 0, 1, 2, 3, 2, 3, 4, 7, 8 ]); + checkCopyWithin(0, -7, -4, -5, [ 0, 1, 2, 3, 2, 3, 4, 7, 8 ]); + + // offset + checkCopyWithin(2, 0, 3, 4, [ 2, 3, 4, 5, 2, 3, 4 ]); + + // clipping + checkCopyWithin(0, 5000, 6000, 0, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(0, -5000, -6000, 0, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(0, -5000, 6000, 0, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(0, 5000, 6000, 1, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(0, -5000, -6000, 1, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(0, 5000, 6000, 0, [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(2, -5000, -6000, 0, [ 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(2, -5000, 6000, 0, [ 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(2, 5000, 6000, 1, [ 2, 3, 4, 5, 6, 7, 8 ]); + checkCopyWithin(2, -5000, -6000, 1, [ 2, 3, 4, 5, 6, 7, 8 ]); + + checkCopyWithin(2, -5000, 3, 1, [ 2, 2, 3, 4, 6, 7, 8 ]); + checkCopyWithin(2, 1, 6000, 0, [ 3, 4, 5, 6, 7, 8, 8 ]); + checkCopyWithin(2, 1, 6000, -4000, [ 3, 4, 5, 6, 7, 8, 8 ]); + + testBufferManagement(); + + print ("done"); + + reportCompare(0, TestFailCount, "typed array tests"); +} -- cgit v1.2.3