Commit 4b5ff0c5 authored by yangguo's avatar yangguo Committed by Commit bot

Attach snapshot data blob to the isolate.

R=vogelheim@chromium.org
BUG=chromium:461259
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#26845}
parent fd35be40
...@@ -92,6 +92,7 @@ class Promise; ...@@ -92,6 +92,7 @@ class Promise;
class RawOperationDescriptor; class RawOperationDescriptor;
class Script; class Script;
class Signature; class Signature;
class StartupData;
class StackFrame; class StackFrame;
class StackTrace; class StackTrace;
class String; class String;
...@@ -4644,9 +4645,7 @@ class V8_EXPORT Isolate { ...@@ -4644,9 +4645,7 @@ class V8_EXPORT Isolate {
*/ */
struct CreateParams { struct CreateParams {
CreateParams() CreateParams()
: entry_hook(NULL), : entry_hook(NULL), code_event_handler(NULL), snapshot_blob(NULL) {}
code_event_handler(NULL),
enable_serializer(false) {}
/** /**
* The optional entry_hook allows the host application to provide the * The optional entry_hook allows the host application to provide the
...@@ -4669,9 +4668,9 @@ class V8_EXPORT Isolate { ...@@ -4669,9 +4668,9 @@ class V8_EXPORT Isolate {
ResourceConstraints constraints; ResourceConstraints constraints;
/** /**
* This flag currently renders the Isolate unusable. * Explicitly specify a startup snapshot blob. The embedder owns the blob.
*/ */
bool enable_serializer; StartupData* snapshot_blob;
}; };
...@@ -5397,7 +5396,7 @@ class V8_EXPORT V8 { ...@@ -5397,7 +5396,7 @@ class V8_EXPORT V8 {
* Returns { NULL, 0 } on failure. * Returns { NULL, 0 } on failure.
* The caller owns the data array in the return value. * The caller owns the data array in the return value.
*/ */
static StartupData CreateSnapshotDataBlob(char* custom_source = NULL); static StartupData CreateSnapshotDataBlob(const char* custom_source = NULL);
/** /**
* Adds a message listener. * Adds a message listener.
......
...@@ -207,7 +207,7 @@ void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) { ...@@ -207,7 +207,7 @@ void V8::SetSnapshotDataBlob(StartupData* snapshot_blob) {
} }
bool RunExtraCode(Isolate* isolate, char* utf8_source) { bool RunExtraCode(Isolate* isolate, const char* utf8_source) {
// Run custom script if provided. // Run custom script if provided.
TryCatch try_catch; TryCatch try_catch;
Local<String> source_string = String::NewFromUtf8(isolate, utf8_source); Local<String> source_string = String::NewFromUtf8(isolate, utf8_source);
...@@ -221,14 +221,13 @@ bool RunExtraCode(Isolate* isolate, char* utf8_source) { ...@@ -221,14 +221,13 @@ bool RunExtraCode(Isolate* isolate, char* utf8_source) {
} }
StartupData V8::CreateSnapshotDataBlob(char* custom_source) { StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
Isolate::CreateParams params; i::Isolate* internal_isolate = new i::Isolate(true);
params.enable_serializer = true; Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate);
Isolate* isolate = v8::Isolate::New(params);
StartupData result = {NULL, 0}; StartupData result = {NULL, 0};
{ {
Isolate::Scope isolate_scope(isolate); Isolate::Scope isolate_scope(isolate);
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate); internal_isolate->Init(NULL);
Persistent<Context> context; Persistent<Context> context;
i::Snapshot::Metadata metadata; i::Snapshot::Metadata metadata;
{ {
...@@ -6524,8 +6523,13 @@ Isolate* Isolate::GetCurrent() { ...@@ -6524,8 +6523,13 @@ Isolate* Isolate::GetCurrent() {
Isolate* Isolate::New(const Isolate::CreateParams& params) { Isolate* Isolate::New(const Isolate::CreateParams& params) {
i::Isolate* isolate = new i::Isolate(params.enable_serializer); i::Isolate* isolate = new i::Isolate(false);
Isolate* v8_isolate = reinterpret_cast<Isolate*>(isolate); Isolate* v8_isolate = reinterpret_cast<Isolate*>(isolate);
if (params.snapshot_blob != NULL) {
isolate->set_snapshot_blob(params.snapshot_blob);
} else {
isolate->set_snapshot_blob(i::Snapshot::DefaultSnapshotBlob());
}
if (params.entry_hook) { if (params.entry_hook) {
isolate->set_function_entry_hook(params.entry_hook); isolate->set_function_entry_hook(params.entry_hook);
} }
...@@ -6540,6 +6544,12 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) { ...@@ -6540,6 +6544,12 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) {
if (params.entry_hook || !i::Snapshot::Initialize(isolate)) { if (params.entry_hook || !i::Snapshot::Initialize(isolate)) {
// If the isolate has a function entry hook, it needs to re-build all its // If the isolate has a function entry hook, it needs to re-build all its
// code stubs with entry hooks embedded, so don't deserialize a snapshot. // code stubs with entry hooks embedded, so don't deserialize a snapshot.
if (i::Snapshot::EmbedsScript(isolate)) {
// If the snapshot embeds a script, we cannot initialize the isolate
// without the snapshot as a fallback. This is unlikely to happen though.
V8_Fatal(__FILE__, __LINE__,
"Initializing isolate from custom startup snapshot failed");
}
isolate->Init(NULL); isolate->Init(NULL);
} }
return v8_isolate; return v8_isolate;
......
...@@ -422,9 +422,8 @@ void FullCodeGenerator::Initialize() { ...@@ -422,9 +422,8 @@ void FullCodeGenerator::Initialize() {
// calculating PC offsets after generating a debug version of code. Therefore // calculating PC offsets after generating a debug version of code. Therefore
// we disable the production of debug code in the full compiler if we are // we disable the production of debug code in the full compiler if we are
// either generating a snapshot or we booted from a snapshot. // either generating a snapshot or we booted from a snapshot.
generate_debug_code_ = FLAG_debug_code && generate_debug_code_ = FLAG_debug_code && !masm_->serializer_enabled() &&
!masm_->serializer_enabled() && !info_->isolate()->snapshot_available();
!Snapshot::HaveASnapshotToStartFrom();
masm_->set_emit_debug_code(generate_debug_code_); masm_->set_emit_debug_code(generate_debug_code_);
masm_->set_predictable_code_size(true); masm_->set_predictable_code_size(true);
} }
......
...@@ -5195,7 +5195,7 @@ bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size, ...@@ -5195,7 +5195,7 @@ bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size,
max_semi_space_size_ = Page::kPageSize; max_semi_space_size_ = Page::kPageSize;
} }
if (Snapshot::HaveASnapshotToStartFrom()) { if (isolate()->snapshot_available()) {
// If we are using a snapshot we always reserve the default amount // If we are using a snapshot we always reserve the default amount
// of memory for each semispace because code in the snapshot has // of memory for each semispace because code in the snapshot has
// write-barrier code that relies on the size and alignment of new // write-barrier code that relies on the size and alignment of new
......
...@@ -1039,7 +1039,7 @@ bool PagedSpace::Expand() { ...@@ -1039,7 +1039,7 @@ bool PagedSpace::Expand() {
intptr_t size = AreaSize(); intptr_t size = AreaSize();
if (anchor_.next_page() == &anchor_) { if (anchor_.next_page() == &anchor_) {
size = Snapshot::SizeOfFirstPage(identity()); size = Snapshot::SizeOfFirstPage(heap()->isolate(), identity());
} }
Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this, Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this,
......
...@@ -381,6 +381,7 @@ typedef List<HeapObject*> DebugObjectCache; ...@@ -381,6 +381,7 @@ typedef List<HeapObject*> DebugObjectCache;
V(int, max_available_threads, 0) \ V(int, max_available_threads, 0) \
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \ V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
V(PromiseRejectCallback, promise_reject_callback, NULL) \ V(PromiseRejectCallback, promise_reject_callback, NULL) \
V(const v8::StartupData*, snapshot_blob, NULL) \
ISOLATE_INIT_SIMULATOR_LIST(V) ISOLATE_INIT_SIMULATOR_LIST(V)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \ #define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
...@@ -993,6 +994,7 @@ class Isolate { ...@@ -993,6 +994,7 @@ class Isolate {
} }
bool serializer_enabled() const { return serializer_enabled_; } bool serializer_enabled() const { return serializer_enabled_; }
bool snapshot_available() const { return snapshot_blob_ != NULL; }
bool IsDead() { return has_fatal_error_; } bool IsDead() { return has_fatal_error_; }
void SignalFatalError() { has_fatal_error_ = true; } void SignalFatalError() { has_fatal_error_ = true; }
...@@ -1128,9 +1130,10 @@ class Isolate { ...@@ -1128,9 +1130,10 @@ class Isolate {
List<Object*>* partial_snapshot_cache() { return &partial_snapshot_cache_; } List<Object*>* partial_snapshot_cache() { return &partial_snapshot_cache_; }
private: protected:
explicit Isolate(bool enable_serializer); explicit Isolate(bool enable_serializer);
private:
friend struct GlobalState; friend struct GlobalState;
friend struct InitializeGlobalState; friend struct InitializeGlobalState;
...@@ -1364,6 +1367,7 @@ class Isolate { ...@@ -1364,6 +1367,7 @@ class Isolate {
friend class v8::Isolate; friend class v8::Isolate;
friend class v8::Locker; friend class v8::Locker;
friend class v8::Unlocker; friend class v8::Unlocker;
friend v8::StartupData v8::V8::CreateSnapshotDataBlob(const char*);
DISALLOW_COPY_AND_ASSIGN(Isolate); DISALLOW_COPY_AND_ASSIGN(Isolate);
}; };
......
...@@ -70,11 +70,8 @@ class SnapshotWriter { ...@@ -70,11 +70,8 @@ class SnapshotWriter {
} }
void WriteFileSuffix() const { void WriteFileSuffix() const {
fprintf(fp_, "const v8::StartupData Snapshot::SnapshotBlob() {\n"); fprintf(fp_, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n");
fprintf(fp_, " v8::StartupData blob;\n"); fprintf(fp_, " return &blob;\n");
fprintf(fp_, " blob.data = reinterpret_cast<const char*>(blob_data);\n");
fprintf(fp_, " blob.raw_size = blob_size;\n");
fprintf(fp_, " return blob;\n");
fprintf(fp_, "}\n\n"); fprintf(fp_, "}\n\n");
fprintf(fp_, "} // namespace internal\n"); fprintf(fp_, "} // namespace internal\n");
fprintf(fp_, "} // namespace v8\n"); fprintf(fp_, "} // namespace v8\n");
...@@ -85,7 +82,8 @@ class SnapshotWriter { ...@@ -85,7 +82,8 @@ class SnapshotWriter {
WriteSnapshotData(blob); WriteSnapshotData(blob);
fprintf(fp_, "};\n"); fprintf(fp_, "};\n");
fprintf(fp_, "static const int blob_size = %d;\n", blob.length()); fprintf(fp_, "static const int blob_size = %d;\n", blob.length());
fprintf(fp_, "\n"); fprintf(fp_, "static const v8::StartupData blob =\n");
fprintf(fp_, "{ (const char*) blob_data, blob_size };\n");
} }
void WriteSnapshotData(const i::Vector<const i::byte>& blob) const { void WriteSnapshotData(const i::Vector<const i::byte>& blob) const {
......
...@@ -14,11 +14,6 @@ ...@@ -14,11 +14,6 @@
namespace v8 { namespace v8 {
namespace internal { namespace internal {
bool Snapshot::HaveASnapshotToStartFrom() {
return SnapshotBlob().data != NULL;
}
#ifdef DEBUG #ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() && return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
...@@ -27,32 +22,31 @@ bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) { ...@@ -27,32 +22,31 @@ bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
#endif // DEBUG #endif // DEBUG
bool Snapshot::EmbedsScript() { bool Snapshot::EmbedsScript(Isolate* isolate) {
if (!HaveASnapshotToStartFrom()) return false; if (!isolate->snapshot_available()) return false;
const v8::StartupData blob = SnapshotBlob(); return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
return ExtractMetadata(&blob).embeds_script();
} }
uint32_t Snapshot::SizeOfFirstPage(AllocationSpace space) { uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE); DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
if (!HaveASnapshotToStartFrom()) { if (!isolate->snapshot_available()) {
return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space)); return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
} }
uint32_t size; uint32_t size;
int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size; int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
memcpy(&size, SnapshotBlob().data + offset, kInt32Size); memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
return size; return size;
} }
bool Snapshot::Initialize(Isolate* isolate) { bool Snapshot::Initialize(Isolate* isolate) {
if (!HaveASnapshotToStartFrom()) return false; if (!isolate->snapshot_available()) return false;
base::ElapsedTimer timer; base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start(); if (FLAG_profile_deserialization) timer.Start();
const v8::StartupData blob = SnapshotBlob(); const v8::StartupData* blob = isolate->snapshot_blob();
Vector<const byte> startup_data = ExtractStartupData(&blob); Vector<const byte> startup_data = ExtractStartupData(blob);
SnapshotData snapshot_data(startup_data); SnapshotData snapshot_data(startup_data);
Deserializer deserializer(&snapshot_data); Deserializer deserializer(&snapshot_data);
bool success = isolate->Init(&deserializer); bool success = isolate->Init(&deserializer);
...@@ -68,12 +62,12 @@ bool Snapshot::Initialize(Isolate* isolate) { ...@@ -68,12 +62,12 @@ bool Snapshot::Initialize(Isolate* isolate) {
MaybeHandle<Context> Snapshot::NewContextFromSnapshot( MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy, Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out) { Handle<FixedArray>* outdated_contexts_out) {
if (!HaveASnapshotToStartFrom()) return Handle<Context>(); if (!isolate->snapshot_available()) return Handle<Context>();
base::ElapsedTimer timer; base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start(); if (FLAG_profile_deserialization) timer.Start();
const v8::StartupData blob = SnapshotBlob(); const v8::StartupData* blob = isolate->snapshot_blob();
Vector<const byte> context_data = ExtractContextData(&blob); Vector<const byte> context_data = ExtractContextData(blob);
SnapshotData snapshot_data(context_data); SnapshotData snapshot_data(context_data);
Deserializer deserializer(&snapshot_data); Deserializer deserializer(&snapshot_data);
...@@ -84,7 +78,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot( ...@@ -84,7 +78,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
CHECK(result->IsContext()); CHECK(result->IsContext());
// If the snapshot does not contain a custom script, we need to update // If the snapshot does not contain a custom script, we need to update
// the global object for exactly one context. // the global object for exactly one context.
CHECK(EmbedsScript() || (*outdated_contexts_out)->length() == 1); CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
if (FLAG_profile_deserialization) { if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF(); double ms = timer.Elapsed().InMillisecondsF();
int bytes = context_data.length(); int bytes = context_data.length();
......
...@@ -22,7 +22,5 @@ void SetSnapshotFromFile(StartupData* data) { CHECK(false); } ...@@ -22,7 +22,5 @@ void SetSnapshotFromFile(StartupData* data) { CHECK(false); }
#endif // V8_USE_EXTERNAL_STARTUP_DATA #endif // V8_USE_EXTERNAL_STARTUP_DATA
const v8::StartupData Snapshot::SnapshotBlob() { const v8::StartupData* Snapshot::DefaultSnapshotBlob() { return NULL; }
return {NULL, 0};
}
} } // namespace v8::internal } } // namespace v8::internal
...@@ -35,9 +35,9 @@ void SetSnapshotFromFile(StartupData* snapshot_blob) { ...@@ -35,9 +35,9 @@ void SetSnapshotFromFile(StartupData* snapshot_blob) {
} }
const v8::StartupData Snapshot::SnapshotBlob() { const v8::StartupData* Snapshot::DefaultSnapshotBlob() {
base::LockGuard<base::Mutex> lock_guard( base::LockGuard<base::Mutex> lock_guard(
external_startup_data_mutex.Pointer()); external_startup_data_mutex.Pointer());
return external_startup_blob; return &external_startup_blob;
} }
} } // namespace v8::internal } } // namespace v8::internal
...@@ -36,14 +36,18 @@ class Snapshot : public AllStatic { ...@@ -36,14 +36,18 @@ class Snapshot : public AllStatic {
Isolate* isolate, Handle<JSGlobalProxy> global_proxy, Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out); Handle<FixedArray>* outdated_contexts_out);
static bool HaveASnapshotToStartFrom(); static bool HaveASnapshotToStartFrom(Isolate* isolate) {
// Do not use snapshots if the isolate is used to create snapshots.
return isolate->snapshot_blob() != NULL;
}
static bool EmbedsScript(Isolate* isolate);
static bool EmbedsScript(); static uint32_t SizeOfFirstPage(Isolate* isolate, AllocationSpace space);
static uint32_t SizeOfFirstPage(AllocationSpace space);
// To be implemented by the snapshot source. // To be implemented by the snapshot source.
static const v8::StartupData SnapshotBlob(); static const v8::StartupData* DefaultSnapshotBlob();
static v8::StartupData CreateSnapshotBlob( static v8::StartupData CreateSnapshotBlob(
const StartupSerializer& startup_ser, const StartupSerializer& startup_ser,
......
...@@ -5073,10 +5073,10 @@ TEST(Regress442710) { ...@@ -5073,10 +5073,10 @@ TEST(Regress442710) {
TEST(NumberStringCacheSize) { TEST(NumberStringCacheSize) {
if (!Snapshot::HaveASnapshotToStartFrom()) return;
// Test that the number-string cache has not been resized in the snapshot. // Test that the number-string cache has not been resized in the snapshot.
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
if (!isolate->snapshot_available()) return;
Heap* heap = isolate->heap(); Heap* heap = isolate->heap();
CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2, CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2,
heap->number_string_cache()->length()); heap->number_string_cache()->length());
...@@ -5093,25 +5093,3 @@ TEST(PathTracer) { ...@@ -5093,25 +5093,3 @@ TEST(PathTracer) {
CcTest::i_isolate()->heap()->TracePathToObject(*o); CcTest::i_isolate()->heap()->TracePathToObject(*o);
} }
#endif // DEBUG #endif // DEBUG
TEST(FirstPageFitsStartup) {
// Test that the first page sizes provided by the default snapshot are large
// enough to fit everything right after startup and creating one context.
// If this test fails, we are allocating too much aside from deserialization.
if (!Snapshot::HaveASnapshotToStartFrom()) return;
if (Snapshot::EmbedsScript()) return;
CcTest::InitializeVM();
LocalContext env;
PagedSpaces spaces(CcTest::heap());
for (PagedSpace* s = spaces.next(); s != NULL; s = spaces.next()) {
uint32_t default_size = s->AreaSize();
uint32_t reduced_size = Snapshot::SizeOfFirstPage(s->identity());
if (reduced_size == default_size) continue;
int counter = 0;
Page* page = NULL;
for (PageIterator it(s); it.has_next(); page = it.next()) counter++;
CHECK_LE(counter, 1);
CHECK(static_cast<uint32_t>(page->area_size()) == reduced_size);
}
}
This diff is collapsed.
...@@ -437,9 +437,10 @@ TEST(LargeObjectSpace) { ...@@ -437,9 +437,10 @@ TEST(LargeObjectSpace) {
TEST(SizeOfFirstPageIsLargeEnough) { TEST(SizeOfFirstPageIsLargeEnough) {
if (i::FLAG_always_opt) return; if (i::FLAG_always_opt) return;
// Bootstrapping without a snapshot causes more allocations. // Bootstrapping without a snapshot causes more allocations.
if (!i::Snapshot::HaveASnapshotToStartFrom()) return;
CcTest::InitializeVM(); CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate(); Isolate* isolate = CcTest::i_isolate();
if (!isolate->snapshot_available()) return;
if (Snapshot::EmbedsScript(isolate)) return;
// Freshly initialized VM gets by with one page per space. // Freshly initialized VM gets by with one page per space.
for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) { for (int i = FIRST_PAGED_SPACE; i <= LAST_PAGED_SPACE; i++) {
......
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