[runtime] Properly calculate upper bound for NOF in_object_properties

Bug: chr:81499
Change-Id: I5a18b9ec061d426e21c08747a8c18a36bf5ca194
Reviewed-on: https://chromium-review.googlesource.com/950724
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51812}
This commit is contained in:
Camillo Bruni 2018-03-08 15:11:52 +01:00 committed by Commit Bot
parent 31f2a821c9
commit 0d26307046
6 changed files with 121 additions and 3 deletions

View File

@ -123,7 +123,8 @@ class FieldIndex final {
};
// Offset of first inobject property from beginning of object.
class FirstInobjectPropertyOffsetBits
: public BitField64<int, InObjectPropertyBits::kNext, 7> {};
: public BitField64<int, InObjectPropertyBits::kNext,
kFirstInobjectPropertyOffsetBitCount> {};
class IsHiddenField
: public BitField64<bool, FirstInobjectPropertyOffsetBits::kNext, 1> {};
STATIC_ASSERT(IsHiddenField::kNext <= 64);

View File

@ -2440,6 +2440,7 @@ int ObjectTemplateInfo::embedder_field_count() const {
}
void ObjectTemplateInfo::set_embedder_field_count(int count) {
DCHECK_LE(count, JSObject::kMaxEmbedderFields);
return set_data(
Smi::FromInt(EmbedderFieldCount::update(Smi::ToInt(data()), count)));
}

View File

@ -13663,18 +13663,24 @@ void JSFunction::CalculateInstanceSizeHelper(InstanceType instance_type,
int requested_in_object_properties,
int* instance_size,
int* in_object_properties) {
DCHECK_LE(static_cast<unsigned>(requested_embedder_fields),
JSObject::kMaxEmbedderFields);
int header_size = JSObject::GetHeaderSize(instance_type, has_prototype_slot);
int max_nof_fields =
(JSObject::kMaxInstanceSize - header_size) >> kPointerSizeLog2;
CHECK_LE(max_nof_fields, JSObject::kMaxInObjectProperties);
*in_object_properties = Min(requested_in_object_properties, max_nof_fields);
CHECK_LE(requested_embedder_fields, max_nof_fields - *in_object_properties);
CHECK_LE(static_cast<unsigned>(requested_embedder_fields),
static_cast<unsigned>(max_nof_fields));
*in_object_properties = Min(requested_in_object_properties,
max_nof_fields - requested_embedder_fields);
*instance_size =
header_size +
((requested_embedder_fields + *in_object_properties) << kPointerSizeLog2);
CHECK_EQ(*in_object_properties,
((*instance_size - header_size) >> kPointerSizeLog2) -
requested_embedder_fields);
CHECK_LE(static_cast<unsigned>(*instance_size),
static_cast<unsigned>(JSObject::kMaxInstanceSize));
}
// static

View File

