Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame^] | 1 | // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | // Flags: --strong-mode --allow-natives-syntax |
| 6 | |
| 7 | "use strict"; |
| 8 | |
| 9 | // Boolean indicates whether an operator can be part of a compound assignment. |
| 10 | let strongNumberBinops = [ |
| 11 | ["-", true], |
| 12 | ["*", true], |
| 13 | ["/", true], |
| 14 | ["%", true], |
| 15 | ["|", true], |
| 16 | ["&", true], |
| 17 | ["^", true], |
| 18 | ["<<", true], |
| 19 | [">>", true], |
| 20 | [">>>", true] |
| 21 | ]; |
| 22 | |
| 23 | let strongStringOrNumberBinops = [ |
| 24 | ["+", true], |
| 25 | ["<", false], |
| 26 | [">", false], |
| 27 | ["<=", false], |
| 28 | [">=", false] |
| 29 | ]; |
| 30 | |
| 31 | let strongBinops = strongNumberBinops.concat(strongStringOrNumberBinops); |
| 32 | |
| 33 | let strongUnops = [ |
| 34 | "~", |
| 35 | "+", |
| 36 | "-" |
| 37 | ]; |
| 38 | |
| 39 | let nonStringOrNumberValues = [ |
| 40 | "null", |
| 41 | "undefined", |
| 42 | "{}", |
| 43 | "false", |
| 44 | "(function(){})", |
| 45 | "[]", |
| 46 | "(class Foo {})" |
| 47 | ]; |
| 48 | |
| 49 | let stringValues = [ |
| 50 | "''", |
| 51 | "' '", |
| 52 | "'foo'", |
| 53 | "'f\\u006F\\u006F'", |
| 54 | "'0'", |
| 55 | "'NaN'" |
| 56 | ]; |
| 57 | |
| 58 | let nonNumberValues = nonStringOrNumberValues.concat(stringValues); |
| 59 | |
| 60 | let numberValues = [ |
| 61 | "0", |
| 62 | "(-0)", |
| 63 | "1", |
| 64 | "(-4294967295)", |
| 65 | "(-4294967296)", |
| 66 | "9999999999999", |
| 67 | "(-9999999999999)", |
| 68 | "NaN", |
| 69 | "Infinity", |
| 70 | "(-Infinity)" |
| 71 | ]; |
| 72 | |
| 73 | //****************************************************************************** |
| 74 | // Relational comparison function declarations |
| 75 | function add_strong(x, y) { |
| 76 | "use strong"; |
| 77 | return x + y; |
| 78 | } |
| 79 | |
| 80 | function add_num_strong(x, y) { |
| 81 | "use strong"; |
| 82 | return x + y; |
| 83 | } |
| 84 | |
| 85 | function sub_strong(x, y) { |
| 86 | "use strong"; |
| 87 | return x - y; |
| 88 | } |
| 89 | |
| 90 | function mul_strong(x, y) { |
| 91 | "use strong"; |
| 92 | return x * y; |
| 93 | } |
| 94 | |
| 95 | function div_strong(x, y) { |
| 96 | "use strong"; |
| 97 | return x / y; |
| 98 | } |
| 99 | |
| 100 | function mod_strong(x, y) { |
| 101 | "use strong"; |
| 102 | return x % y; |
| 103 | } |
| 104 | |
| 105 | function or_strong(x, y) { |
| 106 | "use strong"; |
| 107 | return x | y; |
| 108 | } |
| 109 | |
| 110 | function and_strong(x, y) { |
| 111 | "use strong"; |
| 112 | return x & y; |
| 113 | } |
| 114 | |
| 115 | function xor_strong(x, y) { |
| 116 | "use strong"; |
| 117 | return x ^ y; |
| 118 | } |
| 119 | |
| 120 | function shl_strong(x, y) { |
| 121 | "use strong"; |
| 122 | return x << y; |
| 123 | } |
| 124 | |
| 125 | function shr_strong(x, y) { |
| 126 | "use strong"; |
| 127 | return x >> y; |
| 128 | } |
| 129 | |
| 130 | function sar_strong(x, y) { |
| 131 | "use strong"; |
| 132 | return x >>> y; |
| 133 | } |
| 134 | |
| 135 | function less_strong(x, y) { |
| 136 | "use strong"; |
| 137 | return x < y; |
| 138 | } |
| 139 | |
| 140 | function less_num_strong(x, y) { |
| 141 | "use strong"; |
| 142 | return x < y; |
| 143 | } |
| 144 | |
| 145 | function greater_strong(x, y) { |
| 146 | "use strong"; |
| 147 | return x > y; |
| 148 | } |
| 149 | |
| 150 | function greater_num_strong(x, y) { |
| 151 | "use strong"; |
| 152 | return x > y; |
| 153 | } |
| 154 | |
| 155 | function less_equal_strong(x, y) { |
| 156 | "use strong"; |
| 157 | return x <= y; |
| 158 | } |
| 159 | |
| 160 | function less_equal_num_strong(x, y) { |
| 161 | "use strong"; |
| 162 | return x <= y; |
| 163 | } |
| 164 | |
| 165 | function greater_equal_strong(x, y) { |
| 166 | "use strong"; |
| 167 | return x >= y; |
| 168 | } |
| 169 | |
| 170 | function greater_equal_num_strong(x, y) { |
| 171 | "use strong"; |
| 172 | return x >= y; |
| 173 | } |
| 174 | |
| 175 | function typed_add_strong(x, y) { |
| 176 | "use strong"; |
| 177 | return (+x) + (+y); |
| 178 | } |
| 179 | |
| 180 | function typed_sub_strong(x, y) { |
| 181 | "use strong"; |
| 182 | return (+x) - (+y); |
| 183 | } |
| 184 | |
| 185 | function typed_mul_strong(x, y) { |
| 186 | "use strong"; |
| 187 | return (+x) * (+y); |
| 188 | } |
| 189 | |
| 190 | function typed_div_strong(x, y) { |
| 191 | "use strong"; |
| 192 | return (+x) / (+y); |
| 193 | } |
| 194 | |
| 195 | function typed_mod_strong(x, y) { |
| 196 | "use strong"; |
| 197 | return (+x) % (+y); |
| 198 | } |
| 199 | |
| 200 | function typed_or_strong(x, y) { |
| 201 | "use strong"; |
| 202 | return (+x) | (+y); |
| 203 | } |
| 204 | |
| 205 | function typed_and_strong(x, y) { |
| 206 | "use strong"; |
| 207 | return (+x) & (+y); |
| 208 | } |
| 209 | |
| 210 | function typed_xor_strong(x, y) { |
| 211 | "use strong"; |
| 212 | return (+x) ^ (+y); |
| 213 | } |
| 214 | |
| 215 | function typed_shl_strong(x, y) { |
| 216 | "use strong"; |
| 217 | return (+x) << (+y); |
| 218 | } |
| 219 | |
| 220 | function typed_shr_strong(x, y) { |
| 221 | "use strong"; |
| 222 | return (+x) >> (+y); |
| 223 | } |
| 224 | |
| 225 | function typed_sar_strong(x, y) { |
| 226 | "use strong"; |
| 227 | return (+x) >>> (+y); |
| 228 | } |
| 229 | |
| 230 | function typed_less_strong(x, y) { |
| 231 | "use strong"; |
| 232 | return (+x) < (+y); |
| 233 | } |
| 234 | |
| 235 | function typed_greater_strong(x, y) { |
| 236 | "use strong"; |
| 237 | return (+x) > (+y); |
| 238 | } |
| 239 | |
| 240 | function typed_less_equal_strong(x, y) { |
| 241 | "use strong"; |
| 242 | return (+x) <= (+y); |
| 243 | } |
| 244 | |
| 245 | function typed_greater_equal_strong(x, y) { |
| 246 | "use strong"; |
| 247 | return (+x) >= (+y); |
| 248 | } |
| 249 | |
| 250 | //****************************************************************************** |
| 251 | // (in)equality function declarations |
| 252 | function str_equal_strong(x, y) { |
| 253 | "use strong"; |
| 254 | return x === y; |
| 255 | } |
| 256 | |
| 257 | function str_ineq_strong(x, y) { |
| 258 | "use strong"; |
| 259 | return x !== y; |
| 260 | } |
| 261 | |
| 262 | let strongNumberFuncs = [add_num_strong, sub_strong, mul_strong, div_strong, |
| 263 | mod_strong, or_strong, and_strong, xor_strong, |
| 264 | shl_strong, shr_strong, sar_strong, less_num_strong, |
| 265 | greater_num_strong, less_equal_num_strong, |
| 266 | greater_equal_num_strong, typed_add_strong, |
| 267 | typed_sub_strong, typed_mul_strong, typed_div_strong, |
| 268 | typed_mod_strong, typed_or_strong, typed_and_strong, |
| 269 | typed_xor_strong, typed_shl_strong, typed_shr_strong, |
| 270 | typed_sar_strong, typed_less_strong, |
| 271 | typed_greater_strong, typed_less_equal_strong, |
| 272 | typed_greater_equal_strong]; |
| 273 | |
| 274 | let strongStringOrNumberFuncs = [add_strong, less_strong, greater_strong, |
| 275 | less_equal_strong, greater_equal_strong]; |
| 276 | |
| 277 | let strongFuncs = strongNumberFuncs.concat(strongStringOrNumberFuncs); |
| 278 | |
| 279 | function assertStrongNonThrowBehaviour(expr) { |
| 280 | assertEquals(eval(expr), eval("'use strong';" + expr)); |
| 281 | assertDoesNotThrow("'use strong'; " + expr + ";"); |
| 282 | assertDoesNotThrow("'use strong'; let v = " + expr + ";"); |
| 283 | } |
| 284 | |
| 285 | function assertStrongThrowBehaviour(expr) { |
| 286 | assertDoesNotThrow("'use strict'; " + expr + ";"); |
| 287 | assertDoesNotThrow("'use strict'; let v = " + expr + ";"); |
| 288 | assertThrows("'use strong'; " + expr + ";", TypeError); |
| 289 | assertThrows("'use strong'; let v = " + expr + ";", TypeError); |
| 290 | } |
| 291 | |
| 292 | function checkArgumentCombinations(op, leftList, rightList, willThrow) { |
| 293 | for (let v1 of leftList) { |
| 294 | let assignExpr = "foo " + op[0] + "= " + v1 + ";"; |
| 295 | for (let v2 of rightList) { |
| 296 | let compoundAssignment = "'use strong'; let foo = " + v2 + "; " + |
| 297 | assignExpr; |
| 298 | if (willThrow) { |
| 299 | if (op[1]) { |
| 300 | assertThrows(compoundAssignment, TypeError); |
| 301 | } |
| 302 | assertStrongThrowBehaviour("(" + v1 + op[0] + v2 + ")"); |
| 303 | } else { |
| 304 | if (op[1]) { |
| 305 | assertDoesNotThrow(compoundAssignment); |
| 306 | } |
| 307 | assertStrongNonThrowBehaviour("(" + v1 + op[0] + v2 + ")"); |
| 308 | } |
| 309 | } |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | for (let op of strongBinops) { |
| 314 | checkArgumentCombinations(op, numberValues, numberValues, false); |
| 315 | checkArgumentCombinations(op, numberValues, nonNumberValues, true); |
| 316 | } |
| 317 | |
| 318 | for (let op of strongNumberBinops) { |
| 319 | checkArgumentCombinations(op, nonNumberValues, |
| 320 | numberValues.concat(nonNumberValues), true); |
| 321 | } |
| 322 | |
| 323 | for (let op of strongStringOrNumberBinops) { |
| 324 | checkArgumentCombinations(op, nonNumberValues, |
| 325 | numberValues.concat(nonStringOrNumberValues), true); |
| 326 | checkArgumentCombinations(op, nonStringOrNumberValues, stringValues, true); |
| 327 | checkArgumentCombinations(op, stringValues, stringValues, false); |
| 328 | } |
| 329 | |
| 330 | for (let op of strongUnops) { |
| 331 | for (let value of numberValues) { |
| 332 | assertStrongNonThrowBehaviour("(" + op + value + ")"); |
| 333 | } |
| 334 | for (let value of nonNumberValues) { |
| 335 | assertStrongThrowBehaviour("(" + op + value + ")"); |
| 336 | } |
| 337 | } |
| 338 | |
| 339 | for (let func of strongNumberFuncs) { |
| 340 | // Check IC None*None->None throws |
| 341 | for (let v of nonNumberValues) { |
| 342 | let value = eval(v); |
| 343 | assertThrows(function(){func(2, value);}, TypeError); |
| 344 | %OptimizeFunctionOnNextCall(func); |
| 345 | assertThrows(function(){func(2, value);}, TypeError); |
| 346 | %DeoptimizeFunction(func); |
| 347 | } |
| 348 | func(4, 5); |
| 349 | func(4, 5); |
| 350 | // Check IC Smi*Smi->Smi throws |
| 351 | for (let v of nonNumberValues) { |
| 352 | let value = eval(v); |
| 353 | assertThrows(function(){func(2, value);}, TypeError); |
| 354 | %OptimizeFunctionOnNextCall(func); |
| 355 | assertThrows(function(){func(2, value);}, TypeError); |
| 356 | %DeoptimizeFunction(func); |
| 357 | } |
| 358 | func(NaN, NaN); |
| 359 | func(NaN, NaN); |
| 360 | // Check IC Number*Number->Number throws |
| 361 | for (let v of nonNumberValues) { |
| 362 | let value = eval(v); |
| 363 | assertThrows(function(){func(2, value);}, TypeError); |
| 364 | %OptimizeFunctionOnNextCall(func); |
| 365 | assertThrows(function(){func(2, value);}, TypeError); |
| 366 | %DeoptimizeFunction(func); |
| 367 | } |
| 368 | } |
| 369 | |
| 370 | for (let func of strongStringOrNumberFuncs) { |
| 371 | // Check IC None*None->None throws |
| 372 | for (let v of nonNumberValues) { |
| 373 | let value = eval(v); |
| 374 | assertThrows(function(){func(2, value);}, TypeError); |
| 375 | %OptimizeFunctionOnNextCall(func); |
| 376 | assertThrows(function(){func(2, value);}, TypeError); |
| 377 | %DeoptimizeFunction(func); |
| 378 | } |
| 379 | func("foo", "bar"); |
| 380 | func("foo", "bar"); |
| 381 | // Check IC String*String->String throws |
| 382 | for (let v of nonNumberValues) { |
| 383 | let value = eval(v); |
| 384 | assertThrows(function(){func(2, value);}, TypeError); |
| 385 | %OptimizeFunctionOnNextCall(func); |
| 386 | assertThrows(function(){func(2, value);}, TypeError); |
| 387 | %DeoptimizeFunction(func); |
| 388 | } |
| 389 | func(NaN, NaN); |
| 390 | func(NaN, NaN); |
| 391 | // Check IC Generic*Generic->Generic throws |
| 392 | for (let v of nonNumberValues) { |
| 393 | let value = eval(v); |
| 394 | assertThrows(function(){func(2, value);}, TypeError); |
| 395 | %OptimizeFunctionOnNextCall(func); |
| 396 | assertThrows(function(){func(2, value);}, TypeError); |
| 397 | %DeoptimizeFunction(func); |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | for (let func of [str_equal_strong, str_ineq_strong]) { |
| 402 | assertDoesNotThrow(function(){func(2, undefined)}); |
| 403 | assertDoesNotThrow(function(){func(2, undefined)}); |
| 404 | %OptimizeFunctionOnNextCall(func); |
| 405 | assertDoesNotThrow(function(){func(2, undefined)}); |
| 406 | %DeoptimizeFunction(func); |
| 407 | assertDoesNotThrow(function(){func(true, {})}); |
| 408 | assertDoesNotThrow(function(){func(true, {})}); |
| 409 | %OptimizeFunctionOnNextCall(func); |
| 410 | assertDoesNotThrow(function(){func(true, {})}); |
| 411 | %DeoptimizeFunction(func); |
| 412 | } |