string-substring-endswith-constant-string.js (2538B)
1 // Test case to cover String.prototype.substring as endsWith with a constant search string. 2 // 3 // String.prototype.substring comparison with a short (≤32 characters) constant string is 4 // optimised during lowering. 5 6 function* characters(...ranges) { 7 for (let [start, end] of ranges) { 8 for (let i = start; i <= end; ++i) { 9 yield i; 10 } 11 } 12 } 13 14 const ascii = [...characters( 15 [0x41, 0x5A], // A..Z 16 [0x61, 0x7A], // a..z 17 [0x30, 0x39], // 0..9 18 )]; 19 20 const latin1 = [...characters( 21 [0xC0, 0xFF], // À..ÿ 22 )]; 23 24 const twoByte = [...characters( 25 [0x100, 0x17E], // Ā..ž 26 )]; 27 28 function toRope(s) { 29 try { 30 return newRope(s[0], s.substring(1)); 31 } catch {} 32 // newRope can fail when |s| fits into an inline string. In that case simply 33 // return the input. 34 return s; 35 } 36 37 function atomize(s) { 38 return Object.keys({[s]: 0})[0]; 39 } 40 41 const operators = [ 42 "==", "===", "!=", "!==", 43 ]; 44 45 for (let i = 1; i <= 32; ++i) { 46 let strings = [ascii, latin1, twoByte].flatMap(codePoints => [ 47 // Same string as the input. 48 String.fromCodePoint(...codePoints.slice(0, i)), 49 50 // Same length as the input, but a different string. 51 String.fromCodePoint(...codePoints.slice(1, i + 1)), 52 53 // Shorter string than the input. 54 String.fromCodePoint(...codePoints.slice(0, i - 1)), 55 56 // Longer string than the input. 57 String.fromCodePoint(...codePoints.slice(0, i + 1)), 58 ]).flatMap(x => [ 59 x, 60 toRope(x), 61 newString(x, {twoByte: true}), 62 atomize(x), 63 ]); 64 65 for (let codePoints of [ascii, latin1, twoByte]) { 66 let str = String.fromCodePoint(...codePoints.slice(0, i)); 67 68 for (let op of operators) { 69 let fn = Function("strings", ` 70 const expected = strings.map(x => { 71 // Prevent Warp compilation when computing the expected results. 72 with ({}) ; 73 return x.slice(-${str.length}) ${op} "${str}"; 74 }); 75 76 for (let i = 0; i < 250; ++i) { 77 let idx = i % strings.length; 78 let str = strings[idx]; 79 80 let lhs = str.slice(-${str.length}) ${op} "${str}"; 81 if (lhs !== expected[idx]) throw new Error(); 82 83 let rhs = "${str}" ${op} str.slice(-${str.length}); 84 if (rhs !== expected[idx]) throw new Error(); 85 86 let lhs2 = str.substr(-${str.length}) ${op} "${str}"; 87 if (lhs2 !== expected[idx]) throw new Error(); 88 89 let rhs2 = "${str}" ${op} str.substr(-${str.length}); 90 if (rhs2 !== expected[idx]) throw new Error(); 91 } 92 `); 93 fn(strings); 94 } 95 } 96 }