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

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

Powered by Google App Engine
This is Rietveld 408576698