@ -2646,6 +2646,11 @@ class JSObject: public JSReceiver {
static const int kMaxInObjectProperties =
(kMaxInstanceSize - kHeaderSize) >> kPointerSizeLog2;
STATIC_ASSERT(kMaxInObjectProperties <= kMaxNumberOfDescriptors);
// TODO(cbruni): Revisit calculation of the max supported embedder fields.
static const int kMaxEmbedderFields =
((1 << kFirstInobjectPropertyOffsetBitCount) - 1 - kHeaderSize) >>
kPointerSizeLog2;
STATIC_ASSERT(kMaxEmbedderFields <= kMaxInObjectProperties);
class BodyDescriptor;
// No weak fields.

View File

@ -197,6 +197,7 @@ class Representation {
static const int kDescriptorIndexBitCount = 10;
static const int kFirstInobjectPropertyOffsetBitCount = 7;
// The maximum number of descriptors we want in a descriptor array. It should
// fit in a page and also the following should hold:
// kMaxNumberOfDescriptors + kFieldsAdded <= PropertyArray::kMaxLength.

View File

@ -2730,6 +2730,110 @@ THREADED_TEST(InternalFields) {
CHECK_EQ(17, obj->GetInternalField(0)->Int32Value(env.local()).FromJust());
}
TEST(InternalFieldsSubclassing) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
for (int nof_embedder_fields = 0;
nof_embedder_fields < i::JSObject::kMaxEmbedderFields;
nof_embedder_fields++) {
Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
instance_templ->SetInternalFieldCount(nof_embedder_fields);
Local<Function> constructor =
templ->GetFunction(env.local()).ToLocalChecked();
// Check that instances have the correct NOF properties.
Local<v8::Object> obj =
constructor->NewInstance(env.local()).ToLocalChecked();
i::Handle<i::JSObject> i_obj =
i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*obj));
CHECK_EQ(nof_embedder_fields, obj->InternalFieldCount());
CHECK_EQ(0, i_obj->map()->GetInObjectProperties());
// Check writing and reading internal fields.
for (int j = 0; j < nof_embedder_fields; j++) {
CHECK(obj->GetInternalField(j)->IsUndefined());
int value = 17 + j;
obj->SetInternalField(j, v8_num(value));
}
for (int j = 0; j < nof_embedder_fields; j++) {
int value = 17 + j;
CHECK_EQ(value,
obj->GetInternalField(j)->Int32Value(env.local()).FromJust());
}
CHECK(env->Global()
->Set(env.local(), v8_str("BaseClass"), constructor)
.FromJust());
// Create various levels of subclasses to stress instance size calculation.
const int kMaxNofProperties =
i::JSObject::kMaxInObjectProperties - nof_embedder_fields;
// Select only a few values to speed up the test.
int sizes[] = {0,
1,
2,
3,
4,
5,
6,
kMaxNofProperties / 4,
kMaxNofProperties / 2,
kMaxNofProperties - 2,
kMaxNofProperties - 1,
kMaxNofProperties + 1,
kMaxNofProperties + 2,
kMaxNofProperties * 2,
kMaxNofProperties * 2};
for (size_t i = 0; i < arraysize(sizes); i++) {
int nof_properties = sizes[i];
bool in_object_only = nof_properties <= kMaxNofProperties;
std::ostringstream src;
// Assembler source string for a subclass with {nof_properties}
// in-object properties.
src << "(function() {\n"
<< " class SubClass extends BaseClass {\n"
<< " constructor() {\n"
<< " super();\n";
// Set {nof_properties} instance properties in the constructor.
for (int j = 0; j < nof_properties; j++) {
src << " this.property" << j << " = " << j << ";\n";
}
src << " }\n"
<< " };\n"
<< " let instance;\n"
<< " for (let i = 0; i < 3; i++) {\n"
<< " instance = new SubClass();\n"
<< " }"
<< " return instance;\n"
<< "})();";
Local<v8::Object> value = CompileRun(src.str().c_str()).As<v8::Object>();
i::Handle<i::JSObject> i_value =
i::Handle<i::JSObject>::cast(v8::Utils::OpenHandle(*value));
#ifdef VERIFY_HEAP
i_value->HeapObjectVerify();
i_value->map()->HeapObjectVerify();
i_value->map()->FindRootMap()->HeapObjectVerify();
#endif
CHECK_EQ(nof_embedder_fields, value->InternalFieldCount());
if (in_object_only) {
CHECK_LE(nof_properties, i_value->map()->GetInObjectProperties());
} else {
CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
}
// Make Sure we get the precise property count.
i_value->map()->FindRootMap()->CompleteInobjectSlackTracking();
// TODO(cbruni): fix accounting to make this condition true.
// CHECK_EQ(0, i_value->map()->UnusedPropertyFields());
if (in_object_only) {
CHECK_EQ(nof_properties, i_value->map()->GetInObjectProperties());
} else {
CHECK_LE(kMaxNofProperties, i_value->map()->GetInObjectProperties());
}
}
}
}
THREADED_TEST(InternalFieldsOfRegularObjects) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();