Home | History | Annotate | Download | only in cctest
      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