1// Copyright 2008 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28// Flags: --allow-natives-syntax 29 30function f0() { 31 switch (0) { 32 // switch deliberately left empty 33 } 34} 35 36f0(); // no errors 37 38function f1(x) { 39 switch (x) { 40 default: return "f1"; 41 } 42 return "foo"; 43} 44 45assertEquals("f1", f1(0), "default-switch.0"); 46assertEquals("f1", f1(1), "default-switch.1"); 47 48function f2(x) { 49 var r; 50 switch (x) { 51 case 0: 52 r = "zero"; 53 break; 54 case 1: 55 r = "one"; 56 break; 57 case 2: 58 r = "two"; 59 break; 60 case 3: 61 r = "three"; 62 break; 63 default: 64 r = "default"; 65 } 66 return r; 67} 68 69assertEquals("zero", f2(0), "0-1-switch.0"); 70assertEquals("one", f2(1), "0-1-switch.1"); 71assertEquals("default", f2(7), "0-1-switch.2"); 72assertEquals("default", f2(-1), "0-1-switch.-1"); 73assertEquals("default", f2(NaN), "0-1-switch.NaN"); 74assertEquals("default", f2(Math.pow(2,34)), "0-1-switch.largeNum"); 75assertEquals("default", f2("0"), "0-1-switch.string"); 76assertEquals("default", f2(false), "0-1-switch.bool"); 77assertEquals("default", f2(null), "0-1-switch.null"); 78assertEquals("default", f2(undefined), "0-1-switch.undef"); 79assertEquals("default", f2(new Number(2)), "0-1-switch.undef"); 80assertEquals("default", f2({valueOf: function(){return 2; }}), "0-1-switch.obj"); 81 82 83function f3(x, c) { 84 var r = 0; 85 switch (x) { 86 default: 87 r = "default"; 88 break; 89 case c: 90 r = "value is c = " + c; 91 break; 92 case 2: 93 r = "two"; 94 break; 95 case -5: 96 r = "minus 5"; 97 break; 98 case 9: 99 r = "nine"; 100 break; 101 } 102 return r; 103} 104 105assertEquals("two", f3(2,0), "value-switch.2-0"); 106assertEquals("minus 5", f3(-5,0), "value-switch.-5-0"); 107assertEquals("nine", f3(9,0), "value-switch.9-0"); 108assertEquals("value is c = 0", f3(0,0), "value-switch.0-0"); 109assertEquals("value is c = 2", f3(2,2), "value-switch.2-2"); 110assertEquals("default", f3(7,0), "value-switch.7-0"); 111 112 113function f4(x) { 114 switch(x) { 115 case 0: 116 x++; 117 default: 118 x++; 119 case 2: 120 x++; 121 } 122 return x; 123} 124 125 126assertEquals(3, f4(0), "fallthrough-switch.0"); 127assertEquals(3, f4(1), "fallthrough-switch.1"); 128assertEquals(3, f4(2), "fallthrough-switch.2"); 129assertEquals(5, f4(3), "fallthrough-switch.3"); 130 131function f4_string(tag, x) { 132 switch(tag) { 133 case 'zero': 134 x++; 135 case 'two': 136 x++; 137 } 138 return x; 139} 140 141// Symbols 142assertEquals(2, f4_string('zero', 0), "fallthrough-string-switch.0"); 143assertEquals(1, f4_string('one', 1), "fallthrough-string-switch.1"); 144assertEquals(3, f4_string('two', 2), "fallthrough-string-switch.2"); 145 146// Strings 147assertEquals(2, f4_string('_zero'.slice(1), 0), "fallthrough-string-switch.3"); 148assertEquals(1, f4_string('_one'.slice(1), 1), "fallthrough-string-switch.4"); 149assertEquals(3, f4_string('_two'.slice(1), 2), "fallthrough-string-switch.5"); 150 151// Oddball 152assertEquals(3, f4_string(null, 3), "fallthrough-string-switch.6"); 153 154// Test for regression 155function regress_string(value) { 156 var json = 1; 157 switch (typeof value) { 158 case 'object': 159 break; 160 161 default: 162 163 } 164 return json; 165}; 166assertEquals(1, regress_string('object'), 'regression-string'); 167 168function f5(x) { 169 switch(x) { 170 case -2: return true; 171 case -1: return false; 172 case 0: return true; 173 case 2: return false; 174 default: return 42; 175 } 176} 177 178assertTrue(f5(-2), "negcase.-2"); 179assertFalse(f5(-1), "negcase.-1"); 180assertTrue(f5(0), "negcase.-0"); 181assertEquals(42, f5(1), "negcase.1"); 182assertFalse(f5(2), "negcase.2"); 183 184function f6(N) { 185 // long enough case that code buffer grows during code-generation 186 var res = 0; 187 for(var i = 0; i < N; i++) { 188 switch(i & 0x3f) { 189 case 0: res += 0; break; 190 case 1: res += 1; break; 191 case 2: res += 2; break; 192 case 3: res += 3; break; 193 case 4: res += 4; break; 194 case 5: res += 5; break; 195 case 6: res += 6; break; 196 case 7: res += 7; break; 197 case 8: res += 8; break; 198 case 9: res += 9; break; 199 case 10: res += 10; break; 200 case 11: res += 11; break; 201 case 12: res += 12; break; 202 case 13: res += 13; break; 203 case 14: res += 14; break; 204 case 15: res += 15; break; 205 case 16: res += 16; break; 206 case 17: res += 17; break; 207 case 18: res += 18; break; 208 case 19: res += 19; break; 209 case 20: res += 20; break; 210 case 21: res += 21; break; 211 case 22: res += 22; break; 212 case 23: res += 23; break; 213 case 24: res += 24; break; 214 case 25: res += 25; break; 215 case 26: res += 26; break; 216 case 27: res += 27; break; 217 case 28: res += 28; break; 218 case 29: res += 29; break; 219 case 30: res += 30; break; 220 case 31: res += 31; break; 221 case 32: res += 32; break; 222 case 33: res += 33; break; 223 case 34: res += 34; break; 224 case 35: res += 35; break; 225 case 36: res += 36; break; 226 case 37: res += 37; break; 227 case 38: res += 38; break; 228 case 39: res += 39; break; 229 case 40: res += 40; break; 230 case 41: res += 41; break; 231 case 42: res += 42; break; 232 case 43: res += 43; break; 233 case 44: res += 44; break; 234 case 45: res += 45; break; 235 case 46: res += 46; break; 236 case 47: res += 47; break; 237 case 48: res += 48; break; 238 case 49: res += 49; break; 239 case 50: res += 50; break; 240 case 51: res += 51; break; 241 case 52: res += 52; break; 242 case 53: res += 53; break; 243 case 54: res += 54; break; 244 case 55: res += 55; break; 245 case 56: res += 56; break; 246 case 57: res += 57; break; 247 case 58: res += 58; break; 248 case 59: res += 59; break; 249 case 60: res += 60; break; 250 case 61: res += 61; break; 251 case 62: res += 62; break; 252 case 63: res += 63; break; 253 case 64: break; 254 default: break; 255 } 256 } 257 return res; 258} 259 260assertEquals(190, f6(20), "largeSwitch.20"); 261assertEquals(2016, f6(64), "largeSwitch.64"); 262assertEquals(4032, f6(128), "largeSwitch.128"); 263assertEquals(4222, f6(148), "largeSwitch.148"); 264 265 266function f7(value) { 267 switch (value) { 268 case 0: return "0"; 269 case -0: return "-0"; 270 case 1: case 2: case 3: case 4: // Dummy fillers. 271 } 272 switch (value) { 273 case 0x3fffffff: return "MaxSmi"; 274 case 0x3ffffffe: 275 case 0x3ffffffd: 276 case 0x3ffffffc: 277 case 0x3ffffffb: 278 case 0x3ffffffa: // Dummy fillers 279 } 280 switch (value) { 281 case -0x40000000: return "MinSmi"; 282 case -0x3fffffff: 283 case -0x3ffffffe: 284 case -0x3ffffffd: 285 case -0x3ffffffc: 286 case -0x3ffffffb: // Dummy fillers 287 } 288 switch (value) { 289 case 10: return "A"; 290 case 11: 291 case 12: 292 case 13: 293 case 14: 294 case 15: // Dummy fillers 295 } 296 return "default"; 297} 298 299 300assertEquals("default", f7(0.1), "0-1-switch.double-0.1"); 301assertEquals("0", f7(-0), "0-1-switch.double-neg0"); 302assertEquals("MaxSmi", f7((1<<30)-1), "0-1-switch.maxsmi"); 303assertEquals("MinSmi", f7(-(1<<30)), "0-1-switch.minsmi"); 304assertEquals("default", f7(1<<30), "0-1-switch.maxsmi++"); 305assertEquals("default", f7(-(1<<30)-1), "0-1-switch.minsmi--"); 306assertEquals("A", f7((170/16)-(170%16/16)), "0-1-switch.heapnum"); 307 308 309function makeVeryLong(length) { 310 var res = "(function () {\n" + 311 " var res = 0;\n" + 312 " for (var i = 0; i <= " + length + "; i++) {\n" + 313 " switch(i) {\n"; 314 for (var i = 0; i < length; i++) { 315 res += " case " + i + ": res += 2; break;\n"; 316 } 317 res += " default: res += 1;\n" + 318 " }\n" + 319 " }\n" + 320 " return res;\n" + 321 "})"; 322 return eval(res); 323} 324var verylong_size = 1000; 325var verylong = makeVeryLong(verylong_size); 326 327assertEquals(verylong_size * 2 + 1, verylong()); 328 329// 330// Test suite below aims to cover all possible combinations of following: 331// 332// clauses | tags | type feedback | optimization 333// ========================================================= 334// strings | symbol | all | on 335// smis | string | target | off 336// mixed | oddball | non-target | 337// | smis | none | 338// | heapnum | | 339// ========================================================= 340 341// Function-with-switch generator 342var test_id = 0, 343 clause_values = { 344 string: ['abc', 'def', 'ghi', 'jkl'], 345 smi: [1, 2, 3, 4], 346 mixed: ['abc', 1, 'def', 2, 'ghi', 3, 'jkl', 4] 347 }; 348 349function switch_gen(clause_type, feedback, optimize) { 350 var values = clause_values[clause_type]; 351 352 function opt(fn) { 353 if (feedback === 'all') { 354 values.forEach(fn); 355 } else if (Array.isArray(feedback)) { 356 // Non-target 357 values.filter(function(v) { 358 return feedback.indexOf(v) === -1; 359 }).forEach(fn); 360 } else if (feedback !== undefined) { 361 // Target 362 fn(feedback); 363 } else { 364 // None 365 } 366 367 if (optimize) %OptimizeFunctionOnNextCall(fn); 368 369 return fn; 370 }; 371 372 return opt(new Function( 373 'tag', 374 '"' + (test_id++) + '";' + 375 'switch(tag) {' + 376 values.map(function(value) { 377 return 'case ' + JSON.stringify(value) + ': return' + 378 JSON.stringify('ok-' + value); 379 }).join(';') + 380 '}' 381 )); 382}; 383 384function test_switch(clause_type, test_type, feedback, optimize) { 385 var pairs = [], 386 fn = switch_gen(clause_type, feedback, optimize); 387 388 if (Array.isArray(test_type)) { 389 pairs = test_type.map(function(v) { 390 return { 391 value: v, 392 expected: 'ok-' + v 393 }; 394 }); 395 } else if (test_type === 'symbols') { 396 pairs = clause_values.string.map(function(v) { 397 return { 398 value: v, 399 expected: clause_type !== 'smi' ? 'ok-' + v : undefined 400 }; 401 }); 402 } else if (test_type === 'strings') { 403 pairs = clause_values.string.map(function(v) { 404 return { 405 value: ('%%' + v).slice(2), 406 expected: clause_type !== 'smi' ? 'ok-' + v : undefined 407 }; 408 }); 409 } else if (test_type === 'oddball') { 410 pairs = [ 411 { value: null, expected: undefined }, 412 { value: NaN, expected: undefined }, 413 { value: undefined, expected: undefined } 414 ]; 415 } else if (test_type === 'smi') { 416 pairs = clause_values.smi.map(function(v) { 417 return { 418 value: v, 419 expected: clause_type !== 'string' ? 'ok-' + v : undefined 420 }; 421 }); 422 } else if (test_type === 'heapnum') { 423 pairs = clause_values.smi.map(function(v) { 424 return { 425 value: ((v * 17)/16) - ((v*17)%16/16), 426 expected: clause_type !== 'string' ? 'ok-' + v : undefined 427 }; 428 }); 429 } 430 431 pairs.forEach(function(pair) { 432 assertEquals(fn(pair.value), pair.expected); 433 }); 434}; 435 436// test_switch(clause_type, test_type, feedback, optimize); 437 438function test_switches(opt) { 439 var test_types = ['symbols', 'strings', 'oddball', 'smi', 'heapnum']; 440 441 function test(clause_type) { 442 var values = clause_values[clause_type]; 443 444 test_types.forEach(function(test_type) { 445 test_switch(clause_type, test_type, 'all', opt); 446 test_switch(clause_type, test_type, 'none', opt); 447 448 // Targeting specific clause feedback 449 values.forEach(function(value) { 450 test_switch(clause_type, test_type, [value], value, opt); 451 test_switch(clause_type, test_type, value, value, opt); 452 }); 453 }); 454 }; 455 456 test('string'); 457 test('smi'); 458 test('mixed'); 459}; 460 461test_switches(false); 462test_switches(true); 463 464 465// Test labeled and anonymous breaks in switch statements 466(function test_switch_break() { 467 A: for (var i = 1; i < 10; i++) { 468 switch (i) { 469 case 1: 470 break A; 471 } 472 } 473 assertEquals(1, i); 474 475 for (var i = 1; i < 10; i++) { 476 B: switch (i) { 477 case 1: 478 break B; 479 } 480 } 481 assertEquals(10, i); 482 483 for (var i = 1; i < 10; i++) { 484 switch (i) { 485 case 1: 486 break; 487 } 488 } 489 assertEquals(10, i); 490 491 switch (1) { 492 case 1: 493 C: for (var i = 1; i < 10; i++) { 494 break C; 495 } 496 i = 2; 497 } 498 assertEquals(2, i); 499 500 switch (1) { 501 case 1: 502 for (var i = 1; i < 10; i++) { 503 break; 504 } 505 i = 2; 506 } 507 assertEquals(2, i); 508 509 D: switch (1) { 510 case 1: 511 for (var i = 1; i < 10; i++) { 512 break D; 513 } 514 i = 2; 515 } 516 assertEquals(1, i); 517})(); 518