Commit 7ddacd68 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[web snapshot] Dehandlify more parts of the deserializer

- Use Heap::AddGCEpilogueCallback to update often accessed FixedArrays
  in the WebSnapshotDeserializer.
- ReadValue returns now a raw value to avoid handle creation in more
  cases
- Drop representation support for now in ReadValue
- Avoid a few more handles when setting up objects

Bug v8:11525

Change-Id: I6955b56887834bc655bdaa9c390016d9a17db82d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3416242Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78862}
parent 2879f3f1
...@@ -1045,7 +1045,32 @@ WebSnapshotDeserializer::WebSnapshotDeserializer( ...@@ -1045,7 +1045,32 @@ WebSnapshotDeserializer::WebSnapshotDeserializer(
base::Vector<const uint8_t> buffer) base::Vector<const uint8_t> buffer)
: WebSnapshotSerializerDeserializer(isolate), : WebSnapshotSerializerDeserializer(isolate),
script_name_(script_name), script_name_(script_name),
deserializer_(isolate_, buffer.data(), buffer.length()) {} deserializer_(isolate_, buffer.data(), buffer.length()) {
isolate_->heap()->AddGCEpilogueCallback(UpdatePointersCallback,
v8::kGCTypeAll, this);
Handle<FixedArray> empty_array = isolate_->factory()->empty_fixed_array();
strings_handle_ = empty_array;
maps_handle_ = empty_array;
contexts_handle_ = empty_array;
functions_handle_ = empty_array;
classes_handle_ = empty_array;
arrays_handle_ = empty_array;
objects_handle_ = empty_array;
}
WebSnapshotDeserializer::~WebSnapshotDeserializer() {
isolate_->heap()->RemoveGCEpilogueCallback(UpdatePointersCallback, this);
}
void WebSnapshotDeserializer::UpdatePointers() {
strings_ = *strings_handle_;
maps_ = *maps_handle_;
contexts_ = *contexts_handle_;
functions_ = *functions_handle_;
classes_ = *classes_handle_;
arrays_ = *arrays_handle_;
objects_ = *objects_handle_;
}
// static // static
base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer( base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer(
...@@ -1099,7 +1124,6 @@ base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer( ...@@ -1099,7 +1124,6 @@ base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer(
} }
UNREACHABLE(); UNREACHABLE();
} }
WebSnapshotDeserializer::~WebSnapshotDeserializer() {}
void WebSnapshotDeserializer::Throw(const char* message) { void WebSnapshotDeserializer::Throw(const char* message) {
string_count_ = 0; string_count_ = 0;
...@@ -1212,7 +1236,8 @@ void WebSnapshotDeserializer::DeserializeStrings() { ...@@ -1212,7 +1236,8 @@ void WebSnapshotDeserializer::DeserializeStrings() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength);
strings_ = isolate_->factory()->NewFixedArray(string_count_); strings_handle_ = isolate_->factory()->NewFixedArray(string_count_);
strings_ = *strings_handle_;
for (uint32_t i = 0; i < string_count_; ++i) { for (uint32_t i = 0; i < string_count_; ++i) {
MaybeHandle<String> maybe_string = deserializer_.ReadUtf8String(); MaybeHandle<String> maybe_string = deserializer_.ReadUtf8String();
Handle<String> string; Handle<String> string;
...@@ -1220,22 +1245,21 @@ void WebSnapshotDeserializer::DeserializeStrings() { ...@@ -1220,22 +1245,21 @@ void WebSnapshotDeserializer::DeserializeStrings() {
Throw("Malformed string"); Throw("Malformed string");
return; return;
} }
strings_->set(i, *string); strings_.set(i, *string);
} }
} }
Handle<String> WebSnapshotDeserializer::ReadString(bool internalize) { String WebSnapshotDeserializer::ReadString(bool internalize) {
DCHECK(!strings_->is_null()); DCHECK(!strings_handle_->is_null());
uint32_t string_id; uint32_t string_id;
if (!deserializer_.ReadUint32(&string_id) || string_id >= string_count_) { if (!deserializer_.ReadUint32(&string_id) || string_id >= string_count_) {
Throw("malformed string id\n"); Throw("malformed string id\n");
return isolate_->factory()->empty_string(); return ReadOnlyRoots(isolate_).empty_string();
} }
Handle<String> string = String string = String::cast(strings_.get(string_id));
handle(String::cast(strings_->get(string_id)), isolate_); if (internalize && !string.IsInternalizedString()) {
if (internalize && !string->IsInternalizedString()) { string = *isolate_->factory()->InternalizeString(handle(string, isolate_));
string = isolate_->factory()->InternalizeString(string); strings_.set(string_id, string);
strings_->set(string_id, *string);
} }
return string; return string;
} }
...@@ -1247,7 +1271,8 @@ void WebSnapshotDeserializer::DeserializeMaps() { ...@@ -1247,7 +1271,8 @@ void WebSnapshotDeserializer::DeserializeMaps() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength);
maps_ = isolate_->factory()->NewFixedArray(map_count_); maps_handle_ = isolate_->factory()->NewFixedArray(map_count_);
maps_ = *maps_handle_;
for (uint32_t i = 0; i < map_count_; ++i) { for (uint32_t i = 0; i < map_count_; ++i) {
uint32_t map_type; uint32_t map_type;
if (!deserializer_.ReadUint32(&map_type)) { if (!deserializer_.ReadUint32(&map_type)) {
...@@ -1290,7 +1315,7 @@ void WebSnapshotDeserializer::DeserializeMaps() { ...@@ -1290,7 +1315,7 @@ void WebSnapshotDeserializer::DeserializeMaps() {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
Map empty_map = Map empty_map =
isolate_->native_context()->object_function().initial_map(); isolate_->native_context()->object_function().initial_map();
maps_->set(i, empty_map); maps_.set(i, empty_map);
return; return;
} }
...@@ -1308,7 +1333,7 @@ void WebSnapshotDeserializer::DeserializeMaps() { ...@@ -1308,7 +1333,7 @@ void WebSnapshotDeserializer::DeserializeMaps() {
attributes = FlagsToAttributes(flags); attributes = FlagsToAttributes(flags);
} }
Handle<String> key = ReadString(true); Handle<String> key(ReadString(true), isolate_);
// Use the "none" representation until we see the first object having this // Use the "none" representation until we see the first object having this
// map. At that point, modify the representation. // map. At that point, modify the representation.
...@@ -1332,14 +1357,14 @@ void WebSnapshotDeserializer::DeserializeMaps() { ...@@ -1332,14 +1357,14 @@ void WebSnapshotDeserializer::DeserializeMaps() {
// TODO(v8::11525): Implement stricter checks, e.g., disallow cycles. // TODO(v8::11525): Implement stricter checks, e.g., disallow cycles.
--prototype_id; --prototype_id;
if (prototype_id < current_object_count_) { if (prototype_id < current_object_count_) {
map->set_prototype(HeapObject::cast(objects_->get(prototype_id)), map->set_prototype(HeapObject::cast(objects_.get(prototype_id)),
UPDATE_WRITE_BARRIER); UPDATE_WRITE_BARRIER);
} else { } else {
// The object hasn't been deserialized yet. // The object hasn't been deserialized yet.
AddDeferredReference(map, 0, OBJECT_ID, prototype_id); AddDeferredReference(map, 0, OBJECT_ID, prototype_id);
} }
} }
maps_->set(i, *map); maps_.set(i, *map);
} }
} }
...@@ -1351,7 +1376,8 @@ void WebSnapshotDeserializer::DeserializeContexts() { ...@@ -1351,7 +1376,8 @@ void WebSnapshotDeserializer::DeserializeContexts() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength);
contexts_ = isolate_->factory()->NewFixedArray(context_count_); contexts_handle_ = isolate_->factory()->NewFixedArray(context_count_);
contexts_ = *contexts_handle_;
for (uint32_t i = 0; i < context_count_; ++i) { for (uint32_t i = 0; i < context_count_; ++i) {
uint32_t context_type; uint32_t context_type;
if (!deserializer_.ReadUint32(&context_type)) { if (!deserializer_.ReadUint32(&context_type)) {
...@@ -1380,8 +1406,8 @@ void WebSnapshotDeserializer::DeserializeContexts() { ...@@ -1380,8 +1406,8 @@ void WebSnapshotDeserializer::DeserializeContexts() {
Handle<Context> parent_context; Handle<Context> parent_context;
if (parent_context_id > 0) { if (parent_context_id > 0) {
parent_context = handle( parent_context =
Context::cast(contexts_->get(parent_context_id - 1)), isolate_); handle(Context::cast(contexts_.get(parent_context_id - 1)), isolate_);
scope_info->set_outer_scope_info(parent_context->scope_info()); scope_info->set_outer_scope_info(parent_context->scope_info());
} else { } else {
parent_context = handle(isolate_->context(), isolate_); parent_context = handle(isolate_->context(), isolate_);
...@@ -1391,8 +1417,10 @@ void WebSnapshotDeserializer::DeserializeContexts() { ...@@ -1391,8 +1417,10 @@ void WebSnapshotDeserializer::DeserializeContexts() {
const int context_local_info_base = context_local_base + variable_count; const int context_local_info_base = context_local_base + variable_count;
for (int variable_index = 0; for (int variable_index = 0;
variable_index < static_cast<int>(variable_count); ++variable_index) { variable_index < static_cast<int>(variable_count); ++variable_index) {
Handle<String> name = ReadString(true); {
scope_info->set(context_local_base + variable_index, *name); String name = ReadString(true);
scope_info->set(context_local_base + variable_index, name);
}
// TODO(v8:11525): Support variable modes etc. // TODO(v8:11525): Support variable modes etc.
uint32_t info = uint32_t info =
...@@ -1424,15 +1452,14 @@ void WebSnapshotDeserializer::DeserializeContexts() { ...@@ -1424,15 +1452,14 @@ void WebSnapshotDeserializer::DeserializeContexts() {
Throw("Unsupported context type"); Throw("Unsupported context type");
return; return;
} }
int context_header_length = scope_info->ContextHeaderLength();
for (int variable_index = 0; for (int variable_index = 0;
variable_index < static_cast<int>(variable_count); ++variable_index) { variable_index < static_cast<int>(variable_count); ++variable_index) {
Handle<Object> value; int context_index = context_header_length + variable_index;
Representation representation; Object value = ReadValue(context, context_index);
ReadValue(value, representation, context, context->set(context_index, value);
scope_info->ContextHeaderLength() + variable_index);
context->set(scope_info->ContextHeaderLength() + variable_index, *value);
} }
contexts_->set(i, *context); contexts_.set(i, *context);
} }
} }
...@@ -1488,15 +1515,19 @@ Handle<ScopeInfo> WebSnapshotDeserializer::CreateScopeInfo( ...@@ -1488,15 +1515,19 @@ Handle<ScopeInfo> WebSnapshotDeserializer::CreateScopeInfo(
: 0) + : 0) +
(has_parent ? 1 : 0) + 2 * variable_count; (has_parent ? 1 : 0) + 2 * variable_count;
Handle<ScopeInfo> scope_info = isolate_->factory()->NewScopeInfo(length); Handle<ScopeInfo> scope_info = isolate_->factory()->NewScopeInfo(length);
{
DisallowGarbageCollection no_gc;
ScopeInfo raw = *scope_info;
scope_info->set_flags(flags); raw.set_flags(flags);
DCHECK(!scope_info->IsEmpty()); DCHECK(!raw.IsEmpty());
scope_info->set_context_local_count(variable_count); raw.set_context_local_count(variable_count);
// TODO(v8:11525): Support parameters. // TODO(v8:11525): Support parameters.
scope_info->set_parameter_count(0); raw.set_parameter_count(0);
if (scope_info->HasPositionInfo()) { if (raw.HasPositionInfo()) {
scope_info->SetPositionInfo(0, 0); raw.SetPositionInfo(0, 0);
}
} }
return scope_info; return scope_info;
} }
...@@ -1527,7 +1558,7 @@ Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction( ...@@ -1527,7 +1558,7 @@ Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction(
raw.set_language_mode(LanguageMode::kStrict); raw.set_language_mode(LanguageMode::kStrict);
raw.set_uncompiled_data(*uncompiled_data); raw.set_uncompiled_data(*uncompiled_data);
raw.set_allows_lazy_compilation(true); raw.set_allows_lazy_compilation(true);
shared_function_infos_->Set(shared_function_info_index, shared_function_infos_.Set(shared_function_info_index,
HeapObjectReference::Weak(raw)); HeapObjectReference::Weak(raw));
} }
shared_function_info_table_ = ObjectHashTable::Put( shared_function_info_table_ = ObjectHashTable::Put(
...@@ -1541,8 +1572,8 @@ Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction( ...@@ -1541,8 +1572,8 @@ Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction(
if (context_id > 0) { if (context_id > 0) {
DCHECK_LT(context_id - 1, context_count_); DCHECK_LT(context_id - 1, context_count_);
// Guards raw pointer "context" below. // Guards raw pointer "context" below.
DisallowGarbageCollection no_gc; DisallowHeapAllocation no_heap_access;
Context context = Context::cast(contexts_->get(context_id - 1)); Context context = Context::cast(contexts_.get(context_id - 1));
function->set_context(context); function->set_context(context);
shared->set_outer_scope_info(context.scope_info()); shared->set_outer_scope_info(context.scope_info());
} }
...@@ -1557,19 +1588,22 @@ void WebSnapshotDeserializer::DeserializeFunctions() { ...@@ -1557,19 +1588,22 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength);
functions_ = isolate_->factory()->NewFixedArray(function_count_); functions_handle_ = isolate_->factory()->NewFixedArray(function_count_);
functions_ = *functions_handle_;
// Overallocate the array for SharedFunctionInfos; functions which we // Overallocate the array for SharedFunctionInfos; functions which we
// deserialize soon will create more SharedFunctionInfos when called. // deserialize soon will create more SharedFunctionInfos when called.
shared_function_infos_ = isolate_->factory()->NewWeakFixedArray( shared_function_infos_handle_ = isolate_->factory()->NewWeakFixedArray(
WeakArrayList::CapacityForLength(function_count_ + 1)); WeakArrayList::CapacityForLength(function_count_ + 1),
AllocationType::kOld);
shared_function_infos_ = *shared_function_infos_handle_;
shared_function_info_table_ = ObjectHashTable::New(isolate_, function_count_); shared_function_info_table_ = ObjectHashTable::New(isolate_, function_count_);
script_ = isolate_->factory()->NewScript(isolate_->factory()->empty_string()); script_ = isolate_->factory()->NewScript(isolate_->factory()->empty_string());
{ {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
Script raw = *script_; Script raw = *script_;
raw.set_type(Script::TYPE_WEB_SNAPSHOT); raw.set_type(Script::TYPE_WEB_SNAPSHOT);
raw.set_shared_function_infos(*shared_function_infos_); raw.set_shared_function_infos(shared_function_infos_);
raw.set_shared_function_info_table(*shared_function_info_table_); raw.set_shared_function_info_table(*shared_function_info_table_);
} }
...@@ -1580,13 +1614,15 @@ void WebSnapshotDeserializer::DeserializeFunctions() { ...@@ -1580,13 +1614,15 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
Throw("Malformed function"); Throw("Malformed function");
return; return;
} }
{
Handle<String> source = ReadString(false); String source = ReadString(false);
DisallowGarbageCollection no_gc;
if (current_function_count_ == 0) { if (current_function_count_ == 0) {
script_->set_source(*source); script_->set_source(source);
} else { } else {
// TODO(v8:11525): Support multiple source snippets. // TODO(v8:11525): Support multiple source snippets.
DCHECK_EQ(script_->source(), *source); DCHECK_EQ(script_->source(), source);
}
} }
uint32_t start_position; uint32_t start_position;
...@@ -1606,7 +1642,7 @@ void WebSnapshotDeserializer::DeserializeFunctions() { ...@@ -1606,7 +1642,7 @@ void WebSnapshotDeserializer::DeserializeFunctions() {
Handle<JSFunction> function = Handle<JSFunction> function =
CreateJSFunction(current_function_count_ + 1, start_position, length, CreateJSFunction(current_function_count_ + 1, start_position, length,
parameter_count, flags, context_id); parameter_count, flags, context_id);
functions_->set(current_function_count_, *function); functions_.set(current_function_count_, *function);
ReadFunctionPrototype(function); ReadFunctionPrototype(function);
} }
...@@ -1620,13 +1656,15 @@ void WebSnapshotDeserializer::DeserializeClasses() { ...@@ -1620,13 +1656,15 @@ void WebSnapshotDeserializer::DeserializeClasses() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength);
classes_ = isolate_->factory()->NewFixedArray(class_count_); classes_handle_ = isolate_->factory()->NewFixedArray(class_count_);
classes_ = *classes_handle_;
// Grow the array for SharedFunctionInfos. // Grow the array for SharedFunctionInfos.
shared_function_infos_ = WeakFixedArray::EnsureSpace( shared_function_infos_handle_ = WeakFixedArray::EnsureSpace(
isolate_, shared_function_infos_, isolate_, shared_function_infos_handle_,
WeakArrayList::CapacityForLength(function_count_ + 1 + class_count_)); WeakArrayList::CapacityForLength(function_count_ + 1 + class_count_));
script_->set_shared_function_infos(*shared_function_infos_); shared_function_infos_ = *shared_function_infos_handle_;
script_->set_shared_function_infos(shared_function_infos_);
for (; current_class_count_ < class_count_; ++current_class_count_) { for (; current_class_count_ < class_count_; ++current_class_count_) {
uint32_t context_id; uint32_t context_id;
...@@ -1636,12 +1674,14 @@ void WebSnapshotDeserializer::DeserializeClasses() { ...@@ -1636,12 +1674,14 @@ void WebSnapshotDeserializer::DeserializeClasses() {
return; return;
} }
Handle<String> source = ReadString(false); {
String source = ReadString(false);
if (current_function_count_ + current_class_count_ == 0) { if (current_function_count_ + current_class_count_ == 0) {
script_->set_source(*source); script_->set_source(source);
} else { } else {
// TODO(v8:11525): Support multiple source snippets. // TODO(v8:11525): Support multiple source snippets.
DCHECK_EQ(script_->source(), *source); DCHECK_EQ(script_->source(), source);
}
} }
uint32_t start_position; uint32_t start_position;
...@@ -1661,7 +1701,7 @@ void WebSnapshotDeserializer::DeserializeClasses() { ...@@ -1661,7 +1701,7 @@ void WebSnapshotDeserializer::DeserializeClasses() {
Handle<JSFunction> function = CreateJSFunction( Handle<JSFunction> function = CreateJSFunction(
function_count_ + current_class_count_ + 1, start_position, length, function_count_ + current_class_count_ + 1, start_position, length,
parameter_count, flags, context_id); parameter_count, flags, context_id);
classes_->set(current_class_count_, *function); classes_.set(current_class_count_, *function);
ReadFunctionPrototype(function); ReadFunctionPrototype(function);
} }
...@@ -1675,42 +1715,44 @@ void WebSnapshotDeserializer::DeserializeObjects() { ...@@ -1675,42 +1715,44 @@ void WebSnapshotDeserializer::DeserializeObjects() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength);
objects_ = isolate_->factory()->NewFixedArray(object_count_); objects_handle_ = isolate_->factory()->NewFixedArray(object_count_);
objects_ = *objects_handle_;
for (; current_object_count_ < object_count_; ++current_object_count_) { for (; current_object_count_ < object_count_; ++current_object_count_) {
uint32_t map_id; uint32_t map_id;
if (!deserializer_.ReadUint32(&map_id) || map_id >= map_count_) { if (!deserializer_.ReadUint32(&map_id) || map_id >= map_count_) {
Throw("Malformed object"); Throw("Malformed object");
return; return;
} }
Handle<Map> map = handle(Map::cast(maps_->get(map_id)), isolate_); Map map = Map::cast(maps_.get(map_id));
Handle<DescriptorArray> descriptors = Handle<DescriptorArray> descriptors =
handle(map->instance_descriptors(kRelaxedLoad), isolate_); handle(map.instance_descriptors(kRelaxedLoad), isolate_);
int no_properties = map->NumberOfOwnDescriptors(); int no_properties = map.NumberOfOwnDescriptors();
// TODO(v8:11525): In-object properties. // TODO(v8:11525): In-object properties.
Handle<JSObject> object =
isolate_->factory()->NewJSObjectFromMap(handle(map, isolate_));
Handle<PropertyArray> property_array = Handle<PropertyArray> property_array =
isolate_->factory()->NewPropertyArray(no_properties); isolate_->factory()->NewPropertyArray(no_properties);
for (int i = 0; i < no_properties; ++i) { for (int i = 0; i < no_properties; ++i) {
Handle<Object> value; Object value = ReadValue(property_array, i);
Representation wanted_representation = Representation::None(); DisallowGarbageCollection no_gc;
ReadValue(value, wanted_representation, property_array, i);
// Read the representation from the map. // Read the representation from the map.
PropertyDetails details = descriptors->GetDetails(InternalIndex(i)); DescriptorArray raw_descriptors = *descriptors;
PropertyDetails details = raw_descriptors.GetDetails(InternalIndex(i));
CHECK_EQ(details.location(), PropertyLocation::kField); CHECK_EQ(details.location(), PropertyLocation::kField);
CHECK_EQ(PropertyKind::kData, details.kind()); CHECK_EQ(PropertyKind::kData, details.kind());
Representation r = details.representation(); Representation r = details.representation();
if (r.IsNone()) { if (r.IsNone()) {
// Switch over to wanted_representation. // Switch over to wanted_representation.
details = details.CopyWithRepresentation(wanted_representation); details = details.CopyWithRepresentation(Representation::Tagged());
descriptors->SetDetails(InternalIndex(i), details); raw_descriptors.SetDetails(InternalIndex(i), details);
} else if (!r.Equals(wanted_representation)) { } else if (!r.Equals(Representation::Tagged())) {
// TODO(v8:11525): Support this case too. // TODO(v8:11525): Support this case too.
UNREACHABLE(); UNREACHABLE();
} }
property_array->set(i, *value); property_array->set(i, value);
} }
Handle<JSObject> object = isolate_->factory()->NewJSObjectFromMap(map);
object->set_raw_properties_or_hash(*property_array, kRelaxedStore); object->set_raw_properties_or_hash(*property_array, kRelaxedStore);
objects_->set(static_cast<int>(current_object_count_), *object); objects_.set(static_cast<int>(current_object_count_), *object);
} }
} }
...@@ -1722,7 +1764,8 @@ void WebSnapshotDeserializer::DeserializeArrays() { ...@@ -1722,7 +1764,8 @@ void WebSnapshotDeserializer::DeserializeArrays() {
return; return;
} }
STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength); STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength);
arrays_ = isolate_->factory()->NewFixedArray(array_count_); arrays_handle_ = isolate_->factory()->NewFixedArray(array_count_);
arrays_ = *arrays_handle_;
for (; current_array_count_ < array_count_; ++current_array_count_) { for (; current_array_count_ < array_count_; ++current_array_count_) {
uint32_t length; uint32_t length;
if (!deserializer_.ReadUint32(&length) || length > kMaxItemCount) { if (!deserializer_.ReadUint32(&length) || length > kMaxItemCount) {
...@@ -1732,18 +1775,16 @@ void WebSnapshotDeserializer::DeserializeArrays() { ...@@ -1732,18 +1775,16 @@ void WebSnapshotDeserializer::DeserializeArrays() {
Handle<FixedArray> elements = isolate_->factory()->NewFixedArray(length); Handle<FixedArray> elements = isolate_->factory()->NewFixedArray(length);
ElementsKind elements_kind = PACKED_SMI_ELEMENTS; ElementsKind elements_kind = PACKED_SMI_ELEMENTS;
for (uint32_t i = 0; i < length; ++i) { for (uint32_t i = 0; i < length; ++i) {
Handle<Object> value; Object value = ReadValue(elements, i);
Representation wanted_representation = Representation::None(); DisallowGarbageCollection no_gc;
ReadValue(value, wanted_representation, elements, i); if (!value.IsSmi()) {
if (!wanted_representation.IsSmi()) {
elements_kind = PACKED_ELEMENTS; elements_kind = PACKED_ELEMENTS;
} }
DCHECK(!value.is_null()); elements->set(static_cast<int>(i), value);
elements->set(static_cast<int>(i), *value);
} }
Handle<JSArray> array = isolate_->factory()->NewJSArrayWithElements( Handle<JSArray> array = isolate_->factory()->NewJSArrayWithElements(
elements, elements_kind, length); elements, elements_kind, length);
arrays_->set(static_cast<int>(current_array_count_), *array); arrays_.set(static_cast<int>(current_array_count_), *array);
} }
} }
...@@ -1769,27 +1810,24 @@ void WebSnapshotDeserializer::DeserializeExports() { ...@@ -1769,27 +1810,24 @@ void WebSnapshotDeserializer::DeserializeExports() {
// LookupIterator::ExtendingNonExtensible. // LookupIterator::ExtendingNonExtensible.
InternalIndex entry = InternalIndex::NotFound(); InternalIndex entry = InternalIndex::NotFound();
for (uint32_t i = 0; i < count; ++i) { for (uint32_t i = 0; i < count; ++i) {
Handle<String> export_name = ReadString(true); Handle<String> export_name(ReadString(true), isolate_);
Handle<Object> export_value;
Representation representation;
// No deferred references should occur at this point, since all objects have // No deferred references should occur at this point, since all objects have
// been deserialized. // been deserialized.
ReadValue(export_value, representation); Object export_value = ReadValue();
DisallowGarbageCollection no_gc;
// Check for the correctness of the snapshot (thus far) before producing // Check for the correctness of the snapshot (thus far) before producing
// something observable. TODO(v8:11525): Strictly speaking, we should // something observable. TODO(v8:11525): Strictly speaking, we should
// produce observable effects only when we know that the whole snapshot is // produce observable effects only when we know that the whole snapshot is
// correct. // correct.
if (has_error()) { if (has_error()) return;
return;
}
PropertyDetails property_details = PropertyDetails property_details =
PropertyDetails(PropertyKind::kData, NONE, PropertyDetails(PropertyKind::kData, NONE,
PropertyCell::InitialType(isolate_, *export_value)); PropertyCell::InitialType(isolate_, export_value));
Handle<Object> export_value_handle(export_value, isolate_);
AllowGarbageCollection allow_gc;
Handle<PropertyCell> transition_cell = isolate_->factory()->NewPropertyCell( Handle<PropertyCell> transition_cell = isolate_->factory()->NewPropertyCell(
export_name, property_details, export_value); export_name, property_details, export_value_handle);
dictionary = dictionary =
GlobalDictionary::Add(isolate_, dictionary, export_name, GlobalDictionary::Add(isolate_, dictionary, export_name,
transition_cell, property_details, &entry); transition_cell, property_details, &entry);
...@@ -1799,8 +1837,7 @@ void WebSnapshotDeserializer::DeserializeExports() { ...@@ -1799,8 +1837,7 @@ void WebSnapshotDeserializer::DeserializeExports() {
JSObject::InvalidatePrototypeChains(global->map(isolate_)); JSObject::InvalidatePrototypeChains(global->map(isolate_));
} }
void WebSnapshotDeserializer::ReadValue( Object WebSnapshotDeserializer::ReadValue(
Handle<Object>& value, Representation& representation,
Handle<HeapObject> object_for_deferred_reference, Handle<HeapObject> object_for_deferred_reference,
uint32_t index_for_deferred_reference) { uint32_t index_for_deferred_reference) {
uint32_t value_type; uint32_t value_type;
...@@ -1810,163 +1847,117 @@ void WebSnapshotDeserializer::ReadValue( ...@@ -1810,163 +1847,117 @@ void WebSnapshotDeserializer::ReadValue(
Throw("Malformed variable"); Throw("Malformed variable");
// Set "value" here so that the "keep on trucking" error handling won't fail // Set "value" here so that the "keep on trucking" error handling won't fail
// when dereferencing the handle. // when dereferencing the handle.
value = factory->undefined_value(); return Smi::zero();
representation = Representation::None();
return;
} }
switch (value_type) { switch (value_type) {
case ValueType::FALSE_CONSTANT: { case ValueType::FALSE_CONSTANT: {
value = factory->false_value(); return ReadOnlyRoots(isolate_).false_value();
representation = Representation::Tagged();
break;
} }
case ValueType::TRUE_CONSTANT: { case ValueType::TRUE_CONSTANT: {
value = factory->true_value(); return ReadOnlyRoots(isolate_).true_value();
representation = Representation::Tagged();
break;
} }
case ValueType::NULL_CONSTANT: { case ValueType::NULL_CONSTANT: {
value = factory->null_value(); return ReadOnlyRoots(isolate_).null_value();
representation = Representation::Tagged();
break;
} }
case ValueType::UNDEFINED_CONSTANT: { case ValueType::UNDEFINED_CONSTANT: {
value = factory->undefined_value(); return ReadOnlyRoots(isolate_).undefined_value();
representation = Representation::Tagged();
break;
} }
case ValueType::INTEGER: { case ValueType::INTEGER: {
Maybe<int32_t> number = deserializer_.ReadZigZag<int32_t>(); Maybe<int32_t> number = deserializer_.ReadZigZag<int32_t>();
if (number.IsNothing()) { if (number.IsNothing()) {
Throw("Malformed integer"); Throw("Malformed integer");
return; return Smi::zero();
} }
value = factory->NewNumberFromInt(number.FromJust()); return *factory->NewNumberFromInt(number.FromJust());
representation = Representation::Tagged();
break;
} }
case ValueType::DOUBLE: { case ValueType::DOUBLE: {
double number; double number;
if (!deserializer_.ReadDouble(&number)) { if (!deserializer_.ReadDouble(&number)) {
Throw("Malformed double"); Throw("Malformed double");
return; return Smi::zero();
} }
value = factory->NewNumber(number); return *factory->NewNumber(number);
representation = Representation::Tagged();
break;
} }
case ValueType::STRING_ID: { case ValueType::STRING_ID: {
value = ReadString(false); return ReadString(false);
representation = Representation::Tagged();
break;
} }
case ValueType::ARRAY_ID: case ValueType::ARRAY_ID:
uint32_t array_id; uint32_t array_id;
if (!deserializer_.ReadUint32(&array_id) || array_id >= kMaxItemCount) { if (!deserializer_.ReadUint32(&array_id) || array_id >= kMaxItemCount) {
Throw("Malformed variable"); Throw("Malformed variable");
return; return Smi::zero();
} }
if (array_id < current_array_count_) { if (array_id < current_array_count_) {
value = handle(arrays_->get(array_id), isolate_); return arrays_.get(array_id);
} else {
// The array hasn't been deserialized yet.
value = factory->undefined_value();
if (object_for_deferred_reference.is_null()) {
Throw("Invalid array reference");
return;
}
AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, ARRAY_ID, array_id);
} }
representation = Representation::Tagged(); // The array hasn't been deserialized yet.
break; return AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, ARRAY_ID,
array_id);
case ValueType::OBJECT_ID: case ValueType::OBJECT_ID:
uint32_t object_id; uint32_t object_id;
if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount) { if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount) {
Throw("Malformed variable"); Throw("Malformed variable");
return; return Smi::zero();
} }
if (object_id < current_object_count_) { if (object_id < current_object_count_) {
value = handle(objects_->get(object_id), isolate_); return objects_.get(object_id);
} else {
// The object hasn't been deserialized yet.
value = factory->undefined_value();
if (object_for_deferred_reference.is_null()) {
Throw("Invalid object reference");
return;
} }
AddDeferredReference(object_for_deferred_reference, // The object hasn't been deserialized yet.
return AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, OBJECT_ID, index_for_deferred_reference, OBJECT_ID,
object_id); object_id);
}
representation = Representation::Tagged();
break;
case ValueType::FUNCTION_ID: { case ValueType::FUNCTION_ID: {
uint32_t function_id; uint32_t function_id;
if (!deserializer_.ReadUint32(&function_id) || if (!deserializer_.ReadUint32(&function_id) ||
function_id >= function_count_) { function_id >= function_count_) {
Throw("Malformed object property"); Throw("Malformed object property");
return; return Smi::zero();
} }
if (function_id < current_function_count_) { if (function_id < current_function_count_) {
value = handle(functions_->get(function_id), isolate_); return functions_.get(function_id);
} else {
// The function hasn't been deserialized yet.
value = factory->undefined_value();
if (object_for_deferred_reference.is_null()) {
Throw("Invalid object reference");
return;
} }
AddDeferredReference(object_for_deferred_reference, // The function hasn't been deserialized yet.
return AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, FUNCTION_ID, index_for_deferred_reference, FUNCTION_ID,
function_id); function_id);
} }
representation = Representation::Tagged();
break;
}
case ValueType::CLASS_ID: { case ValueType::CLASS_ID: {
uint32_t class_id; uint32_t class_id;
if (!deserializer_.ReadUint32(&class_id) || class_id >= kMaxItemCount) { if (!deserializer_.ReadUint32(&class_id) || class_id >= kMaxItemCount) {
Throw("Malformed object property"); Throw("Malformed object property");
return; return Smi::zero();
} }
if (class_id < current_class_count_) { if (class_id < current_class_count_) {
value = handle(classes_->get(class_id), isolate_); return classes_.get(class_id);
} else {
// The class hasn't been deserialized yet.
value = factory->undefined_value();
if (object_for_deferred_reference.is_null()) {
Throw("Invalid object reference");
return;
}
AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, CLASS_ID, class_id);
} }
representation = Representation::Tagged(); // The class hasn't been deserialized yet.
break; return AddDeferredReference(object_for_deferred_reference,
index_for_deferred_reference, CLASS_ID,
class_id);
} }
case ValueType::REGEXP: { case ValueType::REGEXP: {
Handle<String> pattern = ReadString(false); Handle<String> pattern(ReadString(false), isolate_);
Handle<String> flags_string = ReadString(false); Handle<String> flags_string(ReadString(false), isolate_);
base::Optional<JSRegExp::Flags> flags = base::Optional<JSRegExp::Flags> flags =
JSRegExp::FlagsFromString(isolate_, flags_string); JSRegExp::FlagsFromString(isolate_, flags_string);
if (!flags.has_value()) { if (!flags.has_value()) {
Throw("Malformed flags in regular expression"); Throw("Malformed flags in regular expression");
return; return Smi::zero();
} }
MaybeHandle<JSRegExp> maybe_regexp = MaybeHandle<JSRegExp> maybe_regexp =
JSRegExp::New(isolate_, pattern, flags.value()); JSRegExp::New(isolate_, pattern, flags.value());
if (!maybe_regexp.ToHandle(&value)) { Handle<JSRegExp> regexp;
if (!maybe_regexp.ToHandle(&regexp)) {
Throw("Malformed RegExp"); Throw("Malformed RegExp");
return; return Smi::zero();
} }
representation = Representation::Tagged(); return *regexp;
break;
} }
default: default:
// TODO(v8:11525): Handle other value types. // TODO(v8:11525): Handle other value types.
Throw("Unsupported value type"); Throw("Unsupported value type");
return; return Smi::zero();
} }
} }
...@@ -1985,7 +1976,7 @@ void WebSnapshotDeserializer::ReadFunctionPrototype( ...@@ -1985,7 +1976,7 @@ void WebSnapshotDeserializer::ReadFunctionPrototype(
--object_id; --object_id;
if (object_id < current_object_count_) { if (object_id < current_object_count_) {
if (!SetFunctionPrototype(*function, if (!SetFunctionPrototype(*function,
JSReceiver::cast(objects_->get(object_id)))) { JSReceiver::cast(objects_.get(object_id)))) {
Throw("Can't reuse function prototype"); Throw("Can't reuse function prototype");
return; return;
} }
...@@ -2009,16 +2000,38 @@ bool WebSnapshotDeserializer::SetFunctionPrototype(JSFunction function, ...@@ -2009,16 +2000,38 @@ bool WebSnapshotDeserializer::SetFunctionPrototype(JSFunction function,
return true; return true;
} }
void WebSnapshotDeserializer::AddDeferredReference(Handle<HeapObject> container, HeapObject WebSnapshotDeserializer::AddDeferredReference(
uint32_t index, Handle<HeapObject> container, uint32_t index, ValueType target_type,
ValueType target_type,
uint32_t target_index) { uint32_t target_index) {
if (container.is_null()) {
const char* message = "Invalid reference";
switch (target_type) {
case ARRAY_ID:
message = "Invalid array reference";
break;
case OBJECT_ID:
message = "Invalid object reference";
break;
case CLASS_ID:
message = "Invalid class reference";
break;
case FUNCTION_ID:
message = "Invalid function reference";
break;
default:
break;
}
Throw(message);
return ReadOnlyRoots(isolate_).undefined_value();
}
DCHECK(container->IsPropertyArray() || container->IsContext() || DCHECK(container->IsPropertyArray() || container->IsContext() ||
container->IsFixedArray() || container->IsJSFunction() || container->IsFixedArray() || container->IsJSFunction() ||
container->IsMap()); container->IsMap());
deferred_references_ = ArrayList::Add( deferred_references_ = ArrayList::Add(
isolate_, deferred_references_, container, Smi::FromInt(index), isolate_, deferred_references_, container, Smi::FromInt(index),
Smi::FromInt(target_type), Smi::FromInt(target_index)); Smi::FromInt(target_type), Smi::FromInt(target_index));
// Use HeapObject as placeholder since this might break elements kinds.
return ReadOnlyRoots(isolate_).undefined_value();
} }
void WebSnapshotDeserializer::ProcessDeferredReferences() { void WebSnapshotDeserializer::ProcessDeferredReferences() {
...@@ -2030,18 +2043,14 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2030,18 +2043,14 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
ArrayList raw_deferred_references = *deferred_references_; ArrayList raw_deferred_references = *deferred_references_;
FixedArray raw_functions = *functions_;
FixedArray raw_classes = *classes_;
FixedArray raw_arrays = *arrays_;
FixedArray raw_objects = *objects_;
// Deferred references is a list of (object, index, target type, target index) // Deferred references is a list of (object, index, target type, target index)
// tuples. // tuples.
for (int i = 0; i < raw_deferred_references.Length() - 3; i += 4) { for (int i = 0; i < raw_deferred_references.Length() - 3; i += 4) {
HeapObject container = HeapObject::cast(raw_deferred_references.Get(i)); HeapObject container = HeapObject::cast(raw_deferred_references.Get(i));
int index = raw_deferred_references.Get(i + 1).ToSmi().value(); int index = raw_deferred_references.Get(i + 1).ToSmi().value();
ValueType target_type = ValueType target_type = static_cast<ValueType>(
ValueType(raw_deferred_references.Get(i + 2).ToSmi().value()); raw_deferred_references.Get(i + 2).ToSmi().value());
int target_index = raw_deferred_references.Get(i + 3).ToSmi().value(); int target_index = raw_deferred_references.Get(i + 3).ToSmi().value();
Object target; Object target;
switch (target_type) { switch (target_type) {
...@@ -2053,7 +2062,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2053,7 +2062,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
Throw("Invalid function reference"); Throw("Invalid function reference");
return; return;
} }
target = raw_functions.get(target_index); target = functions_.get(target_index);
break; break;
case CLASS_ID: case CLASS_ID:
if (static_cast<uint32_t>(target_index) >= class_count_) { if (static_cast<uint32_t>(target_index) >= class_count_) {
...@@ -2061,7 +2070,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2061,7 +2070,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
Throw("Invalid class reference"); Throw("Invalid class reference");
return; return;
} }
target = raw_classes.get(target_index); target = classes_.get(target_index);
break; break;
case ARRAY_ID: case ARRAY_ID:
if (static_cast<uint32_t>(target_index) >= array_count_) { if (static_cast<uint32_t>(target_index) >= array_count_) {
...@@ -2069,7 +2078,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2069,7 +2078,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
Throw("Invalid array reference"); Throw("Invalid array reference");
return; return;
} }
target = raw_arrays.get(target_index); target = arrays_.get(target_index);
break; break;
case OBJECT_ID: case OBJECT_ID:
if (static_cast<uint32_t>(target_index) >= object_count_) { if (static_cast<uint32_t>(target_index) >= object_count_) {
...@@ -2077,7 +2086,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() { ...@@ -2077,7 +2086,7 @@ void WebSnapshotDeserializer::ProcessDeferredReferences() {
Throw("Invalid object reference"); Throw("Invalid object reference");
return; return;
} }
target = raw_objects.get(target_index); target = objects_.get(target_index);
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
......
...@@ -243,6 +243,14 @@ class V8_EXPORT WebSnapshotDeserializer ...@@ -243,6 +243,14 @@ class V8_EXPORT WebSnapshotDeserializer
uint32_t array_count() const { return array_count_; } uint32_t array_count() const { return array_count_; }
uint32_t object_count() const { return object_count_; } uint32_t object_count() const { return object_count_; }
static void UpdatePointersCallback(v8::Isolate* isolate, v8::GCType type,
v8::GCCallbackFlags flags,
void* deserializer) {
reinterpret_cast<WebSnapshotDeserializer*>(deserializer)->UpdatePointers();
}
void UpdatePointers();
private: private:
WebSnapshotDeserializer(Isolate* isolate, Handle<Object> script_name, WebSnapshotDeserializer(Isolate* isolate, Handle<Object> script_name,
base::Vector<const uint8_t> buffer); base::Vector<const uint8_t> buffer);
...@@ -255,7 +263,7 @@ class V8_EXPORT WebSnapshotDeserializer ...@@ -255,7 +263,7 @@ class V8_EXPORT WebSnapshotDeserializer
WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete; WebSnapshotDeserializer& operator=(const WebSnapshotDeserializer&) = delete;
void DeserializeStrings(); void DeserializeStrings();
Handle<String> ReadString(bool internalize = false); String ReadString(bool internalize = false);
void DeserializeMaps(); void DeserializeMaps();
void DeserializeContexts(); void DeserializeContexts();
Handle<ScopeInfo> CreateScopeInfo(uint32_t variable_count, bool has_parent, Handle<ScopeInfo> CreateScopeInfo(uint32_t variable_count, bool has_parent,
...@@ -269,31 +277,47 @@ class V8_EXPORT WebSnapshotDeserializer ...@@ -269,31 +277,47 @@ class V8_EXPORT WebSnapshotDeserializer
void DeserializeArrays(); void DeserializeArrays();
void DeserializeObjects(); void DeserializeObjects();
void DeserializeExports(); void DeserializeExports();
void ReadValue( Object ReadValue(
Handle<Object>& value, Representation& representation,
Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(), Handle<HeapObject> object_for_deferred_reference = Handle<HeapObject>(),
uint32_t index_for_deferred_reference = 0); uint32_t index_for_deferred_reference = 0);
void ReadFunctionPrototype(Handle<JSFunction> function); void ReadFunctionPrototype(Handle<JSFunction> function);
bool SetFunctionPrototype(JSFunction function, JSReceiver prototype); bool SetFunctionPrototype(JSFunction function, JSReceiver prototype);
void AddDeferredReference(Handle<HeapObject> container, uint32_t index, HeapObject AddDeferredReference(Handle<HeapObject> container, uint32_t index,
ValueType target_type, ValueType target_type,
uint32_t target_object_index); uint32_t target_object_index);
void ProcessDeferredReferences(); void ProcessDeferredReferences();
// Not virtual, on purpose (because it doesn't need to be). // Not virtual, on purpose (because it doesn't need to be).
void Throw(const char* message); void Throw(const char* message);
Handle<FixedArray> strings_; Handle<FixedArray> strings_handle_;
Handle<FixedArray> maps_; FixedArray strings_;
Handle<FixedArray> contexts_;
Handle<FixedArray> functions_; Handle<FixedArray> maps_handle_;
Handle<FixedArray> classes_; FixedArray maps_;
Handle<FixedArray> arrays_;
Handle<FixedArray> objects_; Handle<FixedArray> contexts_handle_;
FixedArray contexts_;
Handle<FixedArray> functions_handle_;
FixedArray functions_;
Handle<FixedArray> classes_handle_;
FixedArray classes_;
Handle<FixedArray> arrays_handle_;
FixedArray arrays_;
Handle<FixedArray> objects_handle_;
FixedArray objects_;
Handle<ArrayList> deferred_references_; Handle<ArrayList> deferred_references_;
Handle<WeakFixedArray> shared_function_infos_; Handle<WeakFixedArray> shared_function_infos_handle_;
WeakFixedArray shared_function_infos_;
Handle<ObjectHashTable> shared_function_info_table_; Handle<ObjectHashTable> shared_function_info_table_;
Handle<Script> script_; Handle<Script> script_;
Handle<Object> script_name_; Handle<Object> script_name_;
......
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