Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: test/cctest/test-api.cc

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

Powered by Google App Engine
This is Rietveld 408576698