[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:
parent
31f2a821c9
commit
0d26307046
@ -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);
|
||||
|
@ -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)));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user