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 {
? store_[PreparseDataConstants::kSymbolCountOffset]
: 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
// returned true.
bool has_error() { return store_[PreparseDataConstants::kHasErrorOffset]; }
......
......@@ -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) {
// Compile once just to get the preparse data, then compile the second time
// using the data.
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Local<v8::String> source_string =
v8::String::NewFromUtf8(isolate, source);
v8::ScriptData* preparse = v8::ScriptData::PreCompile(source_string);
v8::ScriptCompiler::Source script_source(
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;
v8::ScriptCompiler::Source script_source(v8_str(source));
v8::ScriptCompiler::Compile(isolate, &script_source,
v8::ScriptCompiler::kProduceDataToCache);
return v8::ScriptCompiler::Compile(isolate, &script_source)->Run();
}
......
......@@ -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.
TEST(PreCompileSerialization) {
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
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.
int serialized_data_length = sd->Length();
char* serialized_data = i::NewArray<char>(serialized_data_length);
i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length);
const v8::ScriptCompiler::CachedData* cd = source.GetCachedData();
char* serialized_data = i::NewArray<char>(cd->length);
i::OS::MemCopy(serialized_data, cd->data, cd->length);
// Deserialize.
v8::ScriptData* deserialized_sd =
v8::ScriptData::New(serialized_data, serialized_data_length);
v8::ScriptData* deserialized =
v8::ScriptData::New(serialized_data, cd->length);
// Verify that the original is the same as the deserialized.
CHECK_EQ(sd->Length(), deserialized_sd->Length());
CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length()));
CHECK_EQ(sd->HasError(), deserialized_sd->HasError());
CHECK_EQ(cd->length, deserialized->Length());
CHECK_EQ(0, memcmp(cd->data, deserialized->Data(), cd->length));
delete sd;
delete deserialized_sd;
delete deserialized;
i::DeleteArray(serialized_data);
}
......@@ -14908,17 +14866,25 @@ TEST(PreCompileDeserializationError) {
}
// Attempts to deserialize bad data.
TEST(PreCompileInvalidPreparseDataError) {
TEST(CompileWithInvalidCachedData) {
v8::V8::Initialize();
v8::Isolate* isolate = CcTest::isolate();
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
i::FLAG_min_preparse_length = 0;
const char* script = "function foo(){ return 5;}\n"
"function bar(){ return 6 + 7;} foo();";
v8::ScriptData* sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
v8::ScriptCompiler::Source source(v8_str(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());
// ScriptDataImpl private implementation details
const int kHeaderSize = i::PreparseDataConstants::kHeaderSize;
......@@ -14932,12 +14898,18 @@ TEST(PreCompileInvalidPreparseDataError) {
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0;
v8::TryCatch try_catch;
v8::ScriptCompiler::Source script_source(
String::NewFromUtf8(isolate, script),
// Make the script slightly different so that we don't hit the compilation
// 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(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
Local<v8::UnboundScript> compiled_script =
v8::ScriptCompiler::CompileUnbound(isolate, &script_source);
v8::ScriptCompiler::CompileUnbound(isolate, &source2);
CHECK(try_catch.HasCaught());
String::Utf8Value exception_value(try_catch.Message()->Get());
......@@ -14950,19 +14922,20 @@ TEST(PreCompileInvalidPreparseDataError) {
// 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
// back on eager compilation.
sd = v8::ScriptData::PreCompile(v8::String::NewFromUtf8(
isolate, script, v8::String::kNormalString, i::StrLength(script)));
// ScriptData does not take ownership of the buffers passed to it.
sd = v8::ScriptData::New(reinterpret_cast<const char*>(cd->data), cd->length);
sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data()));
sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] =
200;
v8::ScriptCompiler::Source script_source2(
String::NewFromUtf8(isolate, script),
const char* script3 = "function foo(){ return 7;}\n"
"function bar(){ return 6 + 7;} foo();";
v8::ScriptCompiler::Source source3(
v8_str(script3),
new v8::ScriptCompiler::CachedData(
reinterpret_cast<const uint8_t*>(sd->Data()), sd->Length()));
compiled_script =
v8::ScriptCompiler::CompileUnbound(isolate, &script_source2);
v8::ScriptCompiler::CompileUnbound(isolate, &source3);
CHECK(!try_catch.HasCaught());
delete sd;
}
......
This diff is collapsed.
......@@ -44,15 +44,9 @@
using namespace v8::internal;
enum TestMode {
PreParseAndParse,
PreParse,
Parse
};
std::pair<TimeDelta, TimeDelta> RunBaselineParser(
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;
const byte* source = ReadFileAndRepeat(fname, &length, repeat);
v8::Handle<v8::String> source_handle;
......@@ -73,42 +67,41 @@ std::pair<TimeDelta, TimeDelta> RunBaselineParser(
break;
}
}
v8::ScriptData* cached_data = NULL;
TimeDelta preparse_time, parse_time;
if (test_mode == PreParseAndParse || test_mode == PreParse) {
TimeDelta parse_time1, parse_time2;
Handle<Script> script = Isolate::Current()->factory()->NewScript(
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;
timer.Start();
cached_data = v8::ScriptData::PreCompile(source_handle);
preparse_time = timer.Elapsed();
if (cached_data == NULL || cached_data->HasError()) {
fprintf(stderr, "Preparsing failed\n");
// Allow lazy parsing; otherwise we won't produce cached data.
bool success = Parser::Parse(&info, true);
parse_time1 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
return std::make_pair(TimeDelta(), TimeDelta());
}
}
if (test_mode == PreParseAndParse || test_mode == Parse) {
Handle<String> str = v8::Utils::OpenHandle(*source_handle);
i::Isolate* internal_isolate = str->GetIsolate();
Handle<Script> script = internal_isolate->factory()->NewScript(str);
// Second round of parsing (consume cached data).
{
CompilationInfoWithZone info(script);
info.MarkAsGlobal();
i::ScriptDataImpl* cached_data_impl =
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));
info.SetCachedData(&cached_data_impl, i::CONSUME_CACHED_DATA);
ElapsedTimer timer;
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);
parse_time = timer.Elapsed();
parse_time2 = timer.Elapsed();
if (!success) {
fprintf(stderr, "Parsing failed\n");
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[]) {
v8::V8::InitializeICU();
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
Encoding encoding = LATIN1;
TestMode test_mode = PreParseAndParse;
std::vector<std::string> fnames;
std::string benchmark;
int repeat = 1;
......@@ -127,12 +119,6 @@ int main(int argc, char* argv[]) {
encoding = UTF8;
} else if (strcmp(argv[i], "--utf16") == 0) {
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) {
benchmark = std::string(argv[i]).substr(12);
} else if (strncmp(argv[i], "--repeat=", 9) == 0) {
......@@ -150,20 +136,19 @@ int main(int argc, char* argv[]) {
ASSERT(!context.IsEmpty());
{
v8::Context::Scope scope(context);
double preparse_total = 0;
double parse_total = 0;
double first_parse_total = 0;
double second_parse_total = 0;
for (size_t i = 0; i < fnames.size(); i++) {
std::pair<TimeDelta, TimeDelta> time = RunBaselineParser(
fnames[i].c_str(), encoding, repeat, isolate, context, test_mode);
preparse_total += time.first.InMillisecondsF();
parse_total += time.second.InMillisecondsF();
fnames[i].c_str(), encoding, repeat, isolate, context);
first_parse_total += time.first.InMillisecondsF();
second_parse_total += time.second.InMillisecondsF();
}
if (benchmark.empty()) benchmark = "Baseline";
printf("%s(PreParseRunTime): %.f ms\n", benchmark.c_str(),
preparse_total);
printf("%s(ParseRunTime): %.f ms\n", benchmark.c_str(), parse_total);
printf("%s(RunTime): %.f ms\n", benchmark.c_str(),
preparse_total + parse_total);
printf("%s(FirstParseRunTime): %.f ms\n", benchmark.c_str(),
first_parse_total);
printf("%s(SecondParseRunTime): %.f ms\n", benchmark.c_str(),
second_parse_total);
}
}
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