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