Commit 7a8d20a7 authored by yangguo's avatar yangguo Committed by Commit bot

[snapshot] encode resource before serializing.

Before serializing an external string for a native source, we replace
its resource field with the type and index of the native source. Upon
deserialization, we restore the resource.

This change also removes the native source caches with a more straight-
forward mechanism to find the resource type and index.

R=ulan@chromium.org

Review-Url: https://codereview.chromium.org/2807023003
Cr-Commit-Position: refs/heads/master@{#44545}
parent 7aa84189
......@@ -35,33 +35,16 @@ Bootstrapper::Bootstrapper(Isolate* isolate)
nesting_(0),
extensions_cache_(Script::TYPE_EXTENSION) {}
template <class Source>
Handle<String> Bootstrapper::SourceLookup(int index) {
DCHECK(0 <= index && index < Source::GetBuiltinsCount());
Heap* heap = isolate_->heap();
if (Source::GetSourceCache(heap)->get(index)->IsUndefined(isolate_)) {
// We can use external strings for the natives.
Vector<const char> source = Source::GetScriptSource(index);
NativesExternalStringResource* resource =
new NativesExternalStringResource(source.start(), source.length());
Handle<ExternalOneByteString> source_code =
isolate_->factory()->NewNativeSourceString(resource);
// Mark this external string with a special map.
DCHECK(source_code->is_short());
Source::GetSourceCache(heap)->set(index, *source_code);
}
Handle<Object> cached_source(Source::GetSourceCache(heap)->get(index),
isolate_);
return Handle<String>::cast(cached_source);
Handle<String> Bootstrapper::GetNativeSource(NativeType type, int index) {
NativesExternalStringResource* resource =
new NativesExternalStringResource(type, index);
Handle<ExternalOneByteString> source_code =
isolate_->factory()->NewNativeSourceString(resource);
isolate_->heap()->RegisterExternalString(*source_code);
DCHECK(source_code->is_short());
return source_code;
}
template Handle<String> Bootstrapper::SourceLookup<Natives>(int index);
template Handle<String> Bootstrapper::SourceLookup<ExperimentalExtraNatives>(
int index);
template Handle<String> Bootstrapper::SourceLookup<ExtraNatives>(int index);
void Bootstrapper::Initialize(bool create_heap_objects) {
extensions_cache_.Initialize(isolate_, create_heap_objects);
}
......@@ -111,30 +94,7 @@ void Bootstrapper::TearDownExtensions() {
ignition_statistics_extension_ = NULL;
}
void DeleteNativeSources(Object* maybe_array) {
if (maybe_array->IsFixedArray()) {
FixedArray* array = FixedArray::cast(maybe_array);
Isolate* isolate = array->GetIsolate();
for (int i = 0; i < array->length(); i++) {
Object* natives_source = array->get(i);
if (!natives_source->IsUndefined(isolate)) {
const NativesExternalStringResource* resource =
reinterpret_cast<const NativesExternalStringResource*>(
ExternalOneByteString::cast(natives_source)->resource());
delete resource;
}
}
}
}
void Bootstrapper::TearDown() {
DeleteNativeSources(Natives::GetSourceCache(isolate_->heap()));
DeleteNativeSources(ExtraNatives::GetSourceCache(isolate_->heap()));
DeleteNativeSources(
ExperimentalExtraNatives::GetSourceCache(isolate_->heap()));
extensions_cache_.Initialize(isolate_, false); // Yes, symmetrical
}
......@@ -3225,7 +3185,7 @@ void Genesis::InitializeExperimentalGlobal() {
bool Bootstrapper::CompileBuiltin(Isolate* isolate, int index) {
Vector<const char> name = Natives::GetScriptName(index);
Handle<String> source_code =
isolate->bootstrapper()->SourceLookup<Natives>(index);
isolate->bootstrapper()->GetNativeSource(CORE, index);
// We pass in extras_utils so that builtin code can set it up for later use
// by actual extras code, compiled with CompileExtraBuiltin.
......@@ -3243,7 +3203,7 @@ bool Bootstrapper::CompileExtraBuiltin(Isolate* isolate, int index) {
HandleScope scope(isolate);
Vector<const char> name = ExtraNatives::GetScriptName(index);
Handle<String> source_code =
isolate->bootstrapper()->SourceLookup<ExtraNatives>(index);
isolate->bootstrapper()->GetNativeSource(EXTRAS, index);
Handle<Object> global = isolate->global_object();
Handle<Object> binding = isolate->extras_binding_object();
Handle<Object> extras_utils = isolate->extras_utils_object();
......@@ -3258,7 +3218,7 @@ bool Bootstrapper::CompileExperimentalExtraBuiltin(Isolate* isolate,
HandleScope scope(isolate);
Vector<const char> name = ExperimentalExtraNatives::GetScriptName(index);
Handle<String> source_code =
isolate->bootstrapper()->SourceLookup<ExperimentalExtraNatives>(index);
isolate->bootstrapper()->GetNativeSource(EXPERIMENTAL_EXTRAS, index);
Handle<Object> global = isolate->global_object();
Handle<Object> binding = isolate->extras_binding_object();
Handle<Object> extras_utils = isolate->extras_utils_object();
......
......@@ -6,6 +6,7 @@
#define V8_BOOTSTRAPPER_H_
#include "src/factory.h"
#include "src/snapshot/natives.h"
namespace v8 {
namespace internal {
......@@ -96,8 +97,7 @@ class Bootstrapper final {
void Iterate(ObjectVisitor* v);
// Accessor for the native scripts source code.
template <class Source>
Handle<String> SourceLookup(int index);
Handle<String> GetNativeSource(NativeType type, int index);
// Tells whether bootstrapping is active.
bool IsActive() const { return nesting_ != 0; }
......@@ -163,20 +163,6 @@ class BootstrapperActive final BASE_EMBEDDED {
DISALLOW_COPY_AND_ASSIGN(BootstrapperActive);
};
class NativesExternalStringResource final
: public v8::String::ExternalOneByteStringResource {
public:
NativesExternalStringResource(const char* source, size_t length)
: data_(source), length_(length) {}
const char* data() const override { return data_; }
size_t length() const override { return length_; }
private:
const char* data_;
size_t length_;
};
} // namespace internal
} // namespace v8
......
......@@ -2782,16 +2782,6 @@ void Heap::CreateInitialObjects() {
set_regexp_multiple_cache(*factory->NewFixedArray(
RegExpResultsCache::kRegExpResultsCacheSize, TENURED));
// Allocate cache for external strings pointing to native source code.
set_natives_source_cache(
*factory->NewFixedArray(Natives::GetBuiltinsCount()));
set_extra_natives_source_cache(
*factory->NewFixedArray(ExtraNatives::GetBuiltinsCount()));
set_experimental_extra_natives_source_cache(
*factory->NewFixedArray(ExperimentalExtraNatives::GetBuiltinsCount()));
set_undefined_cell(*factory->NewCell(factory->undefined_value()));
// Microtask queue uses the empty fixed array as a sentinel for "empty".
......
......@@ -178,10 +178,6 @@ using v8::MemoryPressureLevel;
V(Object, instanceof_cache_function, InstanceofCacheFunction) \
V(Object, instanceof_cache_map, InstanceofCacheMap) \
V(Object, instanceof_cache_answer, InstanceofCacheAnswer) \
V(FixedArray, natives_source_cache, NativesSourceCache) \
V(FixedArray, extra_natives_source_cache, ExtraNativesSourceCache) \
V(FixedArray, experimental_extra_natives_source_cache, \
ExperimentalExtraNativesSourceCache) \
/* Lists and dictionaries */ \
V(NameDictionary, empty_properties_dictionary, EmptyPropertiesDictionary) \
V(NameDictionary, public_symbol_table, PublicSymbolTable) \
......
......@@ -356,6 +356,14 @@ HeapObject* Deserializer::PostProcessNewObject(HeapObject* obj, int space) {
if (isolate_->external_reference_redirector()) {
accessor_infos_.Add(AccessorInfo::cast(obj));
}
} else if (obj->IsExternalOneByteString()) {
DCHECK(obj->map() == isolate_->heap()->native_source_string_map());
ExternalOneByteString* string = ExternalOneByteString::cast(obj);
DCHECK(string->is_short());
string->set_resource(
NativesExternalStringResource::DecodeForDeserialization(
string->resource()));
isolate_->heap()->RegisterExternalString(string);
}
// Check alignment.
DCHECK_EQ(0, Heap::GetFillToAlign(obj->address(), obj->RequiredAlignment()));
......@@ -502,16 +510,6 @@ Address Deserializer::Allocate(int space_index, int size) {
}
}
Object** Deserializer::CopyInNativesSource(Vector<const char> source_vector,
Object** current) {
DCHECK(!isolate_->heap()->deserialization_complete());
NativesExternalStringResource* resource = new NativesExternalStringResource(
source_vector.start(), source_vector.length());
Object* resource_obj = reinterpret_cast<Object*>(resource);
UnalignedCopy(current++, &resource_obj);
return current;
}
bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
Address current_object_address) {
Isolate* const isolate = isolate_;
......@@ -814,16 +812,6 @@ bool Deserializer::ReadData(Object** current, Object** limit, int source_space,
CHECK(false);
break;
case kNativesStringResource:
current = CopyInNativesSource(Natives::GetScriptSource(source_.Get()),
current);
break;
case kExtraNativesStringResource:
current = CopyInNativesSource(
ExtraNatives::GetScriptSource(source_.Get()), current);
break;
// Deserialize raw data of variable length.
case kVariableRawData: {
int size_in_bytes = source_.GetInt();
......
......@@ -117,9 +117,6 @@ class Deserializer : public SerializerDeserializer {
// snapshot by chunk index and offset.
HeapObject* GetBackReferencedObject(int space);
Object** CopyInNativesSource(Vector<const char> source_vector,
Object** current);
// Cached current isolate.
Isolate* isolate_;
......
......@@ -11,21 +11,29 @@
namespace v8 {
namespace internal {
template <>
FixedArray* NativesCollection<CORE>::GetSourceCache(Heap* heap) {
return heap->natives_source_cache();
}
template <>
FixedArray* NativesCollection<EXTRAS>::GetSourceCache(Heap* heap) {
return heap->extra_natives_source_cache();
}
template <>
FixedArray* NativesCollection<EXPERIMENTAL_EXTRAS>::GetSourceCache(Heap* heap) {
return heap->experimental_extra_natives_source_cache();
NativesExternalStringResource::NativesExternalStringResource(NativeType type,
int index)
: type_(type), index_(index) {
Vector<const char> source;
DCHECK(0 <= index);
switch (type_) {
case CORE:
DCHECK(index < Natives::GetBuiltinsCount());
source = Natives::GetScriptSource(index);
break;
case EXTRAS:
DCHECK(index < ExtraNatives::GetBuiltinsCount());
source = ExtraNatives::GetScriptSource(index);
break;
case EXPERIMENTAL_EXTRAS:
DCHECK(index < ExperimentalExtraNatives::GetBuiltinsCount());
source = ExperimentalExtraNatives::GetScriptSource(index);
break;
default:
UNREACHABLE();
}
data_ = source.start();
length_ = source.length();
}
} // namespace internal
......
......@@ -5,6 +5,7 @@
#ifndef V8_SNAPSHOT_NATIVES_H_
#define V8_SNAPSHOT_NATIVES_H_
#include "include/v8.h"
#include "src/objects.h"
#include "src/vector.h"
......@@ -46,10 +47,6 @@ class V8_EXPORT_PRIVATE NativesCollection {
static Vector<const char> GetScriptSource(int index);
static Vector<const char> GetScriptName(int index);
static Vector<const char> GetScriptsSource();
// The following methods are implemented in natives-common.cc:
static FixedArray* GetSourceCache(Heap* heap);
};
typedef NativesCollection<CORE> Natives;
......@@ -64,6 +61,37 @@ void ReadNatives();
void DisposeNatives();
#endif
class NativesExternalStringResource final
: public v8::String::ExternalOneByteStringResource {
public:
NativesExternalStringResource(NativeType type, int index);
const char* data() const override { return data_; }
size_t length() const override { return length_; }
v8::String::ExternalOneByteStringResource* EncodeForSerialization() const {
DCHECK(type_ == CORE || type_ == EXTRAS);
intptr_t val = (index_ << 1) | ((type_ == CORE) ? 0 : 1);
val = val << kPointerSizeLog2; // Pointer align.
return reinterpret_cast<v8::String::ExternalOneByteStringResource*>(val);
}
// Decode from serialization.
static NativesExternalStringResource* DecodeForDeserialization(
const v8::String::ExternalOneByteStringResource* encoded) {
intptr_t val = reinterpret_cast<intptr_t>(encoded) >> kPointerSizeLog2;
NativeType type = (val & 1) ? EXTRAS : CORE;
int index = static_cast<int>(val >> 1);
return new NativesExternalStringResource(type, index);
}
private:
const char* data_;
size_t length_;
NativeType type_;
int index_;
};
} // namespace internal
} // namespace v8
......
......@@ -166,12 +166,9 @@ class SerializerDeserializer : public ObjectVisitor {
// Internal reference encoded as offsets of pc and target from code entry.
static const int kInternalReference = 0x1b;
static const int kInternalReferenceEncoded = 0x1c;
// Used for the source code of the natives, which is in the executable, but
// is referred to from external strings in the snapshot.
static const int kNativesStringResource = 0x1d;
// Used for the source code for compiled stubs, which is in the executable,
// but is referred to from external strings in the snapshot.
static const int kExtraNativesStringResource = 0x1e;
// Used to encode deoptimizer entry code.
static const int kDeoptimizerEntryPlain = 0x1d;
static const int kDeoptimizerEntryFromCode = 0x1e;
// Used for embedder-provided serialization data for embedder fields.
static const int kEmbedderFieldsData = 0x1f;
......@@ -184,10 +181,7 @@ class SerializerDeserializer : public ObjectVisitor {
static const int kHotObjectWithSkip = 0x58;
static const int kHotObjectMask = 0x07;
static const int kDeoptimizerEntryPlain = 0x35;
static const int kDeoptimizerEntryFromCode = 0x36;
// 0x37, 0x55..0x57, 0x75..0x7f unused.
// 0x35..0x37, 0x55..0x57, 0x75..0x7f unused.
// ---------- byte code range 0x80..0xff ----------
// First 32 root array items.
......
......@@ -410,57 +410,17 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
// their resources.
SerializeExternalStringAsSequentialString();
} else {
DCHECK(object_->IsExternalOneByteString());
DCHECK(ExternalOneByteString::cast(object_)->is_short());
int size = object_->Size();
Map* map = object_->map();
AllocationSpace space =
MemoryChunk::FromAddress(object_->address())->owner()->identity();
SerializePrologue(space, size, map);
// Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
typedef v8::String::ExternalOneByteStringResource Resource;
Resource** resource_pointer = reinterpret_cast<Resource**>(
HeapObject::RawField(object_, ExternalString::kResourceOffset));
Address references_start = reinterpret_cast<Address>(resource_pointer);
OutputRawData(references_start);
if (!SerializeExternalNativeSourceString(
Natives::GetBuiltinsCount(), resource_pointer,
Natives::GetSourceCache(heap), kNativesStringResource)) {
bool result = SerializeExternalNativeSourceString(
ExtraNatives::GetBuiltinsCount(), resource_pointer,
ExtraNatives::GetSourceCache(heap), kExtraNativesStringResource);
// One of the strings in the natives cache should match the resource. We
// don't expect any other kinds of external strings here.
USE(result);
DCHECK(result);
}
OutputRawData(object_->address() + size);
}
}
bool Serializer::ObjectSerializer::SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index) {
Isolate* isolate = serializer_->isolate();
for (int i = 0; i < builtin_count; i++) {
Object* source = source_cache->get(i);
if (!source->IsUndefined(isolate)) {
ExternalOneByteString* string = ExternalOneByteString::cast(source);
typedef v8::String::ExternalOneByteStringResource Resource;
const Resource* resource = string->resource();
if (resource == *resource_pointer) {
sink_->Put(resource_index, "NativesStringResource");
sink_->PutSection(i, "NativesStringResourceEnd");
bytes_processed_so_far_ += sizeof(resource);
return true;
}
}
ExternalOneByteString* string = ExternalOneByteString::cast(object_);
DCHECK(string->is_short());
const NativesExternalStringResource* resource =
reinterpret_cast<const NativesExternalStringResource*>(
string->resource());
// Replace the resource field with the type and index of the native source.
string->set_resource(resource->EncodeForSerialization());
SerializeContent();
// Restore the resource field.
string->set_resource(resource);
}
return false;
}
void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
......@@ -566,43 +526,48 @@ void Serializer::ObjectSerializer::Serialize() {
if (object_->IsExternalString()) {
SerializeExternalString();
} else {
// We cannot serialize typed array objects correctly.
DCHECK(!object_->IsJSTypedArray());
return;
}
// We don't expect fillers.
DCHECK(!object_->IsFiller());
// We cannot serialize typed array objects correctly.
DCHECK(!object_->IsJSTypedArray());
if (object_->IsScript()) {
// Clear cached line ends.
Object* undefined = serializer_->isolate()->heap()->undefined_value();
Script::cast(object_)->set_line_ends(undefined);
}
// We don't expect fillers.
DCHECK(!object_->IsFiller());
int size = object_->Size();
Map* map = object_->map();
AllocationSpace space =
MemoryChunk::FromAddress(object_->address())->owner()->identity();
SerializePrologue(space, size, map);
// Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
RecursionScope recursion(serializer_);
// Objects that are immediately post processed during deserialization
// cannot be deferred, since post processing requires the object content.
if (recursion.ExceedsMaximum() && CanBeDeferred(object_)) {
serializer_->QueueDeferredObject(object_);
sink_->Put(kDeferred, "Deferring object content");
return;
}
if (object_->IsScript()) {
// Clear cached line ends.
Object* undefined = serializer_->isolate()->heap()->undefined_value();
Script::cast(object_)->set_line_ends(undefined);
}
UnlinkWeakNextScope unlink_weak_next(object_);
SerializeContent();
}
object_->IterateBody(map->instance_type(), size, this);
OutputRawData(object_->address() + size);
void Serializer::ObjectSerializer::SerializeContent() {
int size = object_->Size();
Map* map = object_->map();
AllocationSpace space =
MemoryChunk::FromAddress(object_->address())->owner()->identity();
SerializePrologue(space, size, map);
// Serialize the rest of the object.
CHECK_EQ(0, bytes_processed_so_far_);
bytes_processed_so_far_ = kPointerSize;
RecursionScope recursion(serializer_);
// Objects that are immediately post processed during deserialization
// cannot be deferred, since post processing requires the object content.
if (recursion.ExceedsMaximum() && CanBeDeferred(object_)) {
serializer_->QueueDeferredObject(object_);
sink_->Put(kDeferred, "Deferring object content");
return;
}
UnlinkWeakNextScope unlink_weak_next(object_);
object_->IterateBody(map->instance_type(), size, this);
OutputRawData(object_->address() + size);
}
void Serializer::ObjectSerializer::SerializeDeferred() {
......
......@@ -280,6 +280,7 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
code_has_been_output_(false) {}
~ObjectSerializer() override {}
void Serialize();
void SerializeContent();
void SerializeDeferred();
void VisitPointers(Object** start, Object** end) override;
void VisitEmbeddedPointer(RelocInfo* target) override;
......@@ -305,10 +306,6 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
int OutputRawData(Address up_to, ReturnSkip return_skip = kIgnoringReturn);
void SerializeExternalString();
void SerializeExternalStringAsSequentialString();
bool SerializeExternalNativeSourceString(
int builtin_count,
v8::String::ExternalOneByteStringResource** resource_pointer,
FixedArray* source_cache, int resource_index);
Address PrepareCode();
......
......@@ -271,13 +271,6 @@ static void PartiallySerializeObject(Vector<const byte>* startup_blob_out,
v8::HandleScope handle_scope(v8_isolate);
v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
}
// Make sure all builtin scripts are cached.
{
HandleScope scope(isolate);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
isolate->bootstrapper()->SourceLookup<Natives>(i);
}
}
heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
heap->CollectAllAvailableGarbage(i::GarbageCollectionReason::kTesting);
......@@ -378,13 +371,6 @@ static void PartiallySerializeContext(Vector<const byte>* startup_blob_out,
v8::HandleScope handle_scope(v8_isolate);
v8::Local<v8::Context>::New(v8_isolate, env)->Enter();
}
// Make sure all builtin scripts are cached.
{
HandleScope scope(isolate);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
isolate->bootstrapper()->SourceLookup<Natives>(i);
}
}
// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of env.
......@@ -503,13 +489,6 @@ static void PartiallySerializeCustomContext(
CompileRun(source_str.ToLocalChecked());
source.Dispose();
}
// Make sure all builtin scripts are cached.
{
HandleScope scope(isolate);
for (int i = 0; i < Natives::GetBuiltinsCount(); i++) {
isolate->bootstrapper()->SourceLookup<Natives>(i);
}
}
// If we don't do this then we end up with a stray root pointing at the
// context even after we have disposed of env.
isolate->heap()->CollectAllAvailableGarbage(
......
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