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;
class RawOperationDescriptor;
class Script;
class Signature;
class StartupData;
class StackFrame;
class StackTrace;
class String;
......@@ -4644,9 +4645,7 @@ class V8_EXPORT Isolate {
*/
struct CreateParams {
CreateParams()
: entry_hook(NULL),
code_event_handler(NULL),
enable_serializer(false) {}
: entry_hook(NULL), code_event_handler(NULL), snapshot_blob(NULL) {}
/**
* The optional entry_hook allows the host application to provide the
......@@ -4669,9 +4668,9 @@ class V8_EXPORT Isolate {
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 {
* Returns { NULL, 0 } on failure.
* 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.
......
......@@ -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.
TryCatch try_catch;
Local<String> source_string = String::NewFromUtf8(isolate, utf8_source);
......@@ -221,14 +221,13 @@ bool RunExtraCode(Isolate* isolate, char* utf8_source) {
}
StartupData V8::CreateSnapshotDataBlob(char* custom_source) {
Isolate::CreateParams params;
params.enable_serializer = true;
Isolate* isolate = v8::Isolate::New(params);
StartupData V8::CreateSnapshotDataBlob(const char* custom_source) {
i::Isolate* internal_isolate = new i::Isolate(true);
Isolate* isolate = reinterpret_cast<Isolate*>(internal_isolate);
StartupData result = {NULL, 0};
{
Isolate::Scope isolate_scope(isolate);
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->Init(NULL);
Persistent<Context> context;
i::Snapshot::Metadata metadata;
{
......@@ -6524,8 +6523,13 @@ Isolate* Isolate::GetCurrent() {
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);
if (params.snapshot_blob != NULL) {
isolate->set_snapshot_blob(params.snapshot_blob);
} else {
isolate->set_snapshot_blob(i::Snapshot::DefaultSnapshotBlob());
}
if (params.entry_hook) {
isolate->set_function_entry_hook(params.entry_hook);
}
......@@ -6540,6 +6544,12 @@ Isolate* Isolate::New(const Isolate::CreateParams& params) {
if (params.entry_hook || !i::Snapshot::Initialize(isolate)) {
// 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.
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);
}
return v8_isolate;
......
......@@ -422,9 +422,8 @@ void FullCodeGenerator::Initialize() {
// 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
// either generating a snapshot or we booted from a snapshot.
generate_debug_code_ = FLAG_debug_code &&
!masm_->serializer_enabled() &&
!Snapshot::HaveASnapshotToStartFrom();
generate_debug_code_ = FLAG_debug_code && !masm_->serializer_enabled() &&
!info_->isolate()->snapshot_available();
masm_->set_emit_debug_code(generate_debug_code_);
masm_->set_predictable_code_size(true);
}
......
......@@ -5195,7 +5195,7 @@ bool Heap::ConfigureHeap(int max_semi_space_size, int max_old_space_size,
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
// of memory for each semispace because code in the snapshot has
// write-barrier code that relies on the size and alignment of new
......
......@@ -1039,7 +1039,7 @@ bool PagedSpace::Expand() {
intptr_t size = AreaSize();
if (anchor_.next_page() == &anchor_) {
size = Snapshot::SizeOfFirstPage(identity());
size = Snapshot::SizeOfFirstPage(heap()->isolate(), identity());
}
Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this,
......
......@@ -381,6 +381,7 @@ typedef List<HeapObject*> DebugObjectCache;
V(int, max_available_threads, 0) \
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
V(PromiseRejectCallback, promise_reject_callback, NULL) \
V(const v8::StartupData*, snapshot_blob, NULL) \
ISOLATE_INIT_SIMULATOR_LIST(V)
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
......@@ -993,6 +994,7 @@ class Isolate {
}
bool serializer_enabled() const { return serializer_enabled_; }
bool snapshot_available() const { return snapshot_blob_ != NULL; }
bool IsDead() { return has_fatal_error_; }
void SignalFatalError() { has_fatal_error_ = true; }
......@@ -1128,9 +1130,10 @@ class Isolate {
List<Object*>* partial_snapshot_cache() { return &partial_snapshot_cache_; }
private:
protected:
explicit Isolate(bool enable_serializer);
private:
friend struct GlobalState;
friend struct InitializeGlobalState;
......@@ -1364,6 +1367,7 @@ class Isolate {
friend class v8::Isolate;
friend class v8::Locker;
friend class v8::Unlocker;
friend v8::StartupData v8::V8::CreateSnapshotDataBlob(const char*);
DISALLOW_COPY_AND_ASSIGN(Isolate);
};
......
......@@ -70,11 +70,8 @@ class SnapshotWriter {
}
void WriteFileSuffix() const {
fprintf(fp_, "const v8::StartupData Snapshot::SnapshotBlob() {\n");
fprintf(fp_, " v8::StartupData 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_, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n");
fprintf(fp_, " return &blob;\n");
fprintf(fp_, "}\n\n");
fprintf(fp_, "} // namespace internal\n");
fprintf(fp_, "} // namespace v8\n");
......@@ -85,7 +82,8 @@ class SnapshotWriter {
WriteSnapshotData(blob);
fprintf(fp_, "};\n");
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 {
......
......@@ -14,11 +14,6 @@
namespace v8 {
namespace internal {
bool Snapshot::HaveASnapshotToStartFrom() {
return SnapshotBlob().data != NULL;
}
#ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
......@@ -27,32 +22,31 @@ bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
#endif // DEBUG
bool Snapshot::EmbedsScript() {
if (!HaveASnapshotToStartFrom()) return false;
const v8::StartupData blob = SnapshotBlob();
return ExtractMetadata(&blob).embeds_script();
bool Snapshot::EmbedsScript(Isolate* isolate) {
if (!isolate->snapshot_available()) return false;
return ExtractMetadata(isolate->snapshot_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);
if (!HaveASnapshotToStartFrom()) {
if (!isolate->snapshot_available()) {
return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
}
uint32_t size;
int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
memcpy(&size, SnapshotBlob().data + offset, kInt32Size);
memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
return size;
}
bool Snapshot::Initialize(Isolate* isolate) {
if (!HaveASnapshotToStartFrom()) return false;
if (!isolate->snapshot_available()) return false;
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
const v8::StartupData blob = SnapshotBlob();
Vector<const byte> startup_data = ExtractStartupData(&blob);
const v8::StartupData* blob = isolate->snapshot_blob();
Vector<const byte> startup_data = ExtractStartupData(blob);
SnapshotData snapshot_data(startup_data);
Deserializer deserializer(&snapshot_data);
bool success = isolate->Init(&deserializer);
......@@ -68,12 +62,12 @@ bool Snapshot::Initialize(Isolate* isolate) {
MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
Handle<FixedArray>* outdated_contexts_out) {
if (!HaveASnapshotToStartFrom()) return Handle<Context>();
if (!isolate->snapshot_available()) return Handle<Context>();
base::ElapsedTimer timer;
if (FLAG_profile_deserialization) timer.Start();
const v8::StartupData blob = SnapshotBlob();
Vector<const byte> context_data = ExtractContextData(&blob);
const v8::StartupData* blob = isolate->snapshot_blob();
Vector<const byte> context_data = ExtractContextData(blob);
SnapshotData snapshot_data(context_data);
Deserializer deserializer(&snapshot_data);
......@@ -84,7 +78,7 @@ MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
CHECK(result->IsContext());
// If the snapshot does not contain a custom script, we need to update
// 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) {
double ms = timer.Elapsed().InMillisecondsF();
int bytes = context_data.length();
......
......@@ -22,7 +22,5 @@ void SetSnapshotFromFile(StartupData* data) { CHECK(false); }
#endif // V8_USE_EXTERNAL_STARTUP_DATA
const v8::StartupData Snapshot::SnapshotBlob() {
return {NULL, 0};
}
const v8::StartupData* Snapshot::DefaultSnapshotBlob() { return NULL; }
} } // namespace v8::internal
......@@ -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(
external_startup_data_mutex.Pointer());
return external_startup_blob;
return &external_startup_blob;
}
} } // namespace v8::internal
......@@ -36,14 +36,18 @@ class Snapshot : public AllStatic {
Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
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.
static const v8::StartupData SnapshotBlob();
static const v8::StartupData* DefaultSnapshotBlob();
static v8::StartupData CreateSnapshotBlob(
const StartupSerializer& startup_ser,
......
......@@ -5073,10 +5073,10 @@ TEST(Regress442710) {
TEST(NumberStringCacheSize) {
if (!Snapshot::HaveASnapshotToStartFrom()) return;
// Test that the number-string cache has not been resized in the snapshot.
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
if (!isolate->snapshot_available()) return;
Heap* heap = isolate->heap();
CHECK_EQ(TestHeap::kInitialNumberStringCacheSize * 2,
heap->number_string_cache()->length());
......@@ -5093,25 +5093,3 @@ TEST(PathTracer) {
CcTest::i_isolate()->heap()->TracePathToObject(*o);
}
#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) {
TEST(SizeOfFirstPageIsLargeEnough) {
if (i::FLAG_always_opt) return;
// Bootstrapping without a snapshot causes more allocations.
if (!i::Snapshot::HaveASnapshotToStartFrom()) return;
CcTest::InitializeVM();
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.
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