Commit cf26c142 authored by verwaest@chromium.org's avatar verwaest@chromium.org

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
parent 63a477b2
...@@ -1823,74 +1823,106 @@ String* JSReceiver::constructor_name() { ...@@ -1823,74 +1823,106 @@ String* JSReceiver::constructor_name() {
} }
void JSObject::AddFastProperty(Handle<JSObject> object, MaybeHandle<Map> Map::CopyWithField(Handle<Map> map,
Handle<Name> name, Handle<Name> name,
Handle<Object> value, Handle<HeapType> type,
PropertyAttributes attributes, PropertyAttributes attributes,
StoreFromKeyed store_mode, Representation representation,
ValueType value_type,
TransitionFlag flag) { TransitionFlag flag) {
ASSERT(!object->IsJSGlobalProxy());
ASSERT(DescriptorArray::kNotFound == ASSERT(DescriptorArray::kNotFound ==
object->map()->instance_descriptors()->Search( map->instance_descriptors()->Search(
*name, object->map()->NumberOfOwnDescriptors())); *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 // Normalize the object if the name is an actual name (not the
// hidden strings) and is not a real identifier. // hidden strings) and is not a real identifier.
// Normalize the object if it will have too many fast properties. // Normalize the object if it will have too many fast properties.
Isolate* isolate = object->GetIsolate(); Isolate* isolate = map->GetIsolate();
if (!name->IsCacheable(isolate) || if (!name->IsCacheable(isolate)) return MaybeHandle<Map>();
object->TooManyFastProperties(store_mode)) {
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. // Compute the new index for new field.
int index = object->map()->NextFreePropertyIndex(); int index = map->NextFreePropertyIndex();
if (map->instance_type() == JS_CONTEXT_EXTENSION_OBJECT_TYPE) {
representation = Representation::Tagged();
type = HeapType::Any(isolate);
}
Handle<HeapType> type = value->OptimalType(isolate, representation);
FieldDescriptor new_field_desc(name, index, type, attributes, representation); FieldDescriptor new_field_desc(name, index, type, attributes, representation);
Handle<Map> new_map = Map::CopyAddDescriptor( Handle<Map> new_map = Map::CopyAddDescriptor(map, &new_field_desc, flag);
handle(object->map()), &new_field_desc, flag);
int unused_property_fields = new_map->unused_property_fields() - 1; int unused_property_fields = new_map->unused_property_fields() - 1;
if (unused_property_fields < 0) { if (unused_property_fields < 0) {
unused_property_fields += JSObject::kFieldsAdded; unused_property_fields += JSObject::kFieldsAdded;
} }
new_map->set_unused_property_fields(unused_property_fields); new_map->set_unused_property_fields(unused_property_fields);
return new_map;
JSObject::MigrateToMap(object, new_map);
if (representation.IsDouble()) {
// Nothing more to be done.
if (value->IsUninitialized()) return;
HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(index));
box->set_value(value->Number());
} else {
object->FastPropertyAtPut(index, *value);
}
} }
void JSObject::AddConstantProperty(Handle<JSObject> object, MaybeHandle<Map> Map::CopyWithConstant(Handle<Map> map,
Handle<Name> name, Handle<Name> name,
Handle<Object> constant, Handle<Object> constant,
PropertyAttributes attributes, PropertyAttributes attributes,
TransitionFlag initial_flag) { TransitionFlag flag) {
ASSERT(!object->IsGlobalObject()); // Ensure the descriptor array does not get too big.
// Don't add transitions to special properties with non-trivial attributes. if (map->NumberOfOwnDescriptors() >= kMaxNumberOfDescriptors) {
TransitionFlag flag = attributes != NONE ? OMIT_TRANSITION : initial_flag; return MaybeHandle<Map>();
}
// Allocate new instance descriptors with (name, constant) added. // Allocate new instance descriptors with (name, constant) added.
ConstantDescriptor new_constant_desc(name, constant, attributes); ConstantDescriptor new_constant_desc(name, constant, attributes);
Handle<Map> new_map = Map::CopyAddDescriptor( return Map::CopyAddDescriptor(map, &new_constant_desc, flag);
handle(object->map()), &new_constant_desc, flag); }
void JSObject::AddFastProperty(Handle<JSObject> object,
Handle<Name> name,
Handle<Object> value,
PropertyAttributes attributes,
StoreFromKeyed store_mode,
ValueType value_type,
TransitionFlag flag) {
ASSERT(!object->IsJSGlobalProxy());
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);
return;
}
JSObject::MigrateToMap(object, new_map); 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;
HeapNumber* box = HeapNumber::cast(object->RawFastPropertyAt(index));
box->set_value(value->Number());
} else {
object->FastPropertyAtPut(index, *value);
}
} }
...@@ -1958,25 +1990,11 @@ MaybeHandle<Object> JSObject::AddProperty( ...@@ -1958,25 +1990,11 @@ MaybeHandle<Object> JSObject::AddProperty(
} }
if (object->HasFastProperties()) { 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, AddFastProperty(object, name, value, attributes, store_mode,
value_type, transition_flag); value_type, transition_flag);
} }
} else {
// Normalize the object to prevent very large instance descriptors. if (!object->HasFastProperties()) {
// This eliminates unwanted N^2 allocation and lookup behavior.
NormalizeProperties(object, CLEAR_INOBJECT_PROPERTIES, 0);
AddSlowProperty(object, name, value, attributes);
}
} else {
AddSlowProperty(object, name, value, attributes); AddSlowProperty(object, name, value, attributes);
} }
...@@ -6616,15 +6634,6 @@ static bool TryAccessorTransition(Handle<JSObject> self, ...@@ -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, bool JSObject::DefineFastAccessor(Handle<JSObject> object,
Handle<Name> name, Handle<Name> name,
AccessorComponent component, AccessorComponent component,
...@@ -6689,8 +6698,11 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object, ...@@ -6689,8 +6698,11 @@ bool JSObject::DefineFastAccessor(Handle<JSObject> object,
? AccessorPair::Copy(Handle<AccessorPair>(source_accessors)) ? AccessorPair::Copy(Handle<AccessorPair>(source_accessors))
: isolate->factory()->NewAccessorPair(); : isolate->factory()->NewAccessorPair();
accessors->set(component, *accessor); 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); JSObject::MigrateToMap(object, new_map);
return true; return true;
} }
......
...@@ -2891,18 +2891,6 @@ class JSObject: public JSReceiver { ...@@ -2891,18 +2891,6 @@ class JSObject: public JSReceiver {
StoreMode mode = ALLOW_AS_CONSTANT, StoreMode mode = ALLOW_AS_CONSTANT,
TransitionFlag flag = INSERT_TRANSITION); 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. // Add a property to a fast-case object.
static void AddFastProperty(Handle<JSObject> object, static void AddFastProperty(Handle<JSObject> object,
Handle<Name> name, Handle<Name> name,
...@@ -6416,9 +6404,6 @@ class Map: public HeapObject { ...@@ -6416,9 +6404,6 @@ class Map: public HeapObject {
Handle<DescriptorArray> descriptors, Handle<DescriptorArray> descriptors,
TransitionFlag flag, TransitionFlag flag,
SimpleTransitionFlag simple_flag = FULL_TRANSITION); SimpleTransitionFlag simple_flag = FULL_TRANSITION);
static Handle<Map> CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag);
static Handle<Map> CopyInsertDescriptor(Handle<Map> map, static Handle<Map> CopyInsertDescriptor(Handle<Map> map,
Descriptor* descriptor, Descriptor* descriptor,
TransitionFlag flag); TransitionFlag flag);
...@@ -6428,6 +6413,21 @@ class Map: public HeapObject { ...@@ -6428,6 +6413,21 @@ class Map: public HeapObject {
int index, int index,
TransitionFlag flag); 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> AsElementsKind(Handle<Map> map, ElementsKind kind);
static Handle<Map> CopyAsElementsKind(Handle<Map> map, static Handle<Map> CopyAsElementsKind(Handle<Map> map,
...@@ -6678,6 +6678,9 @@ class Map: public HeapObject { ...@@ -6678,6 +6678,9 @@ class Map: public HeapObject {
Handle<Map> map, Handle<Map> map,
int new_descriptor, int new_descriptor,
Handle<DescriptorArray> descriptors); Handle<DescriptorArray> descriptors);
static Handle<Map> CopyAddDescriptor(Handle<Map> map,
Descriptor* descriptor,
TransitionFlag flag);
// Zaps the contents of backing data structures. Note that the // Zaps the contents of backing data structures. Note that the
// heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects // heap verifier (i.e. VerifyMarkingVisitor) relies on zapping of objects
......
...@@ -2633,14 +2633,15 @@ TEST(Regress1465) { ...@@ -2633,14 +2633,15 @@ TEST(Regress1465) {
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 256; static const int transitions_count = 256;
CompileRun("function F() {}");
{ {
AlwaysAllocateScope always_allocate(CcTest::i_isolate()); AlwaysAllocateScope always_allocate(CcTest::i_isolate());
for (int i = 0; i < transitions_count; i++) { for (int i = 0; i < transitions_count; i++) {
EmbeddedVector<char, 64> buffer; 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(buffer.start());
} }
CompileRun("var root = new Object;"); CompileRun("var root = new F;");
} }
Handle<JSObject> root = Handle<JSObject> root =
...@@ -2669,7 +2670,7 @@ static void AddTransitions(int transitions_count) { ...@@ -2669,7 +2670,7 @@ static void AddTransitions(int transitions_count) {
AlwaysAllocateScope always_allocate(CcTest::i_isolate()); AlwaysAllocateScope always_allocate(CcTest::i_isolate());
for (int i = 0; i < transitions_count; i++) { for (int i = 0; i < transitions_count; i++) {
EmbeddedVector<char, 64> buffer; 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(buffer.start());
} }
} }
...@@ -2702,8 +2703,9 @@ TEST(TransitionArrayShrinksDuringAllocToZero) { ...@@ -2702,8 +2703,9 @@ TEST(TransitionArrayShrinksDuringAllocToZero) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10; static const int transitions_count = 10;
CompileRun("function F() { }");
AddTransitions(transitions_count); AddTransitions(transitions_count);
CompileRun("var root = new Object;"); CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root"); Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking. // Count number of live transitions before marking.
...@@ -2711,8 +2713,8 @@ TEST(TransitionArrayShrinksDuringAllocToZero) { ...@@ -2711,8 +2713,8 @@ TEST(TransitionArrayShrinksDuringAllocToZero) {
CHECK_EQ(transitions_count, transitions_before); CHECK_EQ(transitions_count, transitions_before);
// Get rid of o // Get rid of o
CompileRun("o = new Object;" CompileRun("o = new F;"
"root = new Object"); "root = new F");
root = GetByName("root"); root = GetByName("root");
AddPropertyTo(2, root, "funny"); AddPropertyTo(2, root, "funny");
...@@ -2730,8 +2732,9 @@ TEST(TransitionArrayShrinksDuringAllocToOne) { ...@@ -2730,8 +2732,9 @@ TEST(TransitionArrayShrinksDuringAllocToOne) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10; static const int transitions_count = 10;
CompileRun("function F() {}");
AddTransitions(transitions_count); AddTransitions(transitions_count);
CompileRun("var root = new Object;"); CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root"); Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking. // Count number of live transitions before marking.
...@@ -2755,8 +2758,9 @@ TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) { ...@@ -2755,8 +2758,9 @@ TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 10; static const int transitions_count = 10;
CompileRun("function F() {}");
AddTransitions(transitions_count); AddTransitions(transitions_count);
CompileRun("var root = new Object;"); CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root"); Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking. // Count number of live transitions before marking.
...@@ -2780,16 +2784,17 @@ TEST(TransitionArraySimpleToFull) { ...@@ -2780,16 +2784,17 @@ TEST(TransitionArraySimpleToFull) {
CcTest::InitializeVM(); CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate()); v8::HandleScope scope(CcTest::isolate());
static const int transitions_count = 1; static const int transitions_count = 1;
CompileRun("function F() {}");
AddTransitions(transitions_count); AddTransitions(transitions_count);
CompileRun("var root = new Object;"); CompileRun("var root = new F;");
Handle<JSObject> root = GetByName("root"); Handle<JSObject> root = GetByName("root");
// Count number of live transitions before marking. // Count number of live transitions before marking.
int transitions_before = CountMapTransitions(root->map()); int transitions_before = CountMapTransitions(root->map());
CHECK_EQ(transitions_count, transitions_before); CHECK_EQ(transitions_count, transitions_before);
CompileRun("o = new Object;" CompileRun("o = new F;"
"root = new Object"); "root = new F");
root = GetByName("root"); root = GetByName("root");
ASSERT(root->map()->transitions()->IsSimpleTransition()); ASSERT(root->map()->transitions()->IsSimpleTransition());
AddPropertyTo(2, root, "happy"); AddPropertyTo(2, root, "happy");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment