Move property addition code from JSObject to Map

BUG=
R=ishell@chromium.org

Review URL: https://codereview.chromium.org/238543005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20791 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2014-04-16 10:45:57 +00:00
parent 63a477b29b
commit cf26c1421a
3 changed files with 121 additions and 101 deletions

View File

@ -1823,6 +1823,62 @@ String* JSReceiver::constructor_name() {
}
MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
Handle<Name> name,
Handle<HeapType> type,
PropertyAttributes attributes,
Representation representation,
TransitionFlag flag) {
ASSERT(DescriptorArray::kNotFound ==
map->instance_descriptors()->Search(
*name, map->NumberOfOwnDescriptors()));
// Ensure the descriptor array does not get too big.
if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
return MaybeHandle<Map>();
}
// Normalize the object if the name is an actual name (not the
// hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = map->GetIsolate();
if (!name->IsCacheable(isolate)) return MaybeHandle<Map>();
// Compute the new index for new field.
int index = map->NextFreePropertyIndex();
if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
representation = Representation::Tagged();
type = HeapType::Any(isolate);
}
FieldDescriptor new_field_desc(name, index, type, attributes, representation);
Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
}
new_map->set_unused_property_fields(unused_property_fields);
return new_map;
}
MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
Handle<Name> name,
Handle<Object> constant,
PropertyAttributes attributes,
TransitionFlag flag) {
// Ensure the descriptor array does not get too big.
if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
return MaybeHandle<Map>();
}
// Allocate new instance descriptors with (name, constant) added.
ConstantDescriptor new_constant_desc(name, constant, attributes);
return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
}
void JSObject::AddFastProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> value,
@ -1831,40 +1887,34 @@ void JSObject::AddFastProperty(Handle<JSObject> object,
ValueType value_type,
TransitionFlag flag) {
ASSERT(!object->IsJSGlobalProxy());
ASSERT(DescriptorArray::kNotFound ==
object->map()->instance_descriptors()->Search(
*name, object->map()->NumberOfOwnDescriptors()));
// Normalize the object if the name is an actual name (not the
// hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties.
Isolate* isolate = object->GetIsolate();
if (!name->IsCacheable(isolate) ||
object->TooManyFastProperties(store_mode)) {
MaybeHandle<Map> maybe_map;
if (value->IsJSFunction()) {
maybe_map = Map::CopyWithConstant(
handle(object->map()), name, value, attributes, flag);
} else if (!object->TooManyFastProperties(store_mode)) {
Isolate* isolate = object->GetIsolate();
Representation representation = value->OptimalRepresentation(value_type);
maybe_map = Map::CopyWithField(
handle(object->map(), isolate), name,
value->OptimalType(isolate, representation),
attributes, representation, flag);
}
Handle<Map> new_map;
if (!maybe_map.ToHandle(&new_map)) {
NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
AddSlowProperty(object, name, value, attributes);
return;
}
// Allocate new instance descriptors with (name, index) added
if (object->IsJSContextExtensionObject()) value_type = FORCE_TAGGED;
Representation representation = value->OptimalRepresentation(value_type);
// Compute the new index for new field.
int index = object->map()->NextFreePropertyIndex();
Handle<HeapType> type = value->OptimalType(isolate, representation);
FieldDescriptor new_field_desc(name, index, type, attributes, representation);
Handle<Map> new_map = Map::CopyAddDescriptor(
handle(object->map()), &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded;
}
new_map->set_unused_property_fields(unused_property_fields);
JSObject::MigrateToMap(object, new_map);
PropertyDetails details = new_map->GetLastDescriptorDetails();
if (details.type() != FIELD) return;
Representation representation = details.representation();
int index = details.field_index();
if (representation.IsDouble()) {
// Nothing more to be done.
if (value->IsUninitialized()) return;
@ -1876,24 +1926,6 @@ void JSObject::AddFastProperty(Handle<JSObject> object,
}
void JSObject::AddConstantProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> constant,
PropertyAttributes attributes,
TransitionFlag initial_flag) {
ASSERT(!object->IsGlobalObject());
// Don't add transitions to special properties with non-trivial attributes.
TransitionFlag flag = attributes != NONE ? OMIT_TRANSITION : initial_flag;
// Allocate new instance descriptors with (name, constant) added.
ConstantDescriptor new_constant_desc(name, constant, attributes);
Handle<Map> new_map = Map::CopyAddDescriptor(
handle(object->map()), &new_constant_desc, flag);
JSObject::MigrateToMap(object, new_map);
}
void JSObject::AddSlowProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> value,
@ -1958,25 +1990,11 @@ MaybeHandle<Object> JSObject::AddProperty(
}
if (object->HasFastProperties()) {
// Ensure the descriptor array does not get too big.
if (object->map()->NumberOfOwnDescriptors() <= kMaxNumberOfDescriptors) {
// TODO(verwaest): Support other constants.
// if (mode == ALLOW_AS_CONSTANT &&
// !value->IsTheHole() &&
// !value->IsConsString()) {
if (value->IsJSFunction()) {
AddConstantProperty(object, name, value, attributes, transition_flag);
} else {
AddFastProperty(object, name, value, attributes, store_mode,
value_type, transition_flag);
}
} else {
// Normalize the object to prevent very large instance descriptors.
// This eliminates unwanted N^2 allocation and lookup behavior.
NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
AddSlowProperty(object, name, value, attributes);
}
} else {
AddFastProperty(object, name, value, attributes, store_mode,
value_type, transition_flag);
}
if (!object->HasFastProperties()) {
AddSlowProperty(object, name, value, attributes);
}
@ -6616,15 +6634,6 @@ static bool TryAccessorTransition(Handle<JSObject> self,
}
static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
Handle<Name> name,
Handle<AccessorPair> accessors,
PropertyAttributes attributes) {
CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
return Map::CopyInsertDescriptor(map, &new_accessors_desc, INSERT_TRANSITION);
}
bool JSObject::DefineFastAccessor(Handle<JSObject> object,
Handle<Name> name,
AccessorComponent component,
@ -6689,8 +6698,11 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
: isolate->factory()->NewAccessorPair();
accessors->set(component, *accessor);
Handle<Map> new_map = CopyInsertDescriptor(Handle<Map>(object->map()),
name, accessors, attributes);
CallbacksDescriptor new_accessors_desc(name, accessors, attributes);
Handle<Map> new_map = Map::CopyInsertDescriptor(
handle(object->map()), &new_accessors_desc, INSERT_TRANSITION);
JSObject::MigrateToMap(object, new_map);
return true;
}

View File

@ -2891,18 +2891,6 @@ class JSObject: public JSReceiver {
StoreMode mode = ALLOW_AS_CONSTANT,
TransitionFlag flag = INSERT_TRANSITION);
// Add a constant function property to a fast-case object.
// This leaves a CONSTANT_TRANSITION in the old map, and
// if it is called on a second object with this map, a
// normal property is added instead, with a map transition.
// This avoids the creation of many maps with the same constant
// function, all orphaned.
static void AddConstantProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> constant,
PropertyAttributes attributes,
TransitionFlag flag);
// Add a property to a fast-case object.
static void AddFastProperty(Handle<JSObject> object,
Handle<Name> name,
@ -6416,9 +6404,6 @@ class Map: public HeapObject {
Handle<DescriptorArray> descriptors,
TransitionFlag flag,
SimpleTransitionFlag simple_flag = FULL_TRANSITION);
static Handle<Map> CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag);
static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag);
@ -6428,6 +6413,21 @@ class Map: public HeapObject {
int index,
TransitionFlag flag);
MUST_USE_RESULT static MaybeHandle<Map> CopyWithField(
Handle<Map> map,
Handle<Name> name,
Handle<HeapType> type,
PropertyAttributes attributes,
Representation representation,
TransitionFlag flag);
MUST_USE_RESULT static MaybeHandle<Map> CopyWithConstant(
Handle<Map> map,
Handle<Name> name,
Handle<Object> constant,
PropertyAttributes attributes,
TransitionFlag flag);
static Handle<Map> AsElementsKind(Handle<Map> map, ElementsKind kind);
static Handle<Map> CopyAsElementsKind(Handle<Map> map,
@ -6678,6 +6678,9 @@ class Map: public HeapObject {
Handle<Map> map,
int new_descriptor,
Handle<DescriptorArray> descriptors);
static Handle<Map> CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag);
// Zaps the contents of backing data structures. Note that the
// heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects

