| OLD | NEW | 
|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. | 
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without | 
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are | 
| 4 // met: | 4 // met: | 
| 5 // | 5 // | 
| 6 //     * Redistributions of source code must retain the above copyright | 6 //     * Redistributions of source code must retain the above copyright | 
| 7 //       notice, this list of conditions and the following disclaimer. | 7 //       notice, this list of conditions and the following disclaimer. | 
| 8 //     * Redistributions in binary form must reproduce the above | 8 //     * Redistributions in binary form must reproduce the above | 
| 9 //       copyright notice, this list of conditions and the following | 9 //       copyright notice, this list of conditions and the following | 
| 10 //       disclaimer in the documentation and/or other materials provided | 10 //       disclaimer in the documentation and/or other materials provided | 
| (...skipping 23035 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 23046                                            IndexedAccessCounter); | 23046                                            IndexedAccessCounter); | 
| 23047 | 23047 | 
| 23048   v8::Handle<Context> context = Context::New(isolate); | 23048   v8::Handle<Context> context = Context::New(isolate); | 
| 23049   v8::Context::Scope context_scope(context); | 23049   v8::Context::Scope context_scope(context); | 
| 23050 | 23050 | 
| 23051   context->Global()->Set(v8_str("o"), object_template->NewInstance()); | 23051   context->Global()->Set(v8_str("o"), object_template->NewInstance()); | 
| 23052   CompileRun( | 23052   CompileRun( | 
| 23053       "Object.defineProperty(o, 'key', " | 23053       "Object.defineProperty(o, 'key', " | 
| 23054       "    { get: function() {}, set: function() {} });"); | 23054       "    { get: function() {}, set: function() {} });"); | 
| 23055 } | 23055 } | 
|  | 23056 | 
|  | 23057 class TestSourceStream : public v8::ScriptCompiler::ExternalSourceStream { | 
|  | 23058  public: | 
|  | 23059   explicit TestSourceStream(const char** chunks) : chunks_(chunks), index_(0) {} | 
|  | 23060 | 
|  | 23061   virtual size_t GetMoreData(const uint8_t** src) { | 
|  | 23062     // Unlike in real use cases, this function will never block. | 
|  | 23063     if (chunks_[index_] == NULL) { | 
|  | 23064       return 0; | 
|  | 23065     } | 
|  | 23066     // Copy the data, since the caller takes ownership of it. | 
|  | 23067     size_t len = strlen(chunks_[index_]); | 
|  | 23068     // We don't need to zero-terminate since we return the length. | 
|  | 23069     uint8_t* copy = new uint8_t[len]; | 
|  | 23070     memcpy(copy, chunks_[index_], len); | 
|  | 23071     *src = copy; | 
|  | 23072     ++index_; | 
|  | 23073     return len; | 
|  | 23074   } | 
|  | 23075 | 
|  | 23076   // Helper for constructing a string from chunks (the compilation needs it | 
|  | 23077   // too). | 
|  | 23078   static char* FullSourceString(const char** chunks) { | 
|  | 23079     size_t total_len = 0; | 
|  | 23080     for (size_t i = 0; chunks[i] != NULL; ++i) { | 
|  | 23081       total_len += strlen(chunks[i]); | 
|  | 23082     } | 
|  | 23083     char* full_string = new char[total_len + 1]; | 
|  | 23084     size_t offset = 0; | 
|  | 23085     for (size_t i = 0; chunks[i] != NULL; ++i) { | 
|  | 23086       size_t len = strlen(chunks[i]); | 
|  | 23087       memcpy(full_string + offset, chunks[i], len); | 
|  | 23088       offset += len; | 
|  | 23089     } | 
|  | 23090     full_string[total_len] = 0; | 
|  | 23091     return full_string; | 
|  | 23092   } | 
|  | 23093 | 
|  | 23094  private: | 
|  | 23095   const char** chunks_; | 
|  | 23096   unsigned index_; | 
|  | 23097 }; | 
|  | 23098 | 
|  | 23099 | 
|  | 23100 // Helper function for running streaming tests. | 
|  | 23101 void RunStreamingTest(const char** chunks, | 
|  | 23102                       v8::ScriptCompiler::StreamedSource::Encoding encoding = | 
|  | 23103                           v8::ScriptCompiler::StreamedSource::ONE_BYTE, | 
|  | 23104                       bool expected_success = true) { | 
|  | 23105   LocalContext env; | 
|  | 23106   v8::Isolate* isolate = env->GetIsolate(); | 
|  | 23107   v8::HandleScope scope(isolate); | 
|  | 23108   v8::TryCatch try_catch; | 
|  | 23109 | 
|  | 23110   v8::ScriptCompiler::StreamedSource source(new TestSourceStream(chunks), | 
|  | 23111                                             encoding); | 
|  | 23112   v8::ScriptCompiler::ScriptStreamingTask* task = | 
|  | 23113       v8::ScriptCompiler::StartStreamingScript(isolate, &source); | 
|  | 23114 | 
|  | 23115   // TestSourceStream::GetMoreData won't block, so it's OK to just run the | 
|  | 23116   // task here in the main thread. | 
|  | 23117   task->Run(); | 
|  | 23118   delete task; | 
|  | 23119 | 
|  | 23120   v8::ScriptOrigin origin(v8_str("http://foo.com")); | 
|  | 23121   char* full_source = TestSourceStream::FullSourceString(chunks); | 
|  | 23122 | 
|  | 23123   // The possible errors are only produced while compiling. | 
|  | 23124   CHECK_EQ(false, try_catch.HasCaught()); | 
|  | 23125 | 
|  | 23126   v8::Handle<Script> script = v8::ScriptCompiler::Compile( | 
|  | 23127       isolate, &source, v8_str(full_source), origin); | 
|  | 23128   if (expected_success) { | 
|  | 23129     CHECK(!script.IsEmpty()); | 
|  | 23130     v8::Handle<Value> result(script->Run()); | 
|  | 23131     // All scripts are supposed to return the fixed value 13 when ran. | 
|  | 23132     CHECK_EQ(13, result->Int32Value()); | 
|  | 23133   } else { | 
|  | 23134     CHECK(script.IsEmpty()); | 
|  | 23135     CHECK(try_catch.HasCaught()); | 
|  | 23136   } | 
|  | 23137   delete[] full_source; | 
|  | 23138 } | 
|  | 23139 | 
|  | 23140 | 
|  | 23141 TEST(StreamingSimpleScript) { | 
|  | 23142   // This script is unrealistically small, since no one chunk is enough to fill | 
|  | 23143   // the backing buffer of Scanner, let alone overflow it. | 
|  | 23144   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", | 
|  | 23145                           NULL}; | 
|  | 23146   RunStreamingTest(chunks); | 
|  | 23147 } | 
|  | 23148 | 
|  | 23149 | 
|  | 23150 TEST(StreamingBiggerScript) { | 
|  | 23151   const char* chunk1 = | 
|  | 23152       "function foo() {\n" | 
|  | 23153       "  // Make this chunk sufficiently long so that it will overflow the\n" | 
|  | 23154       "  // backing buffer of the Scanner.\n" | 
|  | 23155       "  var i = 0;\n" | 
|  | 23156       "  var result = 0;\n" | 
|  | 23157       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n" | 
|  | 23158       "  result = 0;\n" | 
|  | 23159       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n" | 
|  | 23160       "  result = 0;\n" | 
|  | 23161       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n" | 
|  | 23162       "  result = 0;\n" | 
|  | 23163       "  for (i = 0; i < 13; ++i) { result = result + 1; }\n" | 
|  | 23164       "  return result;\n" | 
|  | 23165       "}\n"; | 
|  | 23166   const char* chunks[] = {chunk1, "foo(); ", NULL}; | 
|  | 23167   RunStreamingTest(chunks); | 
|  | 23168 } | 
|  | 23169 | 
|  | 23170 | 
|  | 23171 TEST(StreamingScriptWithParseError) { | 
|  | 23172   // Test that parse errors from streamed scripts are propagated correctly. | 
|  | 23173   { | 
|  | 23174     char chunk1[] = | 
|  | 23175         "  // This will result in a parse error.\n" | 
|  | 23176         "  var if else then foo"; | 
|  | 23177     char chunk2[] = "  13\n"; | 
|  | 23178     const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; | 
|  | 23179 | 
|  | 23180     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::ONE_BYTE, | 
|  | 23181                      false); | 
|  | 23182   } | 
|  | 23183   // Test that the next script succeeds normally. | 
|  | 23184   { | 
|  | 23185     char chunk1[] = | 
|  | 23186         "  // This will be parsed successfully.\n" | 
|  | 23187         "  function foo() { return "; | 
|  | 23188     char chunk2[] = "  13; }\n"; | 
|  | 23189     const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; | 
|  | 23190 | 
|  | 23191     RunStreamingTest(chunks); | 
|  | 23192   } | 
|  | 23193 } | 
|  | 23194 | 
|  | 23195 | 
|  | 23196 TEST(StreamingUtf8Script) { | 
|  | 23197   // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers | 
|  | 23198   // don't like it. | 
|  | 23199   const char* chunk1 = | 
|  | 23200       "function foo() {\n" | 
|  | 23201       "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23202       "  // ASCII.\n" | 
|  | 23203       "  var foob\xeb\x91\x80r = 13;\n" | 
|  | 23204       "  return foob\xeb\x91\x80r;\n" | 
|  | 23205       "}\n"; | 
|  | 23206   const char* chunks[] = {chunk1, "foo(); ", NULL}; | 
|  | 23207   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23208 } | 
|  | 23209 | 
|  | 23210 | 
|  | 23211 TEST(StreamingUtf8ScriptWithSplitCharactersSanityCheck) { | 
|  | 23212   // A sanity check to prove that the approach of splitting UTF-8 | 
|  | 23213   // characters is correct. Here is an UTF-8 character which will take three | 
|  | 23214   // bytes. | 
|  | 23215   const char* reference = "\xeb\x91\x80"; | 
|  | 23216   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned. | 
|  | 23217 | 
|  | 23218   char chunk1[] = | 
|  | 23219       "function foo() {\n" | 
|  | 23220       "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23221       "  // ASCII.\n" | 
|  | 23222       "  var foob"; | 
|  | 23223   char chunk2[] = | 
|  | 23224       "XXXr = 13;\n" | 
|  | 23225       "  return foob\xeb\x91\x80r;\n" | 
|  | 23226       "}\n"; | 
|  | 23227   for (int i = 0; i < 3; ++i) { | 
|  | 23228     chunk2[i] = reference[i]; | 
|  | 23229   } | 
|  | 23230   const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; | 
|  | 23231   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23232 } | 
|  | 23233 | 
|  | 23234 | 
|  | 23235 TEST(StreamingUtf8ScriptWithSplitCharacters) { | 
|  | 23236   // Stream data where a multi-byte UTF-8 character is split between two data | 
|  | 23237   // chunks. | 
|  | 23238   const char* reference = "\xeb\x91\x80"; | 
|  | 23239   char chunk1[] = | 
|  | 23240       "function foo() {\n" | 
|  | 23241       "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23242       "  // ASCII.\n" | 
|  | 23243       "  var foobX"; | 
|  | 23244   char chunk2[] = | 
|  | 23245       "XXr = 13;\n" | 
|  | 23246       "  return foob\xeb\x91\x80r;\n" | 
|  | 23247       "}\n"; | 
|  | 23248   chunk1[strlen(chunk1) - 1] = reference[0]; | 
|  | 23249   chunk2[0] = reference[1]; | 
|  | 23250   chunk2[1] = reference[2]; | 
|  | 23251   const char* chunks[] = {chunk1, chunk2, "foo();", NULL}; | 
|  | 23252   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23253 } | 
|  | 23254 | 
|  | 23255 | 
|  | 23256 TEST(StreamingUtf8ScriptWithSplitCharactersValidEdgeCases) { | 
|  | 23257   // Tests edge cases which should still be decoded correctly. | 
|  | 23258 | 
|  | 23259   // Case 1: a chunk contains only bytes for a split character (and no other | 
|  | 23260   // data). This kind of a chunk would be exceptionally small, but we should | 
|  | 23261   // still decode it correctly. | 
|  | 23262   const char* reference = "\xeb\x91\x80"; | 
|  | 23263   // The small chunk is at the beginning of the split character | 
|  | 23264   { | 
|  | 23265     char chunk1[] = | 
|  | 23266         "function foo() {\n" | 
|  | 23267         "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23268         "  // ASCII.\n" | 
|  | 23269         "  var foob"; | 
|  | 23270     char chunk2[] = "XX"; | 
|  | 23271     char chunk3[] = | 
|  | 23272         "Xr = 13;\n" | 
|  | 23273         "  return foob\xeb\x91\x80r;\n" | 
|  | 23274         "}\n"; | 
|  | 23275     chunk2[0] = reference[0]; | 
|  | 23276     chunk2[1] = reference[1]; | 
|  | 23277     chunk3[0] = reference[2]; | 
|  | 23278     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; | 
|  | 23279     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23280   } | 
|  | 23281   // The small chunk is at the end of a character | 
|  | 23282   { | 
|  | 23283     char chunk1[] = | 
|  | 23284         "function foo() {\n" | 
|  | 23285         "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23286         "  // ASCII.\n" | 
|  | 23287         "  var foobX"; | 
|  | 23288     char chunk2[] = "XX"; | 
|  | 23289     char chunk3[] = | 
|  | 23290         "r = 13;\n" | 
|  | 23291         "  return foob\xeb\x91\x80r;\n" | 
|  | 23292         "}\n"; | 
|  | 23293     chunk1[strlen(chunk1) - 1] = reference[0]; | 
|  | 23294     chunk2[0] = reference[1]; | 
|  | 23295     chunk2[1] = reference[2]; | 
|  | 23296     const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; | 
|  | 23297     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23298   } | 
|  | 23299   // Case 2: the script ends with a multi-byte character. Make sure that it's | 
|  | 23300   // decoded correctly and not just ignored. | 
|  | 23301   { | 
|  | 23302     char chunk1[] = | 
|  | 23303         "var foob\xeb\x91\x80 = 13;\n" | 
|  | 23304         "foob\xeb\x91\x80"; | 
|  | 23305     const char* chunks[] = {chunk1, NULL}; | 
|  | 23306     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8); | 
|  | 23307   } | 
|  | 23308 } | 
|  | 23309 | 
|  | 23310 | 
|  | 23311 TEST(StreamingUtf8ScriptWithSplitCharactersInvalidEdgeCases) { | 
|  | 23312   // Test cases where a UTF-8 character is split over several chunks. Those | 
|  | 23313   // cases are not supported (the embedder should give the data in big enough | 
|  | 23314   // chunks), but we shouldn't crash, just produce a parse error. | 
|  | 23315   const char* reference = "\xeb\x91\x80"; | 
|  | 23316   char chunk1[] = | 
|  | 23317       "function foo() {\n" | 
|  | 23318       "  // This function will contain an UTF-8 character which is not in\n" | 
|  | 23319       "  // ASCII.\n" | 
|  | 23320       "  var foobX"; | 
|  | 23321   char chunk2[] = "X"; | 
|  | 23322   char chunk3[] = | 
|  | 23323       "Xr = 13;\n" | 
|  | 23324       "  return foob\xeb\x91\x80r;\n" | 
|  | 23325       "}\n"; | 
|  | 23326   chunk1[strlen(chunk1) - 1] = reference[0]; | 
|  | 23327   chunk2[0] = reference[1]; | 
|  | 23328   chunk3[0] = reference[2]; | 
|  | 23329   const char* chunks[] = {chunk1, chunk2, chunk3, "foo();", NULL}; | 
|  | 23330 | 
|  | 23331   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false); | 
|  | 23332 } | 
|  | 23333 | 
|  | 23334 | 
|  | 23335 TEST(StreamingProducesParserCache) { | 
|  | 23336   i::FLAG_min_preparse_length = 0; | 
|  | 23337   const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo(); ", | 
|  | 23338                           NULL}; | 
|  | 23339 | 
|  | 23340   LocalContext env; | 
|  | 23341   v8::Isolate* isolate = env->GetIsolate(); | 
|  | 23342   v8::HandleScope scope(isolate); | 
|  | 23343 | 
|  | 23344   v8::ScriptCompiler::StreamedSource source( | 
|  | 23345       new TestSourceStream(chunks), | 
|  | 23346       v8::ScriptCompiler::StreamedSource::ONE_BYTE); | 
|  | 23347   v8::ScriptCompiler::ScriptStreamingTask* task = | 
|  | 23348       v8::ScriptCompiler::StartStreamingScript( | 
|  | 23349           isolate, &source, v8::ScriptCompiler::kProduceParserCache); | 
|  | 23350 | 
|  | 23351   // TestSourceStream::GetMoreData won't block, so it's OK to just run the | 
|  | 23352   // task here in the main thread. | 
|  | 23353   task->Run(); | 
|  | 23354   delete task; | 
|  | 23355 | 
|  | 23356   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData(); | 
|  | 23357   CHECK(cached_data != NULL); | 
|  | 23358   CHECK(cached_data->data != NULL); | 
|  | 23359   CHECK_GT(cached_data->length, 0); | 
|  | 23360 } | 
| OLD | NEW | 
|---|