[runtime] Fix embedder fields offset calculations

Embedder fields are located between JSObject header and inobject fields
and there must be no gaps.
This CL adds respective check to Map verification and fixes existing
issues.

Bug: v8:10391
Change-Id: If55652095588f8704c9a375fb86be1599816aa86
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3482436
Auto-Submit: Igor Sheludko <ishell@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79227}
This commit is contained in:
Igor Sheludko 2022-02-23 00:56:17 +01:00 committed by V8 LUCI CQ
parent 5145860836
commit c4712e8f7e
4 changed files with 26 additions and 14 deletions

View File

@ -526,8 +526,19 @@ void Map::MapVerify(Isolate* isolate) {
TransitionsAccessor(isolate, *this).IsConsistentWithBackPointers());
// Only JSFunction maps have has_prototype_slot() bit set and constructible
// JSFunction objects must have prototype slot.
CHECK_IMPLIES(has_prototype_slot(),
InstanceTypeChecker::IsJSFunction(instance_type()));
CHECK_IMPLIES(has_prototype_slot(), IsJSFunctionMap());
if (IsJSObjectMap()) {
int header_end_offset = JSObject::GetHeaderSize(*this);
int inobject_fields_start_offset = GetInObjectPropertyOffset(0);
// Ensure that embedder fields are located exactly between header and
// inobject properties.
CHECK_EQ(header_end_offset, JSObject::GetEmbedderFieldsStartOffset(*this));
CHECK_EQ(header_end_offset +
JSObject::GetEmbedderFieldCount(*this) * kEmbedderDataSlotSize,
inobject_fields_start_offset);
}
if (!may_have_interesting_symbols()) {
CHECK(!has_named_interceptor());
CHECK(!is_dictionary_map());

View File

@ -432,6 +432,12 @@ V8_NOINLINE Handle<JSFunction> CreateFunctionForBuiltinWithPrototype(
}
Handle<Map> initial_map =
factory->NewMap(type, instance_size, elements_kind, inobject_properties);
if (type == JS_FUNCTION_TYPE) {
DCHECK_EQ(instance_size, JSFunction::kSizeWithPrototype);
// Since we are creating an initial map for JSFunction objects with
// prototype slot, set the respective bit.
initial_map->set_has_prototype_slot(true);
}
// TODO(littledan): Why do we have this is_generator test when
// NewFunctionPrototype already handles finding an appropriately
// shared prototype?

View File

@ -679,8 +679,9 @@ bool FastInitializeDerivedMap(Isolate* isolate, Handle<JSFunction> new_target,
static_cast<int>(constructor->shared().expected_nof_properties()),
JSFunction::CalculateExpectedNofProperties(isolate, new_target));
JSFunction::CalculateInstanceSizeHelper(
instance_type, true, embedder_fields, expected_nof_properties,
&instance_size, &in_object_properties);
instance_type, constructor_initial_map->has_prototype_slot(),
embedder_fields, expected_nof_properties, &instance_size,
&in_object_properties);
int pre_allocated = constructor_initial_map->GetInObjectProperties() -
constructor_initial_map->UnusedPropertyFields();
@ -1038,13 +1039,8 @@ void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
JSObject::kMaxEmbedderFields);
int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
if (requested_embedder_fields) {
// If there are embedder fields, then the embedder fields start offset must
// be properly aligned (embedder fields are located between object header
// and inobject fields).
header_size = RoundUp<kSystemPointerSize>(header_size);
requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
}
requested_embedder_fields *= kEmbedderDataSlotSizeInTaggedSlots;
int max_nof_fields =
(JSObject::kMaxInstanceSize - header_size) >> kTaggedSizeLog2;
CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);

View File

@ -1751,9 +1751,8 @@ static void TestReconfigureElementsKind_GeneralizeFieldInPlace(
Expectations expectations(isolate, PACKED_SMI_ELEMENTS);
// Create a map, add required properties to it and initialize expectations.
Handle<Map> initial_map = Map::Create(isolate, 0);
initial_map->set_instance_type(JS_ARRAY_TYPE);
initial_map->set_elements_kind(PACKED_SMI_ELEMENTS);
Handle<Map> initial_map = isolate->factory()->NewMap(
JS_ARRAY_TYPE, JSArray::kHeaderSize, PACKED_SMI_ELEMENTS);
Handle<Map> map = initial_map;
map = expectations.AsElementsKind(map, PACKED_ELEMENTS);