Commit 13a68e6c authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

[snapshot] make API external references optional.

In snapshots with several contexts, some contexts may not reference
function or object templates, and therefore would not require external
references for deserialization. However, function and object templates
are deserialized with the isolate as part of the partial snapshot cache,
so we would need these external references even if we only use contexts
that don't need them.

With this patch, we use a fallback in case no external references are
provided. This way, we only run into issues when we actually call native
callbacks.

R=jgruber@chromium.org, peria@chromium.org

Change-Id: I6af8a77f26c92bd73fdab6112474c62da270597f
Reviewed-on: https://chromium-review.googlesource.com/784831Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Yang Guo <yangguo@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49615}
parent 6056d32b
......@@ -749,8 +749,8 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) {
DCHECK_EQ(current->type(), type);
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
......
......@@ -490,8 +490,8 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) {
DCHECK_EQ(current->type(), type);
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
......
......@@ -968,7 +968,10 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) return current;
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
return new Redirection(isolate, external_function, type);
}
......
......@@ -901,7 +901,10 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) return current;
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
return new Redirection(isolate, external_function, type);
}
......
......@@ -834,8 +834,8 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) {
DCHECK_EQ(current->type(), type);
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
......
......@@ -1585,8 +1585,8 @@ class Redirection {
ExternalReference::Type type) {
Redirection* current = isolate->simulator_redirection();
for (; current != nullptr; current = current->next_) {
if (current->external_function_ == external_function) {
DCHECK_EQ(current->type(), type);
if (current->external_function_ == external_function &&
current->type_ == type) {
return current;
}
}
......
......@@ -323,6 +323,14 @@ Object* Deserializer<AllocatorT>::ReadDataSingle() {
return o;
}
static void NoExternalReferencesCallback() {
// The following check will trigger if a function or object template
// with references to native functions have been deserialized from
// snapshot, but no actual external references were provided when the
// isolate was created.
CHECK_WITH_MSG(false, "No external references provided via API");
}
template <class AllocatorT>
bool Deserializer<AllocatorT>::ReadData(Object** current, Object** limit,
int source_space,
......@@ -534,10 +542,16 @@ bool Deserializer<AllocatorT>::ReadData(Object** current, Object** limit,
current = reinterpret_cast<Object**>(
reinterpret_cast<Address>(current) + skip);
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
DCHECK_WITH_MSG(reference_id < num_api_references_,
"too few external references provided through the API");
Address address = reinterpret_cast<Address>(
isolate->api_external_references()[reference_id]);
Address address;
if (isolate->api_external_references()) {
DCHECK_WITH_MSG(
reference_id < num_api_references_,
"too few external references provided through the API");
address = reinterpret_cast<Address>(
isolate->api_external_references()[reference_id]);
} else {
address = reinterpret_cast<Address>(NoExternalReferencesCallback);
}
memcpy(current, &address, kPointerSize);
current++;
break;
......
......@@ -104,6 +104,8 @@
# Test that serialization with unknown external reference fails.
'test-serialize/SnapshotCreatorUnknownExternalReferences': [FAIL],
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail1': [FAIL],
'test-serialize/SnapshotCreatorNoExternalReferencesCustomFail2': [FAIL],
############################################################################
# Slow tests.
......
......@@ -2364,6 +2364,114 @@ TEST(SnapshotCreatorShortExternalReferences) {
delete[] blob.data;
}
v8::StartupData CreateSnapshotWithDefaultAndCustom() {
v8::SnapshotCreator creator(original_external_references);
v8::Isolate* isolate = creator.GetIsolate();
{
v8::HandleScope handle_scope(isolate);
{
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
CompileRun("function f() { return 41; }");
creator.SetDefaultContext(context);
ExpectInt32("f()", 41);
}
{
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::FunctionTemplate> function_template =
v8::FunctionTemplate::New(isolate, SerializedCallback);
v8::Local<v8::Value> function =
function_template->GetFunction(context).ToLocalChecked();
CHECK(context->Global()->Set(context, v8_str("f"), function).FromJust());
v8::Local<v8::ObjectTemplate> object_template =
v8::ObjectTemplate::New(isolate);
object_template->SetAccessor(v8_str("x"), AccessorForSerialization);
v8::Local<v8::Object> object =
object_template->NewInstance(context).ToLocalChecked();
CHECK(context->Global()->Set(context, v8_str("o"), object).FromJust());
ExpectInt32("f()", 42);
ExpectInt32("o.x", 2017);
creator.AddContext(context);
}
}
return creator.CreateBlob(v8::SnapshotCreator::FunctionCodeHandling::kClear);
}
TEST(SnapshotCreatorNoExternalReferencesDefault) {
DisableAlwaysOpt();
v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
// Deserialize with an incomplete list of external references.
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
params.external_references = nullptr;
// Test-appropriate equivalent of v8::Isolate::New.
v8::Isolate* isolate = TestIsolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context = v8::Context::New(isolate);
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 41);
}
isolate->Dispose();
}
delete[] blob.data;
}
TEST(SnapshotCreatorNoExternalReferencesCustomFail1) {
DisableAlwaysOpt();
v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
// Deserialize with an incomplete list of external references.
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
params.external_references = nullptr;
// Test-appropriate equivalent of v8::Isolate::New.
v8::Isolate* isolate = TestIsolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Context::Scope context_scope(context);
ExpectInt32("f()", 42);
}
isolate->Dispose();
}
delete[] blob.data;
}
TEST(SnapshotCreatorNoExternalReferencesCustomFail2) {
DisableAlwaysOpt();
v8::StartupData blob = CreateSnapshotWithDefaultAndCustom();
// Deserialize with an incomplete list of external references.
{
v8::Isolate::CreateParams params;
params.snapshot_blob = &blob;
params.array_buffer_allocator = CcTest::array_buffer_allocator();
params.external_references = nullptr;
// Test-appropriate equivalent of v8::Isolate::New.
v8::Isolate* isolate = TestIsolate::New(params);
{
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Context::FromSnapshot(isolate, 0).ToLocalChecked();
v8::Context::Scope context_scope(context);
ExpectInt32("o.x", 2017);
}
isolate->Dispose();
}
delete[] blob.data;
}
TEST(SnapshotCreatorUnknownExternalReferences) {
DisableAlwaysOpt();
v8::SnapshotCreator creator;
......
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