• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
TEST(ScanKeywords)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       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       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 
TEST(ScanHTMLEndComments)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:
ScriptResource(const char * data,size_t length)163   ScriptResource(const char* data, size_t length)
164       : data_(data), length_(length) { }
165 
data() const166   const char* data() const { return data_; }
length() const167   size_t length() const { return length_; }
168 
169  private:
170   const char* data_;
171   size_t length_;
172 };
173 
174 
TEST(Preparsing)175 TEST(Preparsing) {
176   v8::HandleScope handles;
177   v8::Persistent<v8::Context> context = v8::Context::New();
178   v8::Context::Scope context_scope(context);
179   int marker;
180   i::Isolate::Current()->stack_guard()->SetStackLimit(
181       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
182 
183   // Source containing functions that might be lazily compiled  and all types
184   // of symbols (string, propertyName, regexp).
185   const char* source =
186       "var x = 42;"
187       "function foo(a) { return function nolazy(b) { return a + b; } }"
188       "function bar(a) { if (a) return function lazy(b) { return b; } }"
189       "var z = {'string': 'string literal', bareword: 'propertyName', "
190       "         42: 'number literal', for: 'keyword as propertyName', "
191       "         f\\u006fr: 'keyword propertyname with escape'};"
192       "var v = /RegExp Literal/;"
193       "var w = /RegExp Literal\\u0020With Escape/gin;"
194       "var y = { get getter() { return 42; }, "
195       "          set setter(v) { this.value = v; }};";
196   int source_length = i::StrLength(source);
197   const char* error_source = "var x = y z;";
198   int error_source_length = i::StrLength(error_source);
199 
200   v8::ScriptData* preparse =
201       v8::ScriptData::PreCompile(source, source_length);
202   CHECK(!preparse->HasError());
203   bool lazy_flag = i::FLAG_lazy;
204   {
205     i::FLAG_lazy = true;
206     ScriptResource* resource = new ScriptResource(source, source_length);
207     v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
208     v8::Script::Compile(script_source, NULL, preparse);
209   }
210 
211   {
212     i::FLAG_lazy = false;
213 
214     ScriptResource* resource = new ScriptResource(source, source_length);
215     v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
216     v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
217   }
218   delete preparse;
219   i::FLAG_lazy = lazy_flag;
220 
221   // Syntax error.
222   v8::ScriptData* error_preparse =
223       v8::ScriptData::PreCompile(error_source, error_source_length);
224   CHECK(error_preparse->HasError());
225   i::ScriptDataImpl *pre_impl =
226       reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
227   i::Scanner::Location error_location =
228       pre_impl->MessageLocation();
229   // Error is at "z" in source, location 10..11.
230   CHECK_EQ(10, error_location.beg_pos);
231   CHECK_EQ(11, error_location.end_pos);
232   // Should not crash.
233   const char* message = pre_impl->BuildMessage();
234   pre_impl->BuildArgs();
235   CHECK_GT(strlen(message), 0);
236 }
237 
238 
TEST(StandAlonePreParser)239 TEST(StandAlonePreParser) {
240   v8::V8::Initialize();
241 
242   int marker;
243   i::Isolate::Current()->stack_guard()->SetStackLimit(
244       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
245 
246   const char* programs[] = {
247       "{label: 42}",
248       "var x = 42;",
249       "function foo(x, y) { return x + y; }",
250       "%ArgleBargle(glop);",
251       "var x = new new Function('this.x = 42');",
252       NULL
253   };
254 
255   uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
256   for (int i = 0; programs[i]; i++) {
257     const char* program = programs[i];
258     i::Utf8ToUtf16CharacterStream stream(
259         reinterpret_cast<const i::byte*>(program),
260         static_cast<unsigned>(strlen(program)));
261     i::CompleteParserRecorder log;
262     i::Scanner scanner(i::Isolate::Current()->unicode_cache());
263     scanner.Initialize(&stream);
264 
265     int flags = i::kAllowLazy | i::kAllowNativesSyntax;
266     v8::preparser::PreParser::PreParseResult result =
267         v8::preparser::PreParser::PreParseProgram(&scanner,
268                                                   &log,
269                                                   flags,
270                                                   stack_limit);
271     CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
272     i::ScriptDataImpl data(log.ExtractData());
273     CHECK(!data.has_error());
274   }
275 }
276 
277 
TEST(StandAlonePreParserNoNatives)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     // Flags don't allow natives syntax.
302     v8::preparser::PreParser::PreParseResult result =
303         v8::preparser::PreParser::PreParseProgram(&scanner,
304                                                   &log,
305                                                   i::kAllowLazy,
306                                                   stack_limit);
307     CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
308     i::ScriptDataImpl data(log.ExtractData());
309     // Data contains syntax error.
310     CHECK(data.has_error());
311   }
312 }
313 
314 
TEST(RegressChromium62639)315 TEST(RegressChromium62639) {
316   v8::V8::Initialize();
317 
318   int marker;
319   i::Isolate::Current()->stack_guard()->SetStackLimit(
320       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
321 
322   const char* program = "var x = 'something';\n"
323                         "escape: function() {}";
324   // Fails parsing expecting an identifier after "function".
325   // Before fix, didn't check *ok after Expect(Token::Identifier, ok),
326   // and then used the invalid currently scanned literal. This always
327   // failed in debug mode, and sometimes crashed in release mode.
328 
329   i::Utf8ToUtf16CharacterStream stream(
330       reinterpret_cast<const i::byte*>(program),
331       static_cast<unsigned>(strlen(program)));
332   i::ScriptDataImpl* data =
333       i::ParserApi::PreParse(&stream, NULL, false);
334   CHECK(data->HasError());
335   delete data;
336 }
337 
338 
TEST(Regress928)339 TEST(Regress928) {
340   v8::V8::Initialize();
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   i::Isolate::Current()->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;
355   i::Handle<i::String> source(
356       FACTORY->NewStringFromAscii(i::CStrVector(program)));
357   i::ScriptDataImpl* data = i::ParserApi::PartialPreParse(source, NULL, false);
358   CHECK(!data->HasError());
359 
360   data->Initialize();
361 
362   int first_function =
363       static_cast<int>(strstr(program, "function") - program);
364   int first_lbrace = first_function + i::StrLength("function () ");
365   CHECK_EQ('{', program[first_lbrace]);
366   i::FunctionEntry entry1 = data->GetFunctionEntry(first_lbrace);
367   CHECK(!entry1.is_valid());
368 
369   int second_function =
370       static_cast<int>(strstr(program + first_lbrace, "function") - program);
371   int second_lbrace =
372       second_function + i::StrLength("function () ");
373   CHECK_EQ('{', program[second_lbrace]);
374   i::FunctionEntry entry2 = data->GetFunctionEntry(second_lbrace);
375   CHECK(entry2.is_valid());
376   CHECK_EQ('}', program[entry2.end_pos() - 1]);
377   delete data;
378 }
379 
380 
TEST(PreParseOverflow)381 TEST(PreParseOverflow) {
382   v8::V8::Initialize();
383 
384   int marker;
385   i::Isolate::Current()->stack_guard()->SetStackLimit(
386       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
387 
388   size_t kProgramSize = 1024 * 1024;
389   i::SmartArrayPointer<char> program(
390       reinterpret_cast<char*>(malloc(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 
404   v8::preparser::PreParser::PreParseResult result =
405       v8::preparser::PreParser::PreParseProgram(&scanner,
406                                                 &log,
407                                                 true,
408                                                 stack_limit);
409   CHECK_EQ(v8::preparser::PreParser::kPreParseStackOverflow, result);
410 }
411 
412 
413 class TestExternalResource: public v8::String::ExternalStringResource {
414  public:
TestExternalResource(uint16_t * data,int length)415   explicit TestExternalResource(uint16_t* data, int length)
416       : data_(data), length_(static_cast<size_t>(length)) { }
417 
~TestExternalResource()418   ~TestExternalResource() { }
419 
data() const420   const uint16_t* data() const {
421     return data_;
422   }
423 
length() const424   size_t length() const {
425     return length_;
426   }
427  private:
428   uint16_t* data_;
429   size_t length_;
430 };
431 
432 
433 #define CHECK_EQU(v1, v2) CHECK_EQ(static_cast<int>(v1), static_cast<int>(v2))
434 
TestCharacterStream(const char * ascii_source,unsigned length,unsigned start=0,unsigned end=0)435 void TestCharacterStream(const char* ascii_source,
436                          unsigned length,
437                          unsigned start = 0,
438                          unsigned end = 0) {
439   if (end == 0) end = length;
440   unsigned sub_length = end - start;
441   i::HandleScope test_scope;
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 
TEST(CharacterStreams)545 TEST(CharacterStreams) {
546   v8::HandleScope handles;
547   v8::Persistent<v8::Context> context = v8::Context::New();
548   v8::Context::Scope context_scope(context);
549 
550   TestCharacterStream("abc\0\n\r\x7f", 7);
551   static const unsigned kBigStringSize = 4096;
552   char buffer[kBigStringSize + 1];
553   for (unsigned i = 0; i < kBigStringSize; i++) {
554     buffer[i] = static_cast<char>(i & 0x7f);
555   }
556   TestCharacterStream(buffer, kBigStringSize);
557 
558   TestCharacterStream(buffer, kBigStringSize, 576, 3298);
559 
560   TestCharacterStream("\0", 1);
561   TestCharacterStream("", 0);
562 }
563 
564 
TEST(Utf8CharacterStream)565 TEST(Utf8CharacterStream) {
566   static const unsigned kMaxUC16CharU = unibrow::Utf8::kMaxThreeByteChar;
567   static const int kMaxUC16Char = static_cast<int>(kMaxUC16CharU);
568 
569   static const int kAllUtf8CharsSize =
570       (unibrow::Utf8::kMaxOneByteChar + 1) +
571       (unibrow::Utf8::kMaxTwoByteChar - unibrow::Utf8::kMaxOneByteChar) * 2 +
572       (unibrow::Utf8::kMaxThreeByteChar - unibrow::Utf8::kMaxTwoByteChar) * 3;
573   static const unsigned kAllUtf8CharsSizeU =
574       static_cast<unsigned>(kAllUtf8CharsSize);
575 
576   char buffer[kAllUtf8CharsSizeU];
577   unsigned cursor = 0;
578   for (int i = 0; i <= kMaxUC16Char; i++) {
579     cursor += unibrow::Utf8::Encode(buffer + cursor,
580                                     i,
581                                     unibrow::Utf16::kNoPreviousCharacter);
582   }
583   ASSERT(cursor == kAllUtf8CharsSizeU);
584 
585   i::Utf8ToUtf16CharacterStream stream(reinterpret_cast<const i::byte*>(buffer),
586                                        kAllUtf8CharsSizeU);
587   for (int i = 0; i <= kMaxUC16Char; i++) {
588     CHECK_EQU(i, stream.pos());
589     int32_t c = stream.Advance();
590     CHECK_EQ(i, c);
591     CHECK_EQU(i + 1, stream.pos());
592   }
593   for (int i = kMaxUC16Char; i >= 0; i--) {
594     CHECK_EQU(i + 1, stream.pos());
595     stream.PushBack(i);
596     CHECK_EQU(i, stream.pos());
597   }
598   int i = 0;
599   while (stream.pos() < kMaxUC16CharU) {
600     CHECK_EQU(i, stream.pos());
601     unsigned progress = stream.SeekForward(12);
602     i += progress;
603     int32_t c = stream.Advance();
604     if (i <= kMaxUC16Char) {
605       CHECK_EQ(i, c);
606     } else {
607       CHECK_EQ(-1, c);
608     }
609     i += 1;
610     CHECK_EQU(i, stream.pos());
611   }
612 }
613 
614 #undef CHECK_EQU
615 
TestStreamScanner(i::Utf16CharacterStream * stream,i::Token::Value * expected_tokens,int skip_pos=0,int skip_to=0)616 void TestStreamScanner(i::Utf16CharacterStream* stream,
617                        i::Token::Value* expected_tokens,
618                        int skip_pos = 0,  // Zero means not skipping.
619                        int skip_to = 0) {
620   i::Scanner scanner(i::Isolate::Current()->unicode_cache());
621   scanner.Initialize(stream);
622 
623   int i = 0;
624   do {
625     i::Token::Value expected = expected_tokens[i];
626     i::Token::Value actual = scanner.Next();
627     CHECK_EQ(i::Token::String(expected), i::Token::String(actual));
628     if (scanner.location().end_pos == skip_pos) {
629       scanner.SeekForward(skip_to);
630     }
631     i++;
632   } while (expected_tokens[i] != i::Token::ILLEGAL);
633 }
634 
TEST(StreamScanner)635 TEST(StreamScanner) {
636   v8::V8::Initialize();
637 
638   const char* str1 = "{ foo get for : */ <- \n\n /*foo*/ bib";
639   i::Utf8ToUtf16CharacterStream stream1(reinterpret_cast<const i::byte*>(str1),
640                                         static_cast<unsigned>(strlen(str1)));
641   i::Token::Value expectations1[] = {
642       i::Token::LBRACE,
643       i::Token::IDENTIFIER,
644       i::Token::IDENTIFIER,
645       i::Token::FOR,
646       i::Token::COLON,
647       i::Token::MUL,
648       i::Token::DIV,
649       i::Token::LT,
650       i::Token::SUB,
651       i::Token::IDENTIFIER,
652       i::Token::EOS,
653       i::Token::ILLEGAL
654   };
655   TestStreamScanner(&stream1, expectations1, 0, 0);
656 
657   const char* str2 = "case default const {THIS\nPART\nSKIPPED} do";
658   i::Utf8ToUtf16CharacterStream stream2(reinterpret_cast<const i::byte*>(str2),
659                                         static_cast<unsigned>(strlen(str2)));
660   i::Token::Value expectations2[] = {
661       i::Token::CASE,
662       i::Token::DEFAULT,
663       i::Token::CONST,
664       i::Token::LBRACE,
665       // Skipped part here
666       i::Token::RBRACE,
667       i::Token::DO,
668       i::Token::EOS,
669       i::Token::ILLEGAL
670   };
671   ASSERT_EQ('{', str2[19]);
672   ASSERT_EQ('}', str2[37]);
673   TestStreamScanner(&stream2, expectations2, 20, 37);
674 
675   const char* str3 = "{}}}}";
676   i::Token::Value expectations3[] = {
677       i::Token::LBRACE,
678       i::Token::RBRACE,
679       i::Token::RBRACE,
680       i::Token::RBRACE,
681       i::Token::RBRACE,
682       i::Token::EOS,
683       i::Token::ILLEGAL
684   };
685   // Skip zero-four RBRACEs.
686   for (int i = 0; i <= 4; i++) {
687      expectations3[6 - i] = i::Token::ILLEGAL;
688      expectations3[5 - i] = i::Token::EOS;
689      i::Utf8ToUtf16CharacterStream stream3(
690          reinterpret_cast<const i::byte*>(str3),
691          static_cast<unsigned>(strlen(str3)));
692      TestStreamScanner(&stream3, expectations3, 1, 1 + i);
693   }
694 }
695 
696 
TestScanRegExp(const char * re_source,const char * expected)697 void TestScanRegExp(const char* re_source, const char* expected) {
698   i::Utf8ToUtf16CharacterStream stream(
699        reinterpret_cast<const i::byte*>(re_source),
700        static_cast<unsigned>(strlen(re_source)));
701   i::Scanner scanner(i::Isolate::Current()->unicode_cache());
702   scanner.Initialize(&stream);
703 
704   i::Token::Value start = scanner.peek();
705   CHECK(start == i::Token::DIV || start == i::Token::ASSIGN_DIV);
706   CHECK(scanner.ScanRegExpPattern(start == i::Token::ASSIGN_DIV));
707   scanner.Next();  // Current token is now the regexp literal.
708   CHECK(scanner.is_literal_ascii());
709   i::Vector<const char> actual = scanner.literal_ascii_string();
710   for (int i = 0; i < actual.length(); i++) {
711     CHECK_NE('\0', expected[i]);
712     CHECK_EQ(expected[i], actual[i]);
713   }
714 }
715 
716 
TEST(RegExpScanning)717 TEST(RegExpScanning) {
718   v8::V8::Initialize();
719 
720   // RegExp token with added garbage at the end. The scanner should only
721   // scan the RegExp until the terminating slash just before "flipperwald".
722   TestScanRegExp("/b/flipperwald", "b");
723   // Incomplete escape sequences doesn't hide the terminating slash.
724   TestScanRegExp("/\\x/flipperwald", "\\x");
725   TestScanRegExp("/\\u/flipperwald", "\\u");
726   TestScanRegExp("/\\u1/flipperwald", "\\u1");
727   TestScanRegExp("/\\u12/flipperwald", "\\u12");
728   TestScanRegExp("/\\u123/flipperwald", "\\u123");
729   TestScanRegExp("/\\c/flipperwald", "\\c");
730   TestScanRegExp("/\\c//flipperwald", "\\c");
731   // Slashes inside character classes are not terminating.
732   TestScanRegExp("/[/]/flipperwald", "[/]");
733   TestScanRegExp("/[\\s-/]/flipperwald", "[\\s-/]");
734   // Incomplete escape sequences inside a character class doesn't hide
735   // the end of the character class.
736   TestScanRegExp("/[\\c/]/flipperwald", "[\\c/]");
737   TestScanRegExp("/[\\c]/flipperwald", "[\\c]");
738   TestScanRegExp("/[\\x]/flipperwald", "[\\x]");
739   TestScanRegExp("/[\\x1]/flipperwald", "[\\x1]");
740   TestScanRegExp("/[\\u]/flipperwald", "[\\u]");
741   TestScanRegExp("/[\\u1]/flipperwald", "[\\u1]");
742   TestScanRegExp("/[\\u12]/flipperwald", "[\\u12]");
743   TestScanRegExp("/[\\u123]/flipperwald", "[\\u123]");
744   // Escaped ']'s wont end the character class.
745   TestScanRegExp("/[\\]/]/flipperwald", "[\\]/]");
746   // Escaped slashes are not terminating.
747   TestScanRegExp("/\\//flipperwald", "\\/");
748   // Starting with '=' works too.
749   TestScanRegExp("/=/", "=");
750   TestScanRegExp("/=?/", "=?");
751 }
752 
753 
Utf8LengthHelper(const char * s)754 static int Utf8LengthHelper(const char* s) {
755   int len = i::StrLength(s);
756   int character_length = len;
757   for (int i = 0; i < len; i++) {
758     unsigned char c = s[i];
759     int input_offset = 0;
760     int output_adjust = 0;
761     if (c > 0x7f) {
762       if (c < 0xc0) continue;
763       if (c >= 0xf0) {
764         if (c >= 0xf8) {
765           // 5 and 6 byte UTF-8 sequences turn into a kBadChar for each UTF-8
766           // byte.
767           continue;  // Handle first UTF-8 byte.
768         }
769         if ((c & 7) == 0 && ((s[i + 1] & 0x30) == 0)) {
770           // This 4 byte sequence could have been coded as a 3 byte sequence.
771           // Record a single kBadChar for the first byte and continue.
772           continue;
773         }
774         input_offset = 3;
775         // 4 bytes of UTF-8 turn into 2 UTF-16 code units.
776         character_length -= 2;
777       } else if (c >= 0xe0) {
778         if ((c & 0xf) == 0 && ((s[i + 1] & 0x20) == 0)) {
779           // This 3 byte sequence could have been coded as a 2 byte sequence.
780           // Record a single kBadChar for the first byte and continue.
781           continue;
782         }
783         input_offset = 2;
784         // 3 bytes of UTF-8 turn into 1 UTF-16 code unit.
785         output_adjust = 2;
786       } else {
787         if ((c & 0x1e) == 0) {
788           // This 2 byte sequence could have been coded as a 1 byte sequence.
789           // Record a single kBadChar for the first byte and continue.
790           continue;
791         }
792         input_offset = 1;
793         // 2 bytes of UTF-8 turn into 1 UTF-16 code unit.
794         output_adjust = 1;
795       }
796       bool bad = false;
797       for (int j = 1; j <= input_offset; j++) {
798         if ((s[i + j] & 0xc0) != 0x80) {
799           // Bad UTF-8 sequence turns the first in the sequence into kBadChar,
800           // which is a single UTF-16 code unit.
801           bad = true;
802           break;
803         }
804       }
805       if (!bad) {
806         i += input_offset;
807         character_length -= output_adjust;
808       }
809     }
810   }
811   return character_length;
812 }
813 
814 
TEST(ScopePositions)815 TEST(ScopePositions) {
816   // Test the parser for correctly setting the start and end positions
817   // of a scope. We check the scope positions of exactly one scope
818   // nested in the global scope of a program. 'inner source' is the
819   // source code that determines the part of the source belonging
820   // to the nested scope. 'outer_prefix' and 'outer_suffix' are
821   // parts of the source that belong to the global scope.
822   struct SourceData {
823     const char* outer_prefix;
824     const char* inner_source;
825     const char* outer_suffix;
826     i::ScopeType scope_type;
827     i::LanguageMode language_mode;
828   };
829 
830   const SourceData source_data[] = {
831     { "  with ({}) ", "{ block; }", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
832     { "  with ({}) ", "{ block; }", "; more;", i::WITH_SCOPE, i::CLASSIC_MODE },
833     { "  with ({}) ", "{\n"
834       "    block;\n"
835       "  }", "\n"
836       "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
837     { "  with ({}) ", "statement;", " more;", i::WITH_SCOPE, i::CLASSIC_MODE },
838     { "  with ({}) ", "statement", "\n"
839       "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
840     { "  with ({})\n"
841       "    ", "statement;", "\n"
842       "  more;", i::WITH_SCOPE, i::CLASSIC_MODE },
843     { "  try {} catch ", "(e) { block; }", " more;",
844       i::CATCH_SCOPE, i::CLASSIC_MODE },
845     { "  try {} catch ", "(e) { block; }", "; more;",
846       i::CATCH_SCOPE, i::CLASSIC_MODE },
847     { "  try {} catch ", "(e) {\n"
848       "    block;\n"
849       "  }", "\n"
850       "  more;", i::CATCH_SCOPE, i::CLASSIC_MODE },
851     { "  try {} catch ", "(e) { block; }", " finally { block; } more;",
852       i::CATCH_SCOPE, i::CLASSIC_MODE },
853     { "  start;\n"
854       "  ", "{ let block; }", " more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
855     { "  start;\n"
856       "  ", "{ let block; }", "; more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
857     { "  start;\n"
858       "  ", "{\n"
859       "    let block;\n"
860       "  }", "\n"
861       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
862     { "  start;\n"
863       "  function fun", "(a,b) { infunction; }", " more;",
864       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
865     { "  start;\n"
866       "  function fun", "(a,b) {\n"
867       "    infunction;\n"
868       "  }", "\n"
869       "  more;", i::FUNCTION_SCOPE, i::CLASSIC_MODE },
870     { "  (function fun", "(a,b) { infunction; }", ")();",
871       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
872     { "  for ", "(let x = 1 ; x < 10; ++ x) { block; }", " more;",
873       i::BLOCK_SCOPE, i::EXTENDED_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) {\n"
877       "    block;\n"
878       "  }", "\n"
879       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
880     { "  for ", "(let x = 1 ; x < 10; ++ x) statement;", " more;",
881       i::BLOCK_SCOPE, i::EXTENDED_MODE },
882     { "  for ", "(let x = 1 ; x < 10; ++ x) statement", "\n"
883       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
884     { "  for ", "(let x = 1 ; x < 10; ++ x)\n"
885       "    statement;", "\n"
886       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
887     { "  for ", "(let x in {}) { block; }", " more;",
888       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 {}) {\n"
892       "    block;\n"
893       "  }", "\n"
894       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
895     { "  for ", "(let x in {}) statement;", " more;",
896       i::BLOCK_SCOPE, i::EXTENDED_MODE },
897     { "  for ", "(let x in {}) statement", "\n"
898       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
899     { "  for ", "(let x in {})\n"
900       "    statement;", "\n"
901       "  more;", i::BLOCK_SCOPE, i::EXTENDED_MODE },
902     // Check that 6-byte and 4-byte encodings of UTF-8 strings do not throw
903     // the preparser off in terms of byte offsets.
904     // 6 byte encoding.
905     { "  'foo\355\240\201\355\260\211';\n"
906       "  (function fun", "(a,b) { infunction; }", ")();",
907       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
908     // 4 byte encoding.
909     { "  'foo\360\220\220\212';\n"
910       "  (function fun", "(a,b) { infunction; }", ")();",
911       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
912     // 3 byte encoding of \u0fff.
913     { "  'foo\340\277\277';\n"
914       "  (function fun", "(a,b) { infunction; }", ")();",
915       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
916     // Broken 6 byte encoding with missing last byte.
917     { "  'foo\355\240\201\355\211';\n"
918       "  (function fun", "(a,b) { infunction; }", ")();",
919       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
920     // Broken 3 byte encoding of \u0fff with missing last byte.
921     { "  'foo\340\277';\n"
922       "  (function fun", "(a,b) { infunction; }", ")();",
923       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
924     // Broken 3 byte encoding of \u0fff with missing 2 last bytes.
925     { "  'foo\340';\n"
926       "  (function fun", "(a,b) { infunction; }", ")();",
927       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
928     // Broken 3 byte encoding of \u00ff should be a 2 byte encoding.
929     { "  'foo\340\203\277';\n"
930       "  (function fun", "(a,b) { infunction; }", ")();",
931       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
932     // Broken 3 byte encoding of \u007f should be a 2 byte encoding.
933     { "  'foo\340\201\277';\n"
934       "  (function fun", "(a,b) { infunction; }", ")();",
935       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
936     // Unpaired lead surrogate.
937     { "  'foo\355\240\201';\n"
938       "  (function fun", "(a,b) { infunction; }", ")();",
939       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
940     // Unpaired lead surrogate where following code point is a 3 byte sequence.
941     { "  'foo\355\240\201\340\277\277';\n"
942       "  (function fun", "(a,b) { infunction; }", ")();",
943       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
944     // Unpaired lead surrogate where following code point is a 4 byte encoding
945     // of a trail surrogate.
946     { "  'foo\355\240\201\360\215\260\211';\n"
947       "  (function fun", "(a,b) { infunction; }", ")();",
948       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
949     // Unpaired trail surrogate.
950     { "  'foo\355\260\211';\n"
951       "  (function fun", "(a,b) { infunction; }", ")();",
952       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
953     // 2 byte encoding of \u00ff.
954     { "  'foo\303\277';\n"
955       "  (function fun", "(a,b) { infunction; }", ")();",
956       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
957     // Broken 2 byte encoding of \u00ff with missing last byte.
958     { "  'foo\303';\n"
959       "  (function fun", "(a,b) { infunction; }", ")();",
960       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
961     // Broken 2 byte encoding of \u007f should be a 1 byte encoding.
962     { "  'foo\301\277';\n"
963       "  (function fun", "(a,b) { infunction; }", ")();",
964       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
965     // Illegal 5 byte encoding.
966     { "  'foo\370\277\277\277\277';\n"
967       "  (function fun", "(a,b) { infunction; }", ")();",
968       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
969     // Illegal 6 byte encoding.
970     { "  'foo\374\277\277\277\277\277';\n"
971       "  (function fun", "(a,b) { infunction; }", ")();",
972       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
973     // Illegal 0xfe byte
974     { "  'foo\376\277\277\277\277\277\277';\n"
975       "  (function fun", "(a,b) { infunction; }", ")();",
976       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
977     // Illegal 0xff byte
978     { "  'foo\377\277\277\277\277\277\277\277';\n"
979       "  (function fun", "(a,b) { infunction; }", ")();",
980       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
981     { "  'foo';\n"
982       "  (function fun", "(a,b) { 'bar\355\240\201\355\260\213'; }", ")();",
983       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
984     { "  'foo';\n"
985       "  (function fun", "(a,b) { 'bar\360\220\220\214'; }", ")();",
986       i::FUNCTION_SCOPE, i::CLASSIC_MODE },
987     { NULL, NULL, NULL, i::EVAL_SCOPE, i::CLASSIC_MODE }
988   };
989 
990   v8::HandleScope handles;
991   v8::Persistent<v8::Context> context = v8::Context::New();
992   v8::Context::Scope context_scope(context);
993 
994   int marker;
995   i::Isolate::Current()->stack_guard()->SetStackLimit(
996       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
997   i::FLAG_harmony_scoping = true;
998 
999   for (int i = 0; source_data[i].outer_prefix; i++) {
1000     int kPrefixLen = Utf8LengthHelper(source_data[i].outer_prefix);
1001     int kInnerLen = Utf8LengthHelper(source_data[i].inner_source);
1002     int kSuffixLen = Utf8LengthHelper(source_data[i].outer_suffix);
1003     int kPrefixByteLen = i::StrLength(source_data[i].outer_prefix);
1004     int kInnerByteLen = i::StrLength(source_data[i].inner_source);
1005     int kSuffixByteLen = i::StrLength(source_data[i].outer_suffix);
1006     int kProgramSize = kPrefixLen + kInnerLen + kSuffixLen;
1007     int kProgramByteSize = kPrefixByteLen + kInnerByteLen + kSuffixByteLen;
1008     i::Vector<char> program = i::Vector<char>::New(kProgramByteSize + 1);
1009     i::OS::SNPrintF(program, "%s%s%s",
1010                              source_data[i].outer_prefix,
1011                              source_data[i].inner_source,
1012                              source_data[i].outer_suffix);
1013 
1014     // Parse program source.
1015     i::Handle<i::String> source(
1016         FACTORY->NewStringFromUtf8(i::CStrVector(program.start())));
1017     CHECK_EQ(source->length(), kProgramSize);
1018     i::Handle<i::Script> script = FACTORY->NewScript(source);
1019     i::Parser parser(script, i::kAllowLazy | i::EXTENDED_MODE, NULL, NULL);
1020     i::CompilationInfo info(script);
1021     info.MarkAsGlobal();
1022     info.SetLanguageMode(source_data[i].language_mode);
1023     i::FunctionLiteral* function = parser.ParseProgram(&info);
1024     CHECK(function != NULL);
1025 
1026     // Check scope types and positions.
1027     i::Scope* scope = function->scope();
1028     CHECK(scope->is_global_scope());
1029     CHECK_EQ(scope->start_position(), 0);
1030     CHECK_EQ(scope->end_position(), kProgramSize);
1031     CHECK_EQ(scope->inner_scopes()->length(), 1);
1032 
1033     i::Scope* inner_scope = scope->inner_scopes()->at(0);
1034     CHECK_EQ(inner_scope->type(), source_data[i].scope_type);
1035     CHECK_EQ(inner_scope->start_position(), kPrefixLen);
1036     // The end position of a token is one position after the last
1037     // character belonging to that token.
1038     CHECK_EQ(inner_scope->end_position(), kPrefixLen + kInnerLen);
1039   }
1040 }
1041 
1042 
TestParserSync(i::Handle<i::String> source,int flags)1043 void TestParserSync(i::Handle<i::String> source, int flags) {
1044   uintptr_t stack_limit = i::Isolate::Current()->stack_guard()->real_climit();
1045   bool harmony_scoping = ((i::kLanguageModeMask & flags) == i::EXTENDED_MODE);
1046 
1047   // Preparse the data.
1048   i::CompleteParserRecorder log;
1049   i::Scanner scanner(i::Isolate::Current()->unicode_cache());
1050   i::GenericStringUtf16CharacterStream stream(source, 0, source->length());
1051   scanner.SetHarmonyScoping(harmony_scoping);
1052   scanner.Initialize(&stream);
1053   v8::preparser::PreParser::PreParseResult result =
1054       v8::preparser::PreParser::PreParseProgram(
1055           &scanner, &log, flags, stack_limit);
1056   CHECK_EQ(v8::preparser::PreParser::kPreParseSuccess, result);
1057   i::ScriptDataImpl data(log.ExtractData());
1058 
1059   // Parse the data
1060   i::Handle<i::Script> script = FACTORY->NewScript(source);
1061   bool save_harmony_scoping = i::FLAG_harmony_scoping;
1062   i::FLAG_harmony_scoping = harmony_scoping;
1063   i::Parser parser(script, flags, NULL, NULL);
1064   i::CompilationInfo info(script);
1065   info.MarkAsGlobal();
1066   i::FunctionLiteral* function = parser.ParseProgram(&info);
1067   i::FLAG_harmony_scoping = save_harmony_scoping;
1068 
1069   i::String* type_string = NULL;
1070   if (function == NULL) {
1071     // Extract exception from the parser.
1072     i::Handle<i::String> type_symbol = FACTORY->LookupAsciiSymbol("type");
1073     CHECK(i::Isolate::Current()->has_pending_exception());
1074     i::MaybeObject* maybe_object = i::Isolate::Current()->pending_exception();
1075     i::JSObject* exception = NULL;
1076     CHECK(maybe_object->To(&exception));
1077 
1078     // Get the type string.
1079     maybe_object = exception->GetProperty(*type_symbol);
1080     CHECK(maybe_object->To(&type_string));
1081   }
1082 
1083   // Check that preparsing fails iff parsing fails.
1084   if (data.has_error() && function != NULL) {
1085     i::OS::Print(
1086         "Preparser failed on:\n"
1087         "\t%s\n"
1088         "with error:\n"
1089         "\t%s\n"
1090         "However, the parser succeeded",
1091         *source->ToCString(), data.BuildMessage());
1092     CHECK(false);
1093   } else if (!data.has_error() && function == NULL) {
1094     i::OS::Print(
1095         "Parser failed on:\n"
1096         "\t%s\n"
1097         "with error:\n"
1098         "\t%s\n"
1099         "However, the preparser succeeded",
1100         *source->ToCString(), *type_string->ToCString());
1101     CHECK(false);
1102   }
1103 
1104   // Check that preparser and parser produce the same error.
1105   if (function == NULL) {
1106     if (!type_string->IsEqualTo(i::CStrVector(data.BuildMessage()))) {
1107       i::OS::Print(
1108           "Expected parser and preparser to produce the same error on:\n"
1109           "\t%s\n"
1110           "However, found the following error messages\n"
1111           "\tparser:    %s\n"
1112           "\tpreparser: %s\n",
1113           *source->ToCString(), *type_string->ToCString(), data.BuildMessage());
1114       CHECK(false);
1115     }
1116   }
1117 }
1118 
1119 
TestParserSyncWithFlags(i::Handle<i::String> source)1120 void TestParserSyncWithFlags(i::Handle<i::String> source) {
1121   static const int kFlagsCount = 6;
1122   const int flags[kFlagsCount] = {
1123     i::kNoParsingFlags | i::CLASSIC_MODE,
1124     i::kNoParsingFlags | i::STRICT_MODE,
1125     i::kNoParsingFlags | i::EXTENDED_MODE,
1126     i::kAllowLazy | i::CLASSIC_MODE,
1127     i::kAllowLazy | i::STRICT_MODE,
1128     i::kAllowLazy | i::EXTENDED_MODE
1129   };
1130 
1131   for (int k = 0; k < kFlagsCount; ++k) {
1132     TestParserSync(source, flags[k]);
1133   }
1134 }
1135 
1136 
TEST(ParserSync)1137 TEST(ParserSync) {
1138   const char* context_data[][2] = {
1139     { "", "" },
1140     { "{", "}" },
1141     { "if (true) ", " else {}" },
1142     { "if (true) {} else ", "" },
1143     { "if (true) ", "" },
1144     { "do ", " while (false)" },
1145     { "while (false) ", "" },
1146     { "for (;;) ", "" },
1147     { "with ({})", "" },
1148     { "switch (12) { case 12: ", "}" },
1149     { "switch (12) { default: ", "}" },
1150     { "label2: ", "" },
1151     { NULL, NULL }
1152   };
1153 
1154   const char* statement_data[] = {
1155     "{}",
1156     "var x",
1157     "var x = 1",
1158     "const x",
1159     "const x = 1",
1160     ";",
1161     "12",
1162     "if (false) {} else ;",
1163     "if (false) {} else {}",
1164     "if (false) {} else 12",
1165     "if (false) ;"
1166     "if (false) {}",
1167     "if (false) 12",
1168     "do {} while (false)",
1169     "for (;;) ;",
1170     "for (;;) {}",
1171     "for (;;) 12",
1172     "continue",
1173     "continue label",
1174     "continue\nlabel",
1175     "break",
1176     "break label",
1177     "break\nlabel",
1178     "return",
1179     "return  12",
1180     "return\n12",
1181     "with ({}) ;",
1182     "with ({}) {}",
1183     "with ({}) 12",
1184     "switch ({}) { default: }"
1185     "label3: "
1186     "throw",
1187     "throw  12",
1188     "throw\n12",
1189     "try {} catch(e) {}",
1190     "try {} finally {}",
1191     "try {} catch(e) {} finally {}",
1192     "debugger",
1193     NULL
1194   };
1195 
1196   const char* termination_data[] = {
1197     "",
1198     ";",
1199     "\n",
1200     ";\n",
1201     "\n;",
1202     NULL
1203   };
1204 
1205   v8::HandleScope handles;
1206   v8::Persistent<v8::Context> context = v8::Context::New();
1207   v8::Context::Scope context_scope(context);
1208 
1209   int marker;
1210   i::Isolate::Current()->stack_guard()->SetStackLimit(
1211       reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
1212 
1213   for (int i = 0; context_data[i][0] != NULL; ++i) {
1214     for (int j = 0; statement_data[j] != NULL; ++j) {
1215       for (int k = 0; termination_data[k] != NULL; ++k) {
1216         int kPrefixLen = i::StrLength(context_data[i][0]);
1217         int kStatementLen = i::StrLength(statement_data[j]);
1218         int kTerminationLen = i::StrLength(termination_data[k]);
1219         int kSuffixLen = i::StrLength(context_data[i][1]);
1220         int kProgramSize = kPrefixLen + kStatementLen + kTerminationLen
1221             + kSuffixLen + i::StrLength("label: for (;;) {  }");
1222 
1223         // Plug the source code pieces together.
1224         i::Vector<char> program = i::Vector<char>::New(kProgramSize + 1);
1225         int length = i::OS::SNPrintF(program,
1226             "label: for (;;) { %s%s%s%s }",
1227             context_data[i][0],
1228             statement_data[j],
1229             termination_data[k],
1230             context_data[i][1]);
1231         CHECK(length == kProgramSize);
1232         i::Handle<i::String> source =
1233             FACTORY->NewStringFromAscii(i::CStrVector(program.start()));
1234         TestParserSyncWithFlags(source);
1235       }
1236     }
1237   }
1238 }
1239