nan-canonicalization.js (7368B)
1 // Test NaN canonicalisation when reading from a DataView. 2 3 load(libdir + "dataview.js"); 4 5 // Float16 6 function testF16() { 7 function writeBE(ui16, value) { 8 let ui8 = new Uint8Array(ui16.buffer); 9 10 ui8[0] = (value >> 8) & 0xff; 11 ui8[1] = (value >> 0) & 0xff; 12 } 13 14 function writeLE(ui16, value) { 15 let ui8 = new Uint8Array(ui16.buffer); 16 17 ui8[0] = (value >> 0) & 0xff; 18 ui8[1] = (value >> 8) & 0xff; 19 } 20 21 // Smallest and largest SNaNs and QNaNs, with and without sign-bit set. 22 const NaNs = [ 23 0x7C01, 0x7DFF, 0x7E00, 0x7FFF, 24 0xFC01, 0xFDFF, 0xFE00, 0xFFFF, 25 ]; 26 27 const canonicalNaN = new Uint16Array(new Float16Array([NaN]).buffer)[0]; 28 29 // Load from array so that Ion doesn't treat as constants. 30 const True = [true, 1]; 31 const False = [false, 0]; 32 33 function f() { 34 let src_ui16 = new Uint16Array(1); 35 36 let dst_f16 = new Float16Array(1); 37 let dst_ui16 = new Uint16Array(dst_f16.buffer); 38 39 let dv = new DataView(src_ui16.buffer); 40 41 for (let i = 0; i < 100; ++i) { 42 let nan = NaNs[i % NaNs.length]; 43 44 // Write to typed array, implicitly using native endian. 45 src_ui16[0] = nan; 46 dst_f16[0] = dv.getFloat16(0, nativeIsLittleEndian); 47 assertEq(dst_ui16[0], canonicalNaN); 48 49 // Write and read using big endian. |isLittleEndian| parameter is absent. 50 writeBE(src_ui16, nan); 51 dst_f16[0] = dv.getFloat16(0); 52 assertEq(dst_ui16[0], canonicalNaN); 53 54 // Write and read using big endian. |isLittleEndian| parameter is a constant. 55 writeBE(src_ui16, nan); 56 dst_f16[0] = dv.getFloat16(0, false); 57 assertEq(dst_ui16[0], canonicalNaN); 58 59 // Write and read using little endian. |isLittleEndian| parameter is a constant. 60 writeLE(src_ui16, nan); 61 dst_f16[0] = dv.getFloat16(0, true); 62 assertEq(dst_ui16[0], canonicalNaN); 63 64 // Write and read using big endian. 65 writeBE(src_ui16, nan); 66 dst_f16[0] = dv.getFloat16(0, False[i & 1]); 67 assertEq(dst_ui16[0], canonicalNaN); 68 69 // Write and read using little endian. 70 writeLE(src_ui16, nan); 71 dst_f16[0] = dv.getFloat16(0, True[i & 1]); 72 assertEq(dst_ui16[0], canonicalNaN); 73 } 74 } 75 76 for (let i = 0; i < 2; ++i) f(); 77 } 78 testF16(); 79 80 // Float32 81 function testF32() { 82 function writeBE(ui32, value) { 83 let ui8 = new Uint8Array(ui32.buffer); 84 85 ui8[0] = (value >> 24) & 0xff; 86 ui8[1] = (value >> 16) & 0xff; 87 ui8[2] = (value >> 8) & 0xff; 88 ui8[3] = (value >> 0) & 0xff; 89 } 90 91 function writeLE(ui32, value) { 92 let ui8 = new Uint8Array(ui32.buffer); 93 94 ui8[0] = (value >> 0) & 0xff; 95 ui8[1] = (value >> 8) & 0xff; 96 ui8[2] = (value >> 16) & 0xff; 97 ui8[3] = (value >> 24) & 0xff; 98 } 99 100 // Smallest and largest SNaNs and QNaNs, with and without sign-bit set. 101 const NaNs = [ 102 0x7F80_0001, 0x7FBF_FFFF, 0x7FC0_0000, 0x7FFF_FFFF, 103 0xFF80_0001, 0xFFBF_FFFF, 0xFFC0_0000, 0xFFFF_FFFF, 104 ]; 105 106 const canonicalNaN = new Uint32Array(new Float32Array([NaN]).buffer)[0]; 107 108 // Load from array so that Ion doesn't treat as constants. 109 const True = [true, 1]; 110 const False = [false, 0]; 111 112 function f() { 113 let src_ui32 = new Uint32Array(1); 114 115 let dst_f32 = new Float32Array(1); 116 let dst_ui32 = new Uint32Array(dst_f32.buffer); 117 118 let dv = new DataView(src_ui32.buffer); 119 120 for (let i = 0; i < 100; ++i) { 121 let nan = NaNs[i % NaNs.length]; 122 123 // Write to typed array, implicitly using native endian. 124 src_ui32[0] = nan; 125 dst_f32[0] = dv.getFloat32(0, nativeIsLittleEndian); 126 assertEq(dst_ui32[0], canonicalNaN); 127 128 // Write and read using big endian. |isLittleEndian| parameter is absent. 129 writeBE(src_ui32, nan); 130 dst_f32[0] = dv.getFloat32(0); 131 assertEq(dst_ui32[0], canonicalNaN); 132 133 // Write and read using big endian. |isLittleEndian| parameter is a constant. 134 writeBE(src_ui32, nan); 135 dst_f32[0] = dv.getFloat32(0, false); 136 assertEq(dst_ui32[0], canonicalNaN); 137 138 // Write and read using little endian. |isLittleEndian| parameter is a constant. 139 writeLE(src_ui32, nan); 140 dst_f32[0] = dv.getFloat32(0, true); 141 assertEq(dst_ui32[0], canonicalNaN); 142 143 // Write and read using big endian. 144 writeBE(src_ui32, nan); 145 dst_f32[0] = dv.getFloat32(0, False[i & 1]); 146 assertEq(dst_ui32[0], canonicalNaN); 147 148 // Write and read using little endian. 149 writeLE(src_ui32, nan); 150 dst_f32[0] = dv.getFloat32(0, True[i & 1]); 151 assertEq(dst_ui32[0], canonicalNaN); 152 } 153 } 154 155 for (let i = 0; i < 2; ++i) f(); 156 } 157 testF32(); 158 159 // Float64 160 function testF64() { 161 function writeBE(ui64, value) { 162 let ui8 = new Uint8Array(ui64.buffer); 163 164 ui8[0] = Number((value >> 56n) & 0xffn); 165 ui8[1] = Number((value >> 48n) & 0xffn); 166 ui8[2] = Number((value >> 40n) & 0xffn); 167 ui8[3] = Number((value >> 32n) & 0xffn); 168 ui8[4] = Number((value >> 24n) & 0xffn); 169 ui8[5] = Number((value >> 16n) & 0xffn); 170 ui8[6] = Number((value >> 8n) & 0xffn); 171 ui8[7] = Number((value >> 0n) & 0xffn); 172 } 173 174 function writeLE(ui64, value) { 175 let ui8 = new Uint8Array(ui64.buffer); 176 177 ui8[0] = Number((value >> 0n) & 0xffn); 178 ui8[1] = Number((value >> 8n) & 0xffn); 179 ui8[2] = Number((value >> 16n) & 0xffn); 180 ui8[3] = Number((value >> 24n) & 0xffn); 181 ui8[4] = Number((value >> 32n) & 0xffn); 182 ui8[5] = Number((value >> 40n) & 0xffn); 183 ui8[6] = Number((value >> 48n) & 0xffn); 184 ui8[7] = Number((value >> 56n) & 0xffn); 185 } 186 187 // Smallest and largest SNaNs and QNaNs, with and without sign-bit set. 188 const NaNs = [ 189 0x7FF0_0000_0000_0001n, 0x7FF7_FFFF_FFFF_FFFFn, 0x7FF8_0000_0000_0000n, 0x7FFF_FFFF_FFFF_FFFFn, 190 0xFFF0_0000_0000_0001n, 0xFFF7_FFFF_FFFF_FFFFn, 0xFFF8_0000_0000_0000n, 0xFFFF_FFFF_FFFF_FFFFn, 191 ]; 192 193 const canonicalNaN = new BigUint64Array(new Float64Array([NaN]).buffer)[0]; 194 195 // Load from array so that Ion doesn't treat as constants. 196 const True = [true, 1]; 197 const False = [false, 0]; 198 199 function f() { 200 let src_ui64 = new BigUint64Array(1); 201 202 let dst_f64 = new Float64Array(1); 203 let dst_ui64 = new BigUint64Array(dst_f64.buffer); 204 205 let dv = new DataView(src_ui64.buffer); 206 207 for (let i = 0; i < 100; ++i) { 208 let nan = NaNs[i % NaNs.length]; 209 210 src_ui64[0] = nan; 211 dst_f64[0] = dv.getFloat64(0, nativeIsLittleEndian); 212 assertEq(dst_ui64[0], canonicalNaN); 213 214 // Write and read using big endian. |isLittleEndian| parameter is absent. 215 writeBE(src_ui64, nan); 216 dst_f64[0] = dv.getFloat64(0); 217 assertEq(dst_ui64[0], canonicalNaN); 218 219 // Write and read using big endian. |isLittleEndian| parameter is a constant. 220 writeBE(src_ui64, nan); 221 dst_f64[0] = dv.getFloat64(0, false); 222 assertEq(dst_ui64[0], canonicalNaN); 223 224 // Write and read using little endian. |isLittleEndian| parameter is a constant. 225 writeLE(src_ui64, nan); 226 dst_f64[0] = dv.getFloat64(0, true); 227 assertEq(dst_ui64[0], canonicalNaN); 228 229 // Write and read using big endian. 230 writeBE(src_ui64, nan); 231 dst_f64[0] = dv.getFloat64(0, False[i & 1]); 232 assertEq(dst_ui64[0], canonicalNaN); 233 234 // Write and read using little endian. 235 writeLE(src_ui64, nan); 236 dst_f64[0] = dv.getFloat64(0, True[i & 1]); 237 assertEq(dst_ui64[0], canonicalNaN); 238 } 239 } 240 241 for (let i = 0; i < 2; ++i) f(); 242 } 243 testF64();