Commit 3d1a17c2 authored by marja@chromium.org's avatar marja@chromium.org

Update tests to use the new compilation API + related fixes.

Esp. get rid of PreCompile in tests, as it's going to be removed.

Notes:
- The new compilation API doesn't have a separate precompilation phase, so there
is no separate way to check for errors except checking the compilation
errors. Removed some tests which don't make sense any more.
- test-api/Regress31661 didn't make sense as a regression test even before the
compilation API changes, because Blink doesn't precompile this short scripts. So
detecting this kind of errors (see crbug.com/31661 for more information) cannot rely
on precompilation errors.
- test-parsing/PreParserStrictOctal has nothing to do with PreParser, and the comment
about "forcing preparsing" was just wrong.
- test-api/PreCompile was supposed to test that "pre-compilation (aka
preparsing) can be called without initializing the whole VM"; that's no longer
true, since there's no separate precompilation step in the new compile
API. There are other tests (test-parsing/DontRegressPreParserDataSizes) which
ensure that we produce cached data.
- Updated tests which test preparsing to use PreParser directly (not via the
 preparsing API).
- In the new compilation API, the user doesn't need to deal with ScriptData
ever. It's only used internally, and needed in tests that test internal aspects
(e.g., modify the cached data before passing it back).
- Some tests which used to test preparse + parse now test first time parse +
  second time parse, and had to be modified to ensure we don't hit the
  compilation cache.

BUG=
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/225743002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20511 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b0def354
...@@ -114,6 +114,13 @@ class ScriptDataImpl : public ScriptData { ...@@ -114,6 +114,13 @@ class ScriptDataImpl : public ScriptData {
? store_[PreparseDataConstants::kSymbolCountOffset] ? store_[PreparseDataConstants::kSymbolCountOffset]
: 0; : 0;
} }
int function_count() {
int functions_size =
static_cast<int>(store_[PreparseDataConstants::kFunctionsSizeOffset]);
if (functions_size < 0) return 0;
if (functions_size % FunctionEntry::kSize != 0) return 0;
return functions_size / FunctionEntry::kSize;
}
// The following functions should only be called if SanityCheck has // The following functions should only be called if SanityCheck has
// returned true. // returned true.
bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; } bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
......
...@@ -346,19 +346,13 @@ static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) { ...@@ -346,19 +346,13 @@ static inline v8::Local<v8::Value> CompileRun(v8::Local<v8::String> source) {
static inline v8::Local<v8::Value> PreCompileCompileRun(const char* source) { static inline v8::Local<v8::Value> PreCompileCompileRun(const char* source) {
// Compile once just to get the preparse data, then compile the second time
// using the data.
v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::String> source_string = v8::ScriptCompiler::Source script_source(v8_str(source));
v8::String::NewFromUtf8(isolate, source); v8::ScriptCompiler::Compile(isolate, &script_source,
v8::ScriptData* preparse = v8::ScriptData::PreCompile(source_string); v8::ScriptCompiler::kProduceDataToCache);
v8::ScriptCompiler::Source script_source( return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
source_string, new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(preparse->Data()),
preparse->Length()));
v8::Local<v8::Script> script =
v8::ScriptCompiler::Compile(isolate, &script_source);
v8::Local<v8::Value> result = script->Run();
delete preparse;
return result;
} }
......
...@@ -14823,74 +14823,32 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) { ...@@ -14823,74 +14823,32 @@ THREADED_TEST(TurnOnAccessCheckAndRecompile) {
} }
// This test verifies that pre-compilation (aka preparsing) can be called
// without initializing the whole VM. Thus we cannot run this test in a
// multi-threaded setup.
TEST(PreCompile) {
// TODO(155): This test would break without the initialization of V8. This is
// a workaround for now to make this test not fail.
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
HandleScope handle_scope(isolate);
const char* script = "function foo(a) { return a+1; }";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
CHECK_NE(sd->Length(), 0);
CHECK_NE(sd->Data(), NULL);
CHECK(!sd->HasError());
delete sd;
}
TEST(PreCompileWithError) {
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
HandleScope handle_scope(isolate);
const char* script = "function foo(a) { return 1 * * 2; }";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
CHECK(sd->HasError());
delete sd;
}
TEST(Regress31661) {
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
HandleScope handle_scope(isolate);
const char* script = " The Definintive Guide";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
CHECK(sd->HasError());
delete sd;
}
// Tests that ScriptData can be serialized and deserialized. // Tests that ScriptData can be serialized and deserialized.
TEST(PreCompileSerialization) { TEST(PreCompileSerialization) {
v8::V8::Initialize(); v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate(); LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
HandleScope handle_scope(isolate); HandleScope handle_scope(isolate);
const char* script = "function foo(a) { return a+1; }";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
i::FLAG_min_preparse_length = 0;
const char* script = "function foo(a) { return a+1; }";
v8::ScriptCompiler::Source source(v8_str(script));
v8::ScriptCompiler::Compile(isolate, &source,
v8::ScriptCompiler::kProduceDataToCache);
// Serialize. // Serialize.
int serialized_data_length = sd->Length(); const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
char* serialized_data = i::NewArray<char>(serialized_data_length); char* serialized_data = i::NewArray<char>(cd->length);
i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length); i::OS::MemCopy(serialized_data, cd->data, cd->length);
// Deserialize. // Deserialize.
v8::ScriptData* deserialized_sd = v8::ScriptData* deserialized =
v8::ScriptData::New(serialized_data, serialized_data_length); v8::ScriptData::New(serialized_data, cd->length);
// Verify that the original is the same as the deserialized. // Verify that the original is the same as the deserialized.
CHECK_EQ(sd->Length(), deserialized_sd->Length()); CHECK_EQ(cd->length, deserialized->Length());
CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length())); CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
delete sd; delete deserialized;
delete deserialized_sd;
i::DeleteArray(serialized_data); i::DeleteArray(serialized_data);
} }
...@@ -14908,17 +14866,25 @@ TEST(PreCompileDeserializationError) { ...@@ -14908,17 +14866,25 @@ TEST(PreCompileDeserializationError) {
} }
// Attempts to deserialize bad data. TEST(CompileWithInvalidCachedData) {
TEST(PreCompileInvalidPreparseDataError) {
v8::V8::Initialize(); v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate(); v8::Isolate* isolate = CcTest::isolate();
LocalContext context; LocalContext context;
v8::HandleScope scope(context->GetIsolate()); v8::HandleScope scope(context->GetIsolate());
i::FLAG_min_preparse_length = 0;
const char* script = "function foo(){ return 5;}\n" const char* script = "function foo(){ return 5;}\n"
"function bar(){ return 6 + 7;} foo();"; "function bar(){ return 6 + 7;} foo();";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8( v8::ScriptCompiler::Source source(v8_str(script));
isolate, script, v8::String::kNormalString, i::StrLength(script))); v8::ScriptCompiler::Compile(isolate, &source,
v8::ScriptCompiler::kProduceDataToCache);
// source owns its cached data. Create a ScriptData based on it. The user
// never needs to create ScriptDatas any more; we only need it here because we
// want to modify the data before passing it back.
const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
// ScriptData does not take ownership of the buffers passed to it.
v8::ScriptData* sd =
v8::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
CHECK(!sd->HasError()); CHECK(!sd->HasError());
// ScriptDataImpl private implementation details // ScriptDataImpl private implementation details
const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
...@@ -14932,12 +14898,18 @@ TEST(PreCompileInvalidPreparseDataError) { ...@@ -14932,12 +14898,18 @@ TEST(PreCompileInvalidPreparseDataError) {
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
v8::TryCatch try_catch; v8::TryCatch try_catch;
v8::ScriptCompiler::Source script_source( // Make the script slightly different so that we don't hit the compilation
String::NewFromUtf8(isolate, script), // cache. Don't change the lenghts of tokens.
const char* script2 = "function foo(){ return 6;}\n"
"function bar(){ return 6 + 7;} foo();";
v8::ScriptCompiler::Source source2(
v8_str(script2),
// CachedData doesn't take ownership of the buffers, Source takes
// ownership of CachedData.
new v8::ScriptCompiler::CachedData( new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
Local<v8::UnboundScript> compiled_script = Local<v8::UnboundScript> compiled_script =
v8::ScriptCompiler::CompileUnbound(isolate, &script_source); v8::ScriptCompiler::CompileUnbound(isolate, &source2);
CHECK(try_catch.HasCaught()); CHECK(try_catch.HasCaught());
String::Utf8Value exception_value(try_catch.Message()->Get()); String::Utf8Value exception_value(try_catch.Message()->Get());
...@@ -14950,19 +14922,20 @@ TEST(PreCompileInvalidPreparseDataError) { ...@@ -14950,19 +14922,20 @@ TEST(PreCompileInvalidPreparseDataError) {
// Overwrite function bar's start position with 200. The function entry // Overwrite function bar's start position with 200. The function entry
// will not be found when searching for it by position and we should fall // will not be found when searching for it by position and we should fall
// back on eager compilation. // back on eager compilation.
sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8( // ScriptData does not take ownership of the buffers passed to it.
isolate, script, v8::String::kNormalString, i::StrLength(script))); sd = v8::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
200; 200;
v8::ScriptCompiler::Source script_source2( const char* script3 = "function foo(){ return 7;}\n"
String::NewFromUtf8(isolate, script), "function bar(){ return 6 + 7;} foo();";
v8::ScriptCompiler::Source source3(
v8_str(script3),
new v8::ScriptCompiler::CachedData( new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length())); reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
compiled_script = compiled_script =
v8::ScriptCompiler::CompileUnbound(isolate, &script_source2); v8::ScriptCompiler::CompileUnbound(isolate, &source3);
CHECK(!try_catch.HasCaught()); CHECK(!try_catch.HasCaught());
delete sd; delete sd;
} }
......
This diff is collapsed.
...@@ -44,15 +44,9 @@ ...@@ -44,15 +44,9 @@
using namespace v8::internal; using namespace v8::internal;
enum TestMode {
PreParseAndParse,
PreParse,
Parse
};
std::pair<TimeDelta, TimeDelta> RunBaselineParser( std::pair<TimeDelta, TimeDelta> RunBaselineParser(
const char* fname, Encoding encoding, int repeat, v8::Isolate* isolate, const char* fname, Encoding encoding, int repeat, v8::Isolate* isolate,
v8::Handle<v8::Context> context, TestMode test_mode) { v8::Handle<v8::Context> context) {
int length = 0; int length = 0;
const byte* source = ReadFileAndRepeat(fname, &length, repeat); const byte* source = ReadFileAndRepeat(fname, &length, repeat);
v8::Handle<v8::String> source_handle; v8::Handle<v8::String> source_handle;
...@@ -73,42 +67,41 @@ std::pair<TimeDelta, TimeDelta> RunBaselineParser( ...@@ -73,42 +67,41 @@ std::pair<TimeDelta, TimeDelta> RunBaselineParser(
break; break;
} }
} }
v8::ScriptData* cached_data = NULL; TimeDelta parse_time1, parse_time2;
TimeDelta preparse_time, parse_time; Handle<Script> script = Isolate::Current()->factory()->NewScript(
if (test_mode == PreParseAndParse || test_mode == PreParse) { v8::Utils::OpenHandle(*source_handle));
i::ScriptDataImpl* cached_data_impl = NULL;
// First round of parsing (produce data to cache).
{
CompilationInfoWithZone info(script);
info.MarkAsGlobal();
info.SetCachedData(&cached_data_impl, i::PRODUCE_CACHED_DATA);
ElapsedTimer timer; ElapsedTimer timer;
timer.Start(); timer.Start();
cached_data = v8::ScriptData::PreCompile(source_handle); // Allow lazy parsing; otherwise we won't produce cached data.
preparse_time = timer.Elapsed(); bool success = Parser::Parse(&info, true);
if (cached_data == NULL || cached_data->HasError()) { parse_time1 = timer.Elapsed();
fprintf(stderr, "Preparsing failed\n"); if (!success) {
fprintf(stderr, "Parsing failed\n");
return std::make_pair(TimeDelta(), TimeDelta()); return std::make_pair(TimeDelta(), TimeDelta());
} }
} }
if (test_mode == PreParseAndParse || test_mode == Parse) { // Second round of parsing (consume cached data).
Handle<String> str = v8::Utils::OpenHandle(*source_handle); {
i::Isolate* internal_isolate = str->GetIsolate();
Handle<Script> script = internal_isolate->factory()->NewScript(str);
CompilationInfoWithZone info(script); CompilationInfoWithZone info(script);
info.MarkAsGlobal(); info.MarkAsGlobal();
i::ScriptDataImpl* cached_data_impl = info.SetCachedData(&cached_data_impl, i::CONSUME_CACHED_DATA);
static_cast<i::ScriptDataImpl*>(cached_data);
if (test_mode == PreParseAndParse) {
info.SetCachedData(&cached_data_impl,
i::CONSUME_CACHED_DATA);
}
info.SetContext(v8::Utils::OpenHandle(*context));
ElapsedTimer timer; ElapsedTimer timer;
timer.Start(); timer.Start();
// Allow lazy parsing; otherwise the preparse data won't help. // Allow lazy parsing; otherwise cached data won't help.
bool success = Parser::Parse(&info, true); bool success = Parser::Parse(&info, true);
parse_time = timer.Elapsed(); parse_time2 = timer.Elapsed();
if (!success) { if (!success) {
fprintf(stderr, "Parsing failed\n"); fprintf(stderr, "Parsing failed\n");
return std::make_pair(TimeDelta(), TimeDelta()); return std::make_pair(TimeDelta(), TimeDelta());
} }
} }
return std::make_pair(preparse_time, parse_time); return std::make_pair(parse_time1, parse_time2);
} }
...@@ -116,7 +109,6 @@ int main(int argc, char* argv[]) { ...@@ -116,7 +109,6 @@ int main(int argc, char* argv[]) {
v8::V8::InitializeICU(); v8::V8::InitializeICU();
v8::V8::SetFlagsFromCommandLine(&argc, argv, true); v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
Encoding encoding = LATIN1; Encoding encoding = LATIN1;
TestMode test_mode = PreParseAndParse;
std::vector<std::string> fnames; std::vector<std::string> fnames;
std::string benchmark; std::string benchmark;
int repeat = 1; int repeat = 1;
...@@ -127,12 +119,6 @@ int main(int argc, char* argv[]) { ...@@ -127,12 +119,6 @@ int main(int argc, char* argv[]) {
encoding = UTF8; encoding = UTF8;
} else if (strcmp(argv[i], "--utf16") == 0) { } else if (strcmp(argv[i], "--utf16") == 0) {
encoding = UTF16; encoding = UTF16;
} else if (strcmp(argv[i], "--preparse-and-parse") == 0) {
test_mode = PreParseAndParse;
} else if (strcmp(argv[i], "--preparse") == 0) {
test_mode = PreParse;
} else if (strcmp(argv[i], "--parse") == 0) {
test_mode = Parse;
} else if (strncmp(argv[i], "--benchmark=", 12) == 0) { } else if (strncmp(argv[i], "--benchmark=", 12) == 0) {
benchmark = std::string(argv[i]).substr(12); benchmark = std::string(argv[i]).substr(12);
} else if (strncmp(argv[i], "--repeat=", 9) == 0) { } else if (strncmp(argv[i], "--repeat=", 9) == 0) {
...@@ -150,20 +136,19 @@ int main(int argc, char* argv[]) { ...@@ -150,20 +136,19 @@ int main(int argc, char* argv[]) {
ASSERT(!context.IsEmpty()); ASSERT(!context.IsEmpty());
{ {
v8::Context::Scope scope(context); v8::Context::Scope scope(context);
double preparse_total = 0; double first_parse_total = 0;
double parse_total = 0; double second_parse_total = 0;
for (size_t i = 0; i < fnames.size(); i++) { for (size_t i = 0; i < fnames.size(); i++) {
std::pair<TimeDelta, TimeDelta> time = RunBaselineParser( std::pair<TimeDelta, TimeDelta> time = RunBaselineParser(
fnames[i].c_str(), encoding, repeat, isolate, context, test_mode); fnames[i].c_str(), encoding, repeat, isolate, context);
preparse_total += time.first.InMillisecondsF(); first_parse_total += time.first.InMillisecondsF();
parse_total += time.second.InMillisecondsF(); second_parse_total += time.second.InMillisecondsF();
} }
if (benchmark.empty()) benchmark = "Baseline"; if (benchmark.empty()) benchmark = "Baseline";
printf("%s(PreParseRunTime): %.f ms\n", benchmark.c_str(), printf("%s(FirstParseRunTime): %.f ms\n", benchmark.c_str(),
preparse_total); first_parse_total);
printf("%s(ParseRunTime): %.f ms\n", benchmark.c_str(), parse_total); printf("%s(SecondParseRunTime): %.f ms\n", benchmark.c_str(),
printf("%s(RunTime): %.f ms\n", benchmark.c_str(), second_parse_total);
preparse_total + parse_total);
} }
} }
v8::V8::Dispose(); v8::V8::Dispose();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment