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