1 // Copyright 2012 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 #include <stdlib.h> 29 #include <stdio.h> 30 #include <string.h> 31 32 #include "v8.h" 33 34 #include "cctest.h" 35 #include "compiler.h" 36 #include "execution.h" 37 #include "isolate.h" 38 #include "parser.h" 39 #include "preparser.h" 40 #include "scanner-character-streams.h" 41 #include "token.h" 42 #include "utils.h" 43 44 TEST(ScanKeywords) { 45 struct KeywordToken { 46 const char* keyword; 47 i::Token::Value token; 48 }; 49 50 static const KeywordToken keywords[] = { 51 #define KEYWORD(t, s, d) { s, i::Token::t }, 52 TOKEN_LIST(IGNORE_TOKEN, KEYWORD) 53 #undef KEYWORD 54 { NULL, i::Token::IDENTIFIER } 55 }; 56 57 KeywordToken key_token; 58 i::UnicodeCache unicode_cache; 59 i::byte buffer[32]; 60 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) { 61 const i::byte* keyword = 62 reinterpret_cast<const i::byte*>(key_token.keyword); 63 int length = i::StrLength(key_token.keyword); 64 CHECK(static_cast<int>(sizeof(buffer)) >= length); 65 { 66 i::Utf8ToUtf16CharacterStream stream(keyword, length); 67 i::Scanner scanner(&unicode_cache); 68 // The scanner should parse Harmony keywords for this test. 69 scanner.SetHarmonyScoping(true); 70 scanner.SetHarmonyModules(true); 71 scanner.Initialize(&stream); 72 CHECK_EQ(key_token.token, scanner.Next()); 73 CHECK_EQ(i::Token::EOS, scanner.Next()); 74 } 75 // Removing characters will make keyword matching fail. 76 { 77 i::Utf8ToUtf16CharacterStream stream(keyword, length - 1); 78 i::Scanner scanner(&unicode_cache); 79 scanner.Initialize(&stream); 80 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 81 CHECK_EQ(i::Token::EOS, scanner.Next()); 82 } 83 // Adding characters will make keyword matching fail. 84 static const char chars_to_append[] = { 'z', '0', '_' }; 85 for (int j = 0; j < static_cast<int>(ARRAY_SIZE(chars_to_append)); ++j) { 86 i::OS::MemMove(buffer, keyword, length); 87 buffer[length] = chars_to_append[j]; 88 i::Utf8ToUtf16CharacterStream stream(buffer, length + 1); 89 i::Scanner scanner(&unicode_cache); 90 scanner.Initialize(&stream); 91 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 92 CHECK_EQ(i::Token::EOS, scanner.Next()); 93 } 94 // Replacing characters will make keyword matching fail. 95 { 96 i::OS::MemMove(buffer, keyword, length); 97 buffer[length - 1] = '_'; 98 i::Utf8ToUtf16CharacterStream stream(buffer, length); 99 i::Scanner scanner(&unicode_cache); 100 scanner.Initialize(&stream); 101 CHECK_EQ(i::Token::IDENTIFIER, scanner.Next()); 102 CHECK_EQ(i::Token::EOS, scanner.Next()); 103 } 104 } 105 } 106 107 108 TEST(ScanHTMLEndComments) { 109 v8::V8::Initialize(); 110 111 // Regression test. See: 112 // http://code.google.com/p/chromium/issues/detail?id=53548 113 // Tests that --> is correctly interpreted as comment-to-end-of-line if there 114 // is only whitespace before it on the line (with comments considered as 115 // whitespace, even a multiline-comment containing a newline). 116 // This was not the case if it occurred before the first real token 117 // in the input. 118 const char* tests[] = { 119 // Before first real token. 120 "--> is eol-comment\nvar y = 37;\n", 121 "\n --> is eol-comment\nvar y = 37;\n", 122 "/* precomment */ --> is eol-comment\nvar y = 37;\n", 123 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n", 124 // After first real token. 125 "var x = 42;\n--> is eol-comment\nvar y = 37;\n", 126 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n", 127 NULL 128 }; 129 130 const char* fail_tests[] = { 131 "x --> is eol-comment\nvar y = 37;\n", 132 "\"\\n\" --> is eol-comment\nvar y = 37;\n", 133 "x/* precomment */ --> is eol-comment\nvar y = 37;\n", 134 "x/* precomment\n */ --> is eol-comment\nvar y = 37;\n", 135 "var x = 42; --> is eol-comment\nvar y = 37;\n", 136 "var x = 42; /* precomment\n */ --> is eol-comment\nvar y = 37;\n", 137 NULL 138 }; 139 140 // Parser/Scanner needs a stack limit. 141 int marker; 142 i::Isolate::Current()->stack_guard()->SetStackLimit( 143 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 144 145 for (int i = 0; tests[i]; i++) { 146 v8::ScriptData* data = 147 v8::ScriptData::PreCompile(tests[i], i::StrLength(tests[i])); 148 CHECK(data != NULL && !data->HasError()); 149 delete data; 150 } 151 152 for (int i = 0; fail_tests[i]; i++) { 153 v8::ScriptData* data = 154 v8::ScriptData::PreCompile(fail_tests[i], i::StrLength(fail_tests[i])); 155 CHECK(data == NULL || data->HasError()); 156 delete data; 157 } 158 } 159 160 161 class ScriptResource : public v8::String::ExternalAsciiStringResource { 162 public: 163 ScriptResource(const char* data, size_t length) 164 : data_(data), length_(length) { } 165 166 const char* data() const { return data_; } 167 size_t length() const { return length_; } 168 169 private: 170 const char* data_; 171 size_t length_; 172 }; 173 174 175 TEST(Preparsing) { 176 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 177 v8::HandleScope handles(isolate); 178 v8::Local<v8::Context> context = v8::Context::New(isolate); 179 v8::Context::Scope context_scope(context); 180 int marker; 181 i::Isolate::Current()->stack_guard()->SetStackLimit( 182 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 183 184 // Source containing functions that might be lazily compiled and all types 185 // of symbols (string, propertyName, regexp). 186 const char* source = 187 "var x = 42;" 188 "function foo(a) { return function nolazy(b) { return a + b; } }" 189 "function bar(a) { if (a) return function lazy(b) { return b; } }" 190 "var z = {'string': 'string literal', bareword: 'propertyName', " 191 " 42: 'number literal', for: 'keyword as propertyName', " 192 " f\\u006fr: 'keyword propertyname with escape'};" 193 "var v = /RegExp Literal/;" 194 "var w = /RegExp Literal\\u0020With Escape/gin;" 195 "var y = { get getter() { return 42; }, " 196 " set setter(v) { this.value = v; }};"; 197 int source_length = i::StrLength(source); 198 const char* error_source = "var x = y z;"; 199 int error_source_length = i::StrLength(error_source); 200 201 v8::ScriptData* preparse = 202 v8::ScriptData::PreCompile(source, source_length); 203 CHECK(!preparse->HasError()); 204 bool lazy_flag = i::FLAG_lazy; 205 { 206 i::FLAG_lazy = true; 207 ScriptResource* resource = new ScriptResource(source, source_length); 208 v8::Local<v8::String> script_source = v8::String::NewExternal(resource); 209 v8::Script::Compile(script_source, NULL, preparse); 210 } 211 212 { 213 i::FLAG_lazy = false; 214 215 ScriptResource* resource = new ScriptResource(source, source_length); 216 v8::Local<v8::String> script_source = v8::String::NewExternal(resource); 217 v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>()); 218 } 219 delete preparse; 220 i::FLAG_lazy = lazy_flag; 221 222 // Syntax error. 223 v8::ScriptData* error_preparse = 224 v8::ScriptData::PreCompile(error_source, error_source_length); 225 CHECK(error_preparse->HasError()); 226 i::ScriptDataImpl *pre_impl = 227 reinterpret_cast<i::ScriptDataImpl*>(error_preparse); 228 i::Scanner::Location error_location = 229 pre_impl->MessageLocation(); 230 // Error is at "z" in source, location 10..11. 231 CHECK_EQ(10, error_location.beg_pos); 232 CHECK_EQ(11, error_location.end_pos); 233 // Should not crash. 234 const char* message = pre_impl->BuildMessage(); 235 pre_impl->BuildArgs(); 236 CHECK_GT(strlen(message), 0); 237 } 238 239 240 TEST(StandAlonePreParser) { 241 v8::V8::Initialize(); 242 243 int marker; 244 i::Isolate::Current()->stack_guard()->SetStackLimit( 245 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 246 247 const char* programs[] = { 248 "{label: 42}", 249 "var x = 42;", 250 "function foo(x, y) { return x + y; }", 251 "%ArgleBargle(glop);", 252 "var x = new new Function('this.x = 42');", 253 NULL 254 }; 255 256 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit(); 257 for (int i = 0; programs[i]; i++) { 258 const char* program = programs[i]; 259 i::Utf8ToUtf16CharacterStream stream( 260 reinterpret_cast<const i::byte*>(program), 261 static_cast<unsigned>(strlen(program))); 262 i::CompleteParserRecorder log; 263 i::Scanner scanner(i::Isolate::Current()->unicode_cache()); 264 scanner.Initialize(&stream); 265 266 v8::preparser::PreParser preparser(&scanner, &log, stack_limit); 267 preparser.set_allow_lazy(true); 268 preparser.set_allow_natives_syntax(true); 269 v8::preparser::PreParser::PreParseResult result = 270 preparser.PreParseProgram(); 271 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result); 272 i::ScriptDataImpl data(log.ExtractData()); 273 CHECK(!data.has_error()); 274 } 275 } 276 277 278 TEST(StandAlonePreParserNoNatives) { 279 v8::V8::Initialize(); 280 281 int marker; 282 i::Isolate::Current()->stack_guard()->SetStackLimit( 283 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 284 285 const char* programs[] = { 286 "%ArgleBargle(glop);", 287 "var x = %_IsSmi(42);", 288 NULL 289 }; 290 291 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit(); 292 for (int i = 0; programs[i]; i++) { 293 const char* program = programs[i]; 294 i::Utf8ToUtf16CharacterStream stream( 295 reinterpret_cast<const i::byte*>(program), 296 static_cast<unsigned>(strlen(program))); 297 i::CompleteParserRecorder log; 298 i::Scanner scanner(i::Isolate::Current()->unicode_cache()); 299 scanner.Initialize(&stream); 300 301 // Preparser defaults to disallowing natives syntax. 302 v8::preparser::PreParser preparser(&scanner, &log, stack_limit); 303 preparser.set_allow_lazy(true); 304 v8::preparser::PreParser::PreParseResult result = 305 preparser.PreParseProgram(); 306 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result); 307 i::ScriptDataImpl data(log.ExtractData()); 308 // Data contains syntax error. 309 CHECK(data.has_error()); 310 } 311 } 312 313 314 TEST(RegressChromium62639) { 315 v8::V8::Initialize(); 316 317 int marker; 318 i::Isolate::Current()->stack_guard()->SetStackLimit( 319 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 320 321 const char* program = "var x = 'something';\n" 322 "escape: function() {}"; 323 // Fails parsing expecting an identifier after "function". 324 // Before fix, didn't check *ok after Expect(Token::Identifier, ok), 325 // and then used the invalid currently scanned literal. This always 326 // failed in debug mode, and sometimes crashed in release mode. 327 328 i::Utf8ToUtf16CharacterStream stream( 329 reinterpret_cast<const i::byte*>(program), 330 static_cast<unsigned>(strlen(program))); 331 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream); 332 CHECK(data->HasError()); 333 delete data; 334 } 335 336 337 TEST(Regress928) { 338 v8::V8::Initialize(); 339 i::Isolate* isolate = i::Isolate::Current(); 340 i::Factory* factory = isolate->factory(); 341 342 // Preparsing didn't consider the catch clause of a try statement 343 // as with-content, which made it assume that a function inside 344 // the block could be lazily compiled, and an extra, unexpected, 345 // entry was added to the data. 346 int marker; 347 isolate->stack_guard()->SetStackLimit( 348 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 349 350 const char* program = 351 "try { } catch (e) { var foo = function () { /* first */ } }" 352 "var bar = function () { /* second */ }"; 353 354 v8::HandleScope handles(v8::Isolate::GetCurrent()); 355 i::Handle<i::String> source( 356 factory->NewStringFromAscii(i::CStrVector(program))); 357 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 358 i::ScriptDataImpl* data = i::PreParserApi::PreParse(&stream); 359 CHECK(!data->HasError()); 360 361 data->Initialize(); 362 363 int first_function = 364 static_cast<int>(strstr(program, "function") - program); 365 int first_lbrace = first_function + i::StrLength("function () "); 366 CHECK_EQ('{', program[first_lbrace]); 367 i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace); 368 CHECK(!entry1.is_valid()); 369 370 int second_function = 371 static_cast<int>(strstr(program + first_lbrace, "function") - program); 372 int second_lbrace = 373 second_function + i::StrLength("function () "); 374 CHECK_EQ('{', program[second_lbrace]); 375 i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace); 376 CHECK(entry2.is_valid()); 377 CHECK_EQ('}', program[entry2.end_pos() - 1]); 378 delete data; 379 } 380 381 382 TEST(PreParseOverflow) { 383 v8::V8::Initialize(); 384 385 int marker; 386 i::Isolate::Current()->stack_guard()->SetStackLimit( 387 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 388 389 size_t kProgramSize = 1024 * 1024; 390 i::SmartArrayPointer<char> program(i::NewArray<char>(kProgramSize + 1)); 391 memset(*program, '(', kProgramSize); 392 program[kProgramSize] = '\0'; 393 394 uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit(); 395 396 i::Utf8ToUtf16CharacterStream stream( 397 reinterpret_cast<const i::byte*>(*program), 398 static_cast<unsigned>(kProgramSize)); 399 i::CompleteParserRecorder log; 400 i::Scanner scanner(i::Isolate::Current()->unicode_cache()); 401 scanner.Initialize(&stream); 402 403 v8::preparser::PreParser preparser(&scanner, &log, stack_limit); 404 preparser.set_allow_lazy(true); 405 v8::preparser::PreParser::PreParseResult result = 406 preparser.PreParseProgram(); 407 CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result); 408 } 409 410 411 class TestExternalResource: public v8::String::ExternalStringResource { 412 public: 413 explicit TestExternalResource(uint16_t* data, int length) 414 : data_(data), length_(static_cast<size_t>(length)) { } 415 416 ~TestExternalResource() { } 417 418 const uint16_t* data() const { 419 return data_; 420 } 421 422 size_t length() const { 423 return length_; 424 } 425 private: 426 uint16_t* data_; 427 size_t length_; 428 }; 429 430 431 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2)) 432 433 void TestCharacterStream(const char* ascii_source, 434 unsigned length, 435 unsigned start = 0, 436 unsigned end = 0) { 437 if (end == 0) end = length; 438 unsigned sub_length = end - start; 439 i::Isolate* isolate = i::Isolate::Current(); 440 i::Factory* factory = isolate->factory(); 441 i::HandleScope test_scope(isolate); 442 i::SmartArrayPointer<i::uc16> uc16_buffer(new i::uc16[length]); 443 for (unsigned i = 0; i < length; i++) { 444 uc16_buffer[i] = static_cast<i::uc16>(ascii_source[i]); 445 } 446 i::Vector<const char> ascii_vector(ascii_source, static_cast<int>(length)); 447 i::Handle<i::String> ascii_string( 448 factory->NewStringFromAscii(ascii_vector)); 449 TestExternalResource resource(*uc16_buffer, length); 450 i::Handle<i::String> uc16_string( 451 factory->NewExternalStringFromTwoByte(&resource)); 452 453 i::ExternalTwoByteStringUtf16CharacterStream uc16_stream( 454 i::Handle<i::ExternalTwoByteString>::cast(uc16_string), start, end); 455 i::GenericStringUtf16CharacterStream string_stream(ascii_string, start, end); 456 i::Utf8ToUtf16CharacterStream utf8_stream( 457 reinterpret_cast<const i::byte*>(ascii_source), end); 458 utf8_stream.SeekForward(start); 459 460 unsigned i = start; 461 while (i < end) { 462 // Read streams one char at a time 463 CHECK_EQU(i, uc16_stream.pos()); 464 CHECK_EQU(i, string_stream.pos()); 465 CHECK_EQU(i, utf8_stream.pos()); 466 int32_t c0 = ascii_source[i]; 467 int32_t c1 = uc16_stream.Advance(); 468 int32_t c2 = string_stream.Advance(); 469 int32_t c3 = utf8_stream.Advance(); 470 i++; 471 CHECK_EQ(c0, c1); 472 CHECK_EQ(c0, c2); 473 CHECK_EQ(c0, c3); 474 CHECK_EQU(i, uc16_stream.pos()); 475 CHECK_EQU(i, string_stream.pos()); 476 CHECK_EQU(i, utf8_stream.pos()); 477 } 478 while (i > start + sub_length / 4) { 479 // Pushback, re-read, pushback again. 480 int32_t c0 = ascii_source[i - 1]; 481 CHECK_EQU(i, uc16_stream.pos()); 482 CHECK_EQU(i, string_stream.pos()); 483 CHECK_EQU(i, utf8_stream.pos()); 484 uc16_stream.PushBack(c0); 485 string_stream.PushBack(c0); 486 utf8_stream.PushBack(c0); 487 i--; 488 CHECK_EQU(i, uc16_stream.pos()); 489 CHECK_EQU(i, string_stream.pos()); 490 CHECK_EQU(i, utf8_stream.pos()); 491 int32_t c1 = uc16_stream.Advance(); 492 int32_t c2 = string_stream.Advance(); 493 int32_t c3 = utf8_stream.Advance(); 494 i++; 495 CHECK_EQU(i, uc16_stream.pos()); 496 CHECK_EQU(i, string_stream.pos()); 497 CHECK_EQU(i, utf8_stream.pos()); 498 CHECK_EQ(c0, c1); 499 CHECK_EQ(c0, c2); 500 CHECK_EQ(c0, c3); 501 uc16_stream.PushBack(c0); 502 string_stream.PushBack(c0); 503 utf8_stream.PushBack(c0); 504 i--; 505 CHECK_EQU(i, uc16_stream.pos()); 506 CHECK_EQU(i, string_stream.pos()); 507 CHECK_EQU(i, utf8_stream.pos()); 508 } 509 unsigned halfway = start + sub_length / 2; 510 uc16_stream.SeekForward(halfway - i); 511 string_stream.SeekForward(halfway - i); 512 utf8_stream.SeekForward(halfway - i); 513 i = halfway; 514 CHECK_EQU(i, uc16_stream.pos()); 515 CHECK_EQU(i, string_stream.pos()); 516 CHECK_EQU(i, utf8_stream.pos()); 517 518 while (i < end) { 519 // Read streams one char at a time 520 CHECK_EQU(i, uc16_stream.pos()); 521 CHECK_EQU(i, string_stream.pos()); 522 CHECK_EQU(i, utf8_stream.pos()); 523 int32_t c0 = ascii_source[i]; 524 int32_t c1 = uc16_stream.Advance(); 525 int32_t c2 = string_stream.Advance(); 526 int32_t c3 = utf8_stream.Advance(); 527 i++; 528 CHECK_EQ(c0, c1); 529 CHECK_EQ(c0, c2); 530 CHECK_EQ(c0, c3); 531 CHECK_EQU(i, uc16_stream.pos()); 532 CHECK_EQU(i, string_stream.pos()); 533 CHECK_EQU(i, utf8_stream.pos()); 534 } 535 536 int32_t c1 = uc16_stream.Advance(); 537 int32_t c2 = string_stream.Advance(); 538 int32_t c3 = utf8_stream.Advance(); 539 CHECK_LT(c1, 0); 540 CHECK_LT(c2, 0); 541 CHECK_LT(c3, 0); 542 } 543 544 545 TEST(CharacterStreams) { 546 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 547 v8::HandleScope handles(isolate); 548 v8::Local<v8::Context> context = v8::Context::New(isolate); 549 v8::Context::Scope context_scope(context); 550 551 TestCharacterStream("abc\0\n\r\x7f", 7); 552 static const unsigned kBigStringSize = 4096; 553 char buffer[kBigStringSize + 1]; 554 for (unsigned i = 0; i < kBigStringSize; i++) { 555 buffer[i] = static_cast<char>(i & 0x7f); 556 } 557 TestCharacterStream(buffer, kBigStringSize); 558 559 TestCharacterStream(buffer, kBigStringSize, 576, 3298); 560 561 TestCharacterStream("\0", 1); 562 TestCharacterStream("", 0); 563 } 564 565 566 TEST(Utf8CharacterStream) { 567 static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar; 568 static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU); 569 570 static const int kAllUtf8CharsSize = 571 (unibrow::Utf8::kMaxOneByteChar + 1) + 572 (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 + 573 (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3; 574 static const unsigned kAllUtf8CharsSizeU = 575 static_cast<unsigned>(kAllUtf8CharsSize); 576 577 char buffer[kAllUtf8CharsSizeU]; 578 unsigned cursor = 0; 579 for (int i = 0; i <= kMaxUC16Char; i++) { 580 cursor += unibrow::Utf8::Encode(buffer + cursor, 581 i, 582 unibrow::Utf16::kNoPreviousCharacter); 583 } 584 ASSERT(cursor == kAllUtf8CharsSizeU); 585 586 i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer), 587 kAllUtf8CharsSizeU); 588 for (int i = 0; i <= kMaxUC16Char; i++) { 589 CHECK_EQU(i, stream.pos()); 590 int32_t c = stream.Advance(); 591 CHECK_EQ(i, c); 592 CHECK_EQU(i + 1, stream.pos()); 593 } 594 for (int i = kMaxUC16Char; i >= 0; i--) { 595 CHECK_EQU(i + 1, stream.pos()); 596 stream.PushBack(i); 597 CHECK_EQU(i, stream.pos()); 598 } 599 int i = 0; 600 while (stream.pos() < kMaxUC16CharU) { 601 CHECK_EQU(i, stream.pos()); 602 unsigned progress = stream.SeekForward(12); 603 i += progress; 604 int32_t c = stream.Advance(); 605 if (i <= kMaxUC16Char) { 606 CHECK_EQ(i, c); 607 } else { 608 CHECK_EQ(-1, c); 609 } 610 i += 1; 611 CHECK_EQU(i, stream.pos()); 612 } 613 } 614 615 #undef CHECK_EQU 616 617 void TestStreamScanner(i::Utf16CharacterStream* stream, 618 i::Token::Value* expected_tokens, 619 int skip_pos = 0, // Zero means not skipping. 620 int skip_to = 0) { 621 i::Scanner scanner(i::Isolate::Current()->unicode_cache()); 622 scanner.Initialize(stream); 623 624 int i = 0; 625 do { 626 i::Token::Value expected = expected_tokens[i]; 627 i::Token::Value actual = scanner.Next(); 628 CHECK_EQ(i::Token::String(expected), i::Token::String(actual)); 629 if (scanner.location().end_pos == skip_pos) { 630 scanner.SeekForward(skip_to); 631 } 632 i++; 633 } while (expected_tokens[i] != i::Token::ILLEGAL); 634 } 635 636 637 TEST(StreamScanner) { 638 v8::V8::Initialize(); 639 640 const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib"; 641 i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1), 642 static_cast<unsigned>(strlen(str1))); 643 i::Token::Value expectations1[] = { 644 i::Token::LBRACE, 645 i::Token::IDENTIFIER, 646 i::Token::IDENTIFIER, 647 i::Token::FOR, 648 i::Token::COLON, 649 i::Token::MUL, 650 i::Token::DIV, 651 i::Token::LT, 652 i::Token::SUB, 653 i::Token::IDENTIFIER, 654 i::Token::EOS, 655 i::Token::ILLEGAL 656 }; 657 TestStreamScanner(&stream1, expectations1, 0, 0); 658 659 const char* str2 = "case default const {THIS\nPART\nSKIPPED} do"; 660 i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2), 661 static_cast<unsigned>(strlen(str2))); 662 i::Token::Value expectations2[] = { 663 i::Token::CASE, 664 i::Token::DEFAULT, 665 i::Token::CONST, 666 i::Token::LBRACE, 667 // Skipped part here 668 i::Token::RBRACE, 669 i::Token::DO, 670 i::Token::EOS, 671 i::Token::ILLEGAL 672 }; 673 ASSERT_EQ('{', str2[19]); 674 ASSERT_EQ('}', str2[37]); 675 TestStreamScanner(&stream2, expectations2, 20, 37); 676 677 const char* str3 = "{}}}}"; 678 i::Token::Value expectations3[] = { 679 i::Token::LBRACE, 680 i::Token::RBRACE, 681 i::Token::RBRACE, 682 i::Token::RBRACE, 683 i::Token::RBRACE, 684 i::Token::EOS, 685 i::Token::ILLEGAL 686 }; 687 // Skip zero-four RBRACEs. 688 for (int i = 0; i <= 4; i++) { 689 expectations3[6 - i] = i::Token::ILLEGAL; 690 expectations3[5 - i] = i::Token::EOS; 691 i::Utf8ToUtf16CharacterStream stream3( 692 reinterpret_cast<const i::byte*>(str3), 693 static_cast<unsigned>(strlen(str3))); 694 TestStreamScanner(&stream3, expectations3, 1, 1 + i); 695 } 696 } 697 698 699 void TestScanRegExp(const char* re_source, const char* expected) { 700 i::Utf8ToUtf16CharacterStream stream( 701 reinterpret_cast<const i::byte*>(re_source), 702 static_cast<unsigned>(strlen(re_source))); 703 i::Scanner scanner(i::Isolate::Current()->unicode_cache()); 704 scanner.Initialize(&stream); 705 706 i::Token::Value start = scanner.peek(); 707 CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV); 708 CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV)); 709 scanner.Next(); // Current token is now the regexp literal. 710 CHECK(scanner.is_literal_ascii()); 711 i::Vector<const char> actual = scanner.literal_ascii_string(); 712 for (int i = 0; i < actual.length(); i++) { 713 CHECK_NE('\0', expected[i]); 714 CHECK_EQ(expected[i], actual[i]); 715 } 716 } 717 718 719 TEST(RegExpScanning) { 720 v8::V8::Initialize(); 721 722 // RegExp token with added garbage at the end. The scanner should only 723 // scan the RegExp until the terminating slash just before "flipperwald". 724 TestScanRegExp("/b/flipperwald", "b"); 725 // Incomplete escape sequences doesn't hide the terminating slash. 726 TestScanRegExp("/\\x/flipperwald", "\\x"); 727 TestScanRegExp("/\\u/flipperwald", "\\u"); 728 TestScanRegExp("/\\u1/flipperwald", "\\u1"); 729 TestScanRegExp("/\\u12/flipperwald", "\\u12"); 730 TestScanRegExp("/\\u123/flipperwald", "\\u123"); 731 TestScanRegExp("/\\c/flipperwald", "\\c"); 732 TestScanRegExp("/\\c//flipperwald", "\\c"); 733 // Slashes inside character classes are not terminating. 734 TestScanRegExp("/[/]/flipperwald", "[/]"); 735 TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]"); 736 // Incomplete escape sequences inside a character class doesn't hide 737 // the end of the character class. 738 TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]"); 739 TestScanRegExp("/[\\c]/flipperwald", "[\\c]"); 740 TestScanRegExp("/[\\x]/flipperwald", "[\\x]"); 741 TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]"); 742 TestScanRegExp("/[\\u]/flipperwald", "[\\u]"); 743 TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]"); 744 TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]"); 745 TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]"); 746 // Escaped ']'s wont end the character class. 747 TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]"); 748 // Escaped slashes are not terminating. 749 TestScanRegExp("/\\//flipperwald", "\\/"); 750 // Starting with '=' works too. 751 TestScanRegExp("/=/", "="); 752 TestScanRegExp("/=?/", "=?"); 753 } 754 755 756 static int Utf8LengthHelper(const char* s) { 757 int len = i::StrLength(s); 758 int character_length = len; 759 for (int i = 0; i < len; i++) { 760 unsigned char c = s[i]; 761 int input_offset = 0; 762 int output_adjust = 0; 763 if (c > 0x7f) { 764 if (c < 0xc0) continue; 765 if (c >= 0xf0) { 766 if (c >= 0xf8) { 767 // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8 768 // byte. 769 continue; // Handle first UTF-8 byte. 770 } 771 if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) { 772 // This 4 byte sequence could have been coded as a 3 byte sequence. 773 // Record a single kBadChar for the first byte and continue. 774 continue; 775 } 776 input_offset = 3; 777 // 4 bytes of UTF-8 turn into 2 UTF-16 code units. 778 character_length -= 2; 779 } else if (c >= 0xe0) { 780 if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) { 781 // This 3 byte sequence could have been coded as a 2 byte sequence. 782 // Record a single kBadChar for the first byte and continue. 783 continue; 784 } 785 input_offset = 2; 786 // 3 bytes of UTF-8 turn into 1 UTF-16 code unit. 787 output_adjust = 2; 788 } else { 789 if ((c & 0x1e) == 0) { 790 // This 2 byte sequence could have been coded as a 1 byte sequence. 791 // Record a single kBadChar for the first byte and continue. 792 continue; 793 } 794 input_offset = 1; 795 // 2 bytes of UTF-8 turn into 1 UTF-16 code unit. 796 output_adjust = 1; 797 } 798 bool bad = false; 799 for (int j = 1; j <= input_offset; j++) { 800 if ((s[i + j] & 0xc0) != 0x80) { 801 // Bad UTF-8 sequence turns the first in the sequence into kBadChar, 802 // which is a single UTF-16 code unit. 803 bad = true; 804 break; 805 } 806 } 807 if (!bad) { 808 i += input_offset; 809 character_length -= output_adjust; 810 } 811 } 812 } 813 return character_length; 814 } 815 816 817 TEST(ScopePositions) { 818 // Test the parser for correctly setting the start and end positions 819 // of a scope. We check the scope positions of exactly one scope 820 // nested in the global scope of a program. 'inner source' is the 821 // source code that determines the part of the source belonging 822 // to the nested scope. 'outer_prefix' and 'outer_suffix' are 823 // parts of the source that belong to the global scope. 824 struct SourceData { 825 const char* outer_prefix; 826 const char* inner_source; 827 const char* outer_suffix; 828 i::ScopeType scope_type; 829 i::LanguageMode language_mode; 830 }; 831 832 const SourceData source_data[] = { 833 { " with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 834 { " with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 835 { " with ({}) ", "{\n" 836 " block;\n" 837 " }", "\n" 838 " more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 839 { " with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 840 { " with ({}) ", "statement", "\n" 841 " more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 842 { " with ({})\n" 843 " ", "statement;", "\n" 844 " more;", i::WITH_SCOPE, i::CLASSIC_MODE }, 845 { " try {} catch ", "(e) { block; }", " more;", 846 i::CATCH_SCOPE, i::CLASSIC_MODE }, 847 { " try {} catch ", "(e) { block; }", "; more;", 848 i::CATCH_SCOPE, i::CLASSIC_MODE }, 849 { " try {} catch ", "(e) {\n" 850 " block;\n" 851 " }", "\n" 852 " more;", i::CATCH_SCOPE, i::CLASSIC_MODE }, 853 { " try {} catch ", "(e) { block; }", " finally { block; } more;", 854 i::CATCH_SCOPE, i::CLASSIC_MODE }, 855 { " start;\n" 856 " ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 857 { " start;\n" 858 " ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 859 { " start;\n" 860 " ", "{\n" 861 " let block;\n" 862 " }", "\n" 863 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 864 { " start;\n" 865 " function fun", "(a,b) { infunction; }", " more;", 866 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 867 { " start;\n" 868 " function fun", "(a,b) {\n" 869 " infunction;\n" 870 " }", "\n" 871 " more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 872 { " (function fun", "(a,b) { infunction; }", ")();", 873 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 874 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;", 875 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 876 { " for ", "(let x = 1 ; x < 10; ++ x) { block; }", "; more;", 877 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 878 { " for ", "(let x = 1 ; x < 10; ++ x) {\n" 879 " block;\n" 880 " }", "\n" 881 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 882 { " for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;", 883 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 884 { " for ", "(let x = 1 ; x < 10; ++ x) statement", "\n" 885 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 886 { " for ", "(let x = 1 ; x < 10; ++ x)\n" 887 " statement;", "\n" 888 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 889 { " for ", "(let x in {}) { block; }", " more;", 890 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 891 { " for ", "(let x in {}) { block; }", "; more;", 892 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 893 { " for ", "(let x in {}) {\n" 894 " block;\n" 895 " }", "\n" 896 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 897 { " for ", "(let x in {}) statement;", " more;", 898 i::BLOCK_SCOPE, i::EXTENDED_MODE }, 899 { " for ", "(let x in {}) statement", "\n" 900 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 901 { " for ", "(let x in {})\n" 902 " statement;", "\n" 903 " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE }, 904 // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw 905 // the preparser off in terms of byte offsets. 906 // 6 byte encoding. 907 { " 'foo\355\240\201\355\260\211';\n" 908 " (function fun", "(a,b) { infunction; }", ")();", 909 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 910 // 4 byte encoding. 911 { " 'foo\360\220\220\212';\n" 912 " (function fun", "(a,b) { infunction; }", ")();", 913 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 914 // 3 byte encoding of \u0fff. 915 { " 'foo\340\277\277';\n" 916 " (function fun", "(a,b) { infunction; }", ")();", 917 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 918 // Broken 6 byte encoding with missing last byte. 919 { " 'foo\355\240\201\355\211';\n" 920 " (function fun", "(a,b) { infunction; }", ")();", 921 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 922 // Broken 3 byte encoding of \u0fff with missing last byte. 923 { " 'foo\340\277';\n" 924 " (function fun", "(a,b) { infunction; }", ")();", 925 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 926 // Broken 3 byte encoding of \u0fff with missing 2 last bytes. 927 { " 'foo\340';\n" 928 " (function fun", "(a,b) { infunction; }", ")();", 929 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 930 // Broken 3 byte encoding of \u00ff should be a 2 byte encoding. 931 { " 'foo\340\203\277';\n" 932 " (function fun", "(a,b) { infunction; }", ")();", 933 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 934 // Broken 3 byte encoding of \u007f should be a 2 byte encoding. 935 { " 'foo\340\201\277';\n" 936 " (function fun", "(a,b) { infunction; }", ")();", 937 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 938 // Unpaired lead surrogate. 939 { " 'foo\355\240\201';\n" 940 " (function fun", "(a,b) { infunction; }", ")();", 941 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 942 // Unpaired lead surrogate where following code point is a 3 byte sequence. 943 { " 'foo\355\240\201\340\277\277';\n" 944 " (function fun", "(a,b) { infunction; }", ")();", 945 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 946 // Unpaired lead surrogate where following code point is a 4 byte encoding 947 // of a trail surrogate. 948 { " 'foo\355\240\201\360\215\260\211';\n" 949 " (function fun", "(a,b) { infunction; }", ")();", 950 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 951 // Unpaired trail surrogate. 952 { " 'foo\355\260\211';\n" 953 " (function fun", "(a,b) { infunction; }", ")();", 954 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 955 // 2 byte encoding of \u00ff. 956 { " 'foo\303\277';\n" 957 " (function fun", "(a,b) { infunction; }", ")();", 958 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 959 // Broken 2 byte encoding of \u00ff with missing last byte. 960 { " 'foo\303';\n" 961 " (function fun", "(a,b) { infunction; }", ")();", 962 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 963 // Broken 2 byte encoding of \u007f should be a 1 byte encoding. 964 { " 'foo\301\277';\n" 965 " (function fun", "(a,b) { infunction; }", ")();", 966 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 967 // Illegal 5 byte encoding. 968 { " 'foo\370\277\277\277\277';\n" 969 " (function fun", "(a,b) { infunction; }", ")();", 970 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 971 // Illegal 6 byte encoding. 972 { " 'foo\374\277\277\277\277\277';\n" 973 " (function fun", "(a,b) { infunction; }", ")();", 974 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 975 // Illegal 0xfe byte 976 { " 'foo\376\277\277\277\277\277\277';\n" 977 " (function fun", "(a,b) { infunction; }", ")();", 978 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 979 // Illegal 0xff byte 980 { " 'foo\377\277\277\277\277\277\277\277';\n" 981 " (function fun", "(a,b) { infunction; }", ")();", 982 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 983 { " 'foo';\n" 984 " (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();", 985 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 986 { " 'foo';\n" 987 " (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();", 988 i::FUNCTION_SCOPE, i::CLASSIC_MODE }, 989 { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE } 990 }; 991 992 i::Isolate* isolate = i::Isolate::Current(); 993 i::Factory* factory = isolate->factory(); 994 995 v8::HandleScope handles(v8::Isolate::GetCurrent()); 996 v8::Handle<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent()); 997 v8::Context::Scope context_scope(context); 998 999 int marker; 1000 isolate->stack_guard()->SetStackLimit( 1001 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1002 1003 for (int i = 0; source_data[i].outer_prefix; i++) { 1004 int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix); 1005 int kInnerLen = Utf8LengthHelper(source_data[i].inner_source); 1006 int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix); 1007 int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix); 1008 int kInnerByteLen = i::StrLength(source_data[i].inner_source); 1009 int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix); 1010 int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen; 1011 int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen; 1012 i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1); 1013 i::OS::SNPrintF(program, "%s%s%s", 1014 source_data[i].outer_prefix, 1015 source_data[i].inner_source, 1016 source_data[i].outer_suffix); 1017 1018 // Parse program source. 1019 i::Handle<i::String> source( 1020 factory->NewStringFromUtf8(i::CStrVector(program.start()))); 1021 CHECK_EQ(source->length(), kProgramSize); 1022 i::Handle<i::Script> script = factory->NewScript(source); 1023 i::CompilationInfoWithZone info(script); 1024 i::Parser parser(&info); 1025 parser.set_allow_lazy(true); 1026 parser.set_allow_harmony_scoping(true); 1027 info.MarkAsGlobal(); 1028 info.SetLanguageMode(source_data[i].language_mode); 1029 i::FunctionLiteral* function = parser.ParseProgram(); 1030 CHECK(function != NULL); 1031 1032 // Check scope types and positions. 1033 i::Scope* scope = function->scope(); 1034 CHECK(scope->is_global_scope()); 1035 CHECK_EQ(scope->start_position(), 0); 1036 CHECK_EQ(scope->end_position(), kProgramSize); 1037 CHECK_EQ(scope->inner_scopes()->length(), 1); 1038 1039 i::Scope* inner_scope = scope->inner_scopes()->at(0); 1040 CHECK_EQ(inner_scope->scope_type(), source_data[i].scope_type); 1041 CHECK_EQ(inner_scope->start_position(), kPrefixLen); 1042 // The end position of a token is one position after the last 1043 // character belonging to that token. 1044 CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen); 1045 } 1046 } 1047 1048 1049 i::Handle<i::String> FormatMessage(i::ScriptDataImpl* data) { 1050 i::Isolate* isolate = i::Isolate::Current(); 1051 i::Factory* factory = isolate->factory(); 1052 const char* message = data->BuildMessage(); 1053 i::Handle<i::String> format = v8::Utils::OpenHandle( 1054 *v8::String::New(message)); 1055 i::Vector<const char*> args = data->BuildArgs(); 1056 i::Handle<i::JSArray> args_array = factory->NewJSArray(args.length()); 1057 for (int i = 0; i < args.length(); i++) { 1058 i::JSArray::SetElement(args_array, 1059 i, 1060 v8::Utils::OpenHandle(*v8::String::New(args[i])), 1061 NONE, 1062 i::kNonStrictMode); 1063 } 1064 i::Handle<i::JSObject> builtins(isolate->js_builtins_object()); 1065 i::Handle<i::Object> format_fun = 1066 i::GetProperty(builtins, "FormatMessage"); 1067 i::Handle<i::Object> arg_handles[] = { format, args_array }; 1068 bool has_exception = false; 1069 i::Handle<i::Object> result = 1070 i::Execution::Call(format_fun, builtins, 2, arg_handles, &has_exception); 1071 CHECK(!has_exception); 1072 CHECK(result->IsString()); 1073 for (int i = 0; i < args.length(); i++) { 1074 i::DeleteArray(args[i]); 1075 } 1076 i::DeleteArray(args.start()); 1077 i::DeleteArray(message); 1078 return i::Handle<i::String>::cast(result); 1079 } 1080 1081 1082 enum ParserFlag { 1083 kAllowLazy, 1084 kAllowNativesSyntax, 1085 kAllowHarmonyScoping, 1086 kAllowModules, 1087 kAllowGenerators, 1088 kAllowForOf, 1089 kAllowHarmonyNumericLiterals, 1090 kParserFlagCount 1091 }; 1092 1093 1094 static bool checkParserFlag(unsigned flags, ParserFlag flag) { 1095 return flags & (1 << flag); 1096 } 1097 1098 1099 #define SET_PARSER_FLAGS(parser, flags) \ 1100 parser.set_allow_lazy(checkParserFlag(flags, kAllowLazy)); \ 1101 parser.set_allow_natives_syntax(checkParserFlag(flags, \ 1102 kAllowNativesSyntax)); \ 1103 parser.set_allow_harmony_scoping(checkParserFlag(flags, \ 1104 kAllowHarmonyScoping)); \ 1105 parser.set_allow_modules(checkParserFlag(flags, kAllowModules)); \ 1106 parser.set_allow_generators(checkParserFlag(flags, kAllowGenerators)); \ 1107 parser.set_allow_for_of(checkParserFlag(flags, kAllowForOf)); \ 1108 parser.set_allow_harmony_numeric_literals( \ 1109 checkParserFlag(flags, kAllowHarmonyNumericLiterals)); 1110 1111 void TestParserSyncWithFlags(i::Handle<i::String> source, unsigned flags) { 1112 i::Isolate* isolate = i::Isolate::Current(); 1113 i::Factory* factory = isolate->factory(); 1114 1115 uintptr_t stack_limit = isolate->stack_guard()->real_climit(); 1116 1117 // Preparse the data. 1118 i::CompleteParserRecorder log; 1119 { 1120 i::Scanner scanner(isolate->unicode_cache()); 1121 i::GenericStringUtf16CharacterStream stream(source, 0, source->length()); 1122 v8::preparser::PreParser preparser(&scanner, &log, stack_limit); 1123 SET_PARSER_FLAGS(preparser, flags); 1124 scanner.Initialize(&stream); 1125 v8::preparser::PreParser::PreParseResult result = 1126 preparser.PreParseProgram(); 1127 CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result); 1128 } 1129 i::ScriptDataImpl data(log.ExtractData()); 1130 1131 // Parse the data 1132 i::FunctionLiteral* function; 1133 { 1134 i::Handle<i::Script> script = factory->NewScript(source); 1135 i::CompilationInfoWithZone info(script); 1136 i::Parser parser(&info); 1137 SET_PARSER_FLAGS(parser, flags); 1138 info.MarkAsGlobal(); 1139 function = parser.ParseProgram(); 1140 } 1141 1142 // Check that preparsing fails iff parsing fails. 1143 if (function == NULL) { 1144 // Extract exception from the parser. 1145 CHECK(isolate->has_pending_exception()); 1146 i::MaybeObject* maybe_object = isolate->pending_exception(); 1147 i::JSObject* exception = NULL; 1148 CHECK(maybe_object->To(&exception)); 1149 i::Handle<i::JSObject> exception_handle(exception); 1150 i::Handle<i::String> message_string = 1151 i::Handle<i::String>::cast(i::GetProperty(exception_handle, "message")); 1152 1153 if (!data.has_error()) { 1154 i::OS::Print( 1155 "Parser failed on:\n" 1156 "\t%s\n" 1157 "with error:\n" 1158 "\t%s\n" 1159 "However, the preparser succeeded", 1160 *source->ToCString(), *message_string->ToCString()); 1161 CHECK(false); 1162 } 1163 // Check that preparser and parser produce the same error. 1164 i::Handle<i::String> preparser_message = FormatMessage(&data); 1165 if (!message_string->Equals(*preparser_message)) { 1166 i::OS::Print( 1167 "Expected parser and preparser to produce the same error on:\n" 1168 "\t%s\n" 1169 "However, found the following error messages\n" 1170 "\tparser: %s\n" 1171 "\tpreparser: %s\n", 1172 *source->ToCString(), 1173 *message_string->ToCString(), 1174 *preparser_message->ToCString()); 1175 CHECK(false); 1176 } 1177 } else if (data.has_error()) { 1178 i::OS::Print( 1179 "Preparser failed on:\n" 1180 "\t%s\n" 1181 "with error:\n" 1182 "\t%s\n" 1183 "However, the parser succeeded", 1184 *source->ToCString(), *FormatMessage(&data)->ToCString()); 1185 CHECK(false); 1186 } 1187 } 1188 1189 1190 void TestParserSync(i::Handle<i::String> source) { 1191 for (unsigned flags = 0; flags < (1 << kParserFlagCount); ++flags) { 1192 TestParserSyncWithFlags(source, flags); 1193 } 1194 } 1195 1196 1197 TEST(ParserSync) { 1198 const char* context_data[][2] = { 1199 { "", "" }, 1200 { "{", "}" }, 1201 { "if (true) ", " else {}" }, 1202 { "if (true) {} else ", "" }, 1203 { "if (true) ", "" }, 1204 { "do ", " while (false)" }, 1205 { "while (false) ", "" }, 1206 { "for (;;) ", "" }, 1207 { "with ({})", "" }, 1208 { "switch (12) { case 12: ", "}" }, 1209 { "switch (12) { default: ", "}" }, 1210 { "switch (12) { ", "case 12: }" }, 1211 { "label2: ", "" }, 1212 { NULL, NULL } 1213 }; 1214 1215 const char* statement_data[] = { 1216 "{}", 1217 "var x", 1218 "var x = 1", 1219 "const x", 1220 "const x = 1", 1221 ";", 1222 "12", 1223 "if (false) {} else ;", 1224 "if (false) {} else {}", 1225 "if (false) {} else 12", 1226 "if (false) ;" 1227 "if (false) {}", 1228 "if (false) 12", 1229 "do {} while (false)", 1230 "for (;;) ;", 1231 "for (;;) {}", 1232 "for (;;) 12", 1233 "continue", 1234 "continue label", 1235 "continue\nlabel", 1236 "break", 1237 "break label", 1238 "break\nlabel", 1239 "return", 1240 "return 12", 1241 "return\n12", 1242 "with ({}) ;", 1243 "with ({}) {}", 1244 "with ({}) 12", 1245 "switch ({}) { default: }" 1246 "label3: " 1247 "throw", 1248 "throw 12", 1249 "throw\n12", 1250 "try {} catch(e) {}", 1251 "try {} finally {}", 1252 "try {} catch(e) {} finally {}", 1253 "debugger", 1254 NULL 1255 }; 1256 1257 const char* termination_data[] = { 1258 "", 1259 ";", 1260 "\n", 1261 ";\n", 1262 "\n;", 1263 NULL 1264 }; 1265 1266 // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the 1267 // correct timeout for this and re-enable this test again. 1268 if (i::FLAG_stress_compaction) return; 1269 1270 i::Isolate* isolate = i::Isolate::Current(); 1271 i::Factory* factory = isolate->factory(); 1272 1273 v8::HandleScope handles(v8::Isolate::GetCurrent()); 1274 v8::Handle<v8::Context> context = v8::Context::New(v8::Isolate::GetCurrent()); 1275 v8::Context::Scope context_scope(context); 1276 1277 int marker; 1278 isolate->stack_guard()->SetStackLimit( 1279 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024); 1280 1281 for (int i = 0; context_data[i][0] != NULL; ++i) { 1282 for (int j = 0; statement_data[j] != NULL; ++j) { 1283 for (int k = 0; termination_data[k] != NULL; ++k) { 1284 int kPrefixLen = i::StrLength(context_data[i][0]); 1285 int kStatementLen = i::StrLength(statement_data[j]); 1286 int kTerminationLen = i::StrLength(termination_data[k]); 1287 int kSuffixLen = i::StrLength(context_data[i][1]); 1288 int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen 1289 + kSuffixLen + i::StrLength("label: for (;;) { }"); 1290 1291 // Plug the source code pieces together. 1292 i::ScopedVector<char> program(kProgramSize + 1); 1293 int length = i::OS::SNPrintF(program, 1294 "label: for (;;) { %s%s%s%s }", 1295 context_data[i][0], 1296 statement_data[j], 1297 termination_data[k], 1298 context_data[i][1]); 1299 CHECK(length == kProgramSize); 1300 i::Handle<i::String> source = 1301 factory->NewStringFromAscii(i::CStrVector(program.start())); 1302 TestParserSync(source); 1303 } 1304 } 1305 } 1306 } 1307 1308 1309 TEST(PreparserStrictOctal) { 1310 // Test that syntax error caused by octal literal is reported correctly as 1311 // such (issue 2220). 1312 v8::internal::FLAG_min_preparse_length = 1; // Force preparsing. 1313 v8::V8::Initialize(); 1314 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1315 v8::Context::Scope context_scope( 1316 v8::Context::New(v8::Isolate::GetCurrent())); 1317 v8::TryCatch try_catch; 1318 const char* script = 1319 "\"use strict\"; \n" 1320 "a = function() { \n" 1321 " b = function() { \n" 1322 " 01; \n" 1323 " }; \n" 1324 "}; \n"; 1325 v8::Script::Compile(v8::String::New(script)); 1326 CHECK(try_catch.HasCaught()); 1327 v8::String::Utf8Value exception(try_catch.Exception()); 1328 CHECK_EQ("SyntaxError: Octal literals are not allowed in strict mode.", 1329 *exception); 1330 } 1331