Reland "[web snapshot] Dehandlify more parts of the deserializer"
This is a reland of 7ddacd681b
- Allocate JSObject only after the properties are fully deserialized
Original change's description:
> [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/+/3416242
> Reviewed-by: Marja Hölttä <marja@chromium.org>
> Commit-Queue: Camillo Bruni <cbruni@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#78862}
Change-Id: I2b64e59df02d4d723f76e157aad045f94a22d2b9
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3427202
Auto-Submit: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78902}
This commit is contained in:
parent
8370387f21
commit
418aa66f69
@ -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 raw_map = Map::cast(maps_.get(map_id));
|
||||
Handle<DescriptorArray> descriptors =
|
||||
handle(map->instance_descriptors(kRelaxedLoad), isolate_);
|
||||
int no_properties = map->NumberOfOwnDescriptors();
|
||||
handle(raw_map.instance_descriptors(kRelaxedLoad), isolate_);
|
||||
int no_properties = raw_map.NumberOfOwnDescriptors();
|
||||
// TODO(v8:11525): In-object properties.
|
||||
Handle<Map> map(raw_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(®exp)) {
|
||||
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_;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user