View File

@ -2633,14 +2633,15 @@ TEST(Regress1465) {
v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 256;
CompileRun("function F() {}");
{
AlwaysAllocateScope always_allocate(CcTest::i_isolate());
for (int i = 0; i < transitions_count; i++) {
EmbeddedVector<char, 64> buffer;
OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
CompileRun(buffer.start());
}
CompileRun("var root = new Object;");
CompileRun("var root = new F;");
}
Handle<JSObject> root =
@ -2669,7 +2670,7 @@ static void AddTransitions(int transitions_count) {
AlwaysAllocateScope always_allocate(CcTest::i_isolate());
for (int i = 0; i < transitions_count; i++) {
EmbeddedVector<char, 64> buffer;
OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
OS::SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
CompileRun(buffer.start());
}
}
@ -2702,8 +2703,9 @@ TEST(TransitionArrayShrinksDuringAllocToZero) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10;
CompileRun("function F() { }");
AddTransitions(transitions_count);
CompileRun("var root = new Object;");
CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking.
@ -2711,8 +2713,8 @@ TEST(TransitionArrayShrinksDuringAllocToZero) {
CHECK_EQ(transitions_count, transitions_before);
// Get rid of o
CompileRun("o = new Object;"
"root = new Object");
CompileRun("o = new F;"
"root = new F");
root = GetByName("root");
AddPropertyTo(2, root, "funny");
@ -2730,8 +2732,9 @@ TEST(TransitionArrayShrinksDuringAllocToOne) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10;
CompileRun("function F() {}");
AddTransitions(transitions_count);
CompileRun("var root = new Object;");
CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking.
@ -2755,8 +2758,9 @@ TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10;
CompileRun("function F() {}");
AddTransitions(transitions_count);
CompileRun("var root = new Object;");
CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking.
@ -2780,16 +2784,17 @@ TEST(TransitionArraySimpleToFull) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 1;
CompileRun("function F() {}");
AddTransitions(transitions_count);
CompileRun("var root = new Object;");
CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking.
int transitions_before = CountMapTransitions(root->map());
CHECK_EQ(transitions_count, transitions_before);
CompileRun("o = new Object;"
"root = new Object");
CompileRun("o = new F;"
"root = new F");
root = GetByName("root");
ASSERT(root->map()->transitions()->IsSimpleTransition());
AddPropertyTo(2, root, "happy");