Revert part of 11727 as it sometimes tanked V8 benchmark (raytrace) performance
for reasons that are not obvious. Now we make objects into fast-case objects when they are made prototypes for other objects, but we do not mark objects that are already fast case with a bit that helps keep them in fast case. Review URL: https://chromiumcodereview.appspot.com/10556004 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@11831 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
3a739a1cb6
commit
045b2fbf20
@ -1616,8 +1616,7 @@ bool JSObject::TooManyFastProperties(int properties,
|
|||||||
int inobject = map()->inobject_properties();
|
int inobject = map()->inobject_properties();
|
||||||
|
|
||||||
int limit;
|
int limit;
|
||||||
if (store_mode == CERTAINLY_NOT_STORE_FROM_KEYED ||
|
if (store_mode == CERTAINLY_NOT_STORE_FROM_KEYED) {
|
||||||
map()->used_for_prototype()) {
|
|
||||||
limit = Max(inobject, kMaxFastProperties);
|
limit = Max(inobject, kMaxFastProperties);
|
||||||
} else {
|
} else {
|
||||||
limit = Max(inobject, kFastPropertiesSoftLimit);
|
limit = Max(inobject, kFastPropertiesSoftLimit);
|
||||||
@ -2982,20 +2981,6 @@ bool Map::is_shared() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Map::set_used_for_prototype(bool value) {
|
|
||||||
if (value) {
|
|
||||||
set_bit_field3(bit_field3() | (1 << kUsedForPrototype));
|
|
||||||
} else {
|
|
||||||
set_bit_field3(bit_field3() & ~(1 << kUsedForPrototype));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Map::used_for_prototype() {
|
|
||||||
return ((1 << kUsedForPrototype) & bit_field3()) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
JSFunction* Map::unchecked_constructor() {
|
JSFunction* Map::unchecked_constructor() {
|
||||||
return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
|
return reinterpret_cast<JSFunction*>(READ_FIELD(this, kConstructorOffset));
|
||||||
}
|
}
|
||||||
|
@ -7563,34 +7563,11 @@ MaybeObject* JSObject::OptimizeAsPrototype() {
|
|||||||
// Make sure prototypes are fast objects and their maps have the bit set
|
// Make sure prototypes are fast objects and their maps have the bit set
|
||||||
// so they remain fast.
|
// so they remain fast.
|
||||||
Map* proto_map = map();
|
Map* proto_map = map();
|
||||||
if (!proto_map->used_for_prototype()) {
|
if (!HasFastProperties()) {
|
||||||
if (!HasFastProperties()) {
|
MaybeObject* new_proto = TransformToFastProperties(0);
|
||||||
MaybeObject* new_proto = TransformToFastProperties(0);
|
if (new_proto->IsFailure()) return new_proto;
|
||||||
if (new_proto->IsFailure()) return new_proto;
|
ASSERT(new_proto == this);
|
||||||
ASSERT(new_proto == this);
|
proto_map = map();
|
||||||
proto_map = map();
|
|
||||||
if (!proto_map->is_shared()) {
|
|
||||||
proto_map->set_used_for_prototype(true);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Heap* heap = GetHeap();
|
|
||||||
// We use the hole value as a singleton key in the prototype transition
|
|
||||||
// map so that we don't multiply the number of maps unnecessarily.
|
|
||||||
Map* new_map =
|
|
||||||
proto_map->GetPrototypeTransition(heap->the_hole_value());
|
|
||||||
if (new_map == NULL) {
|
|
||||||
MaybeObject* maybe_new_map =
|
|
||||||
proto_map->CopyDropTransitions(DescriptorArray::MAY_BE_SHARED);
|
|
||||||
if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
|
|
||||||
new_map->set_used_for_prototype(true);
|
|
||||||
MaybeObject* ok =
|
|
||||||
proto_map->PutPrototypeTransition(heap->the_hole_value(),
|
|
||||||
new_map);
|
|
||||||
if (ok->IsFailure()) return ok;
|
|
||||||
}
|
|
||||||
ASSERT(!proto_map->is_shared() && !new_map->is_shared());
|
|
||||||
set_map(new_map);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -7600,8 +7577,8 @@ MaybeObject* JSFunction::SetInstancePrototype(Object* value) {
|
|||||||
ASSERT(value->IsJSReceiver());
|
ASSERT(value->IsJSReceiver());
|
||||||
Heap* heap = GetHeap();
|
Heap* heap = GetHeap();
|
||||||
|
|
||||||
// First some logic for the map of the prototype to make sure the
|
// First some logic for the map of the prototype to make sure it is in fast
|
||||||
// used_for_prototype flag is set.
|
// mode.
|
||||||
if (value->IsJSObject()) {
|
if (value->IsJSObject()) {
|
||||||
MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
|
MaybeObject* ok = JSObject::cast(value)->OptimizeAsPrototype();
|
||||||
if (ok->IsFailure()) return ok;
|
if (ok->IsFailure()) return ok;
|
||||||
|
@ -4749,14 +4749,6 @@ class Map: public HeapObject {
|
|||||||
inline void set_is_shared(bool value);
|
inline void set_is_shared(bool value);
|
||||||
inline bool is_shared();
|
inline bool is_shared();
|
||||||
|
|
||||||
// Tells whether the map is used for an object that is a prototype for another
|
|
||||||
// object or is the prototype on a function. Such maps are made faster by
|
|
||||||
// tweaking the heuristics that distinguish between regular object-oriented
|
|
||||||
// objects and the objects that are being used as hash maps. This flag is
|
|
||||||
// for optimization, not correctness.
|
|
||||||
inline void set_used_for_prototype(bool value);
|
|
||||||
inline bool used_for_prototype();
|
|
||||||
|
|
||||||
// Tells whether the instance needs security checks when accessing its
|
// Tells whether the instance needs security checks when accessing its
|
||||||
// properties.
|
// properties.
|
||||||
inline void set_is_access_check_needed(bool access_check_needed);
|
inline void set_is_access_check_needed(bool access_check_needed);
|
||||||
@ -4944,9 +4936,7 @@ class Map: public HeapObject {
|
|||||||
// the original map. That way we can transition to the same map if the same
|
// the original map. That way we can transition to the same map if the same
|
||||||
// prototype is set, rather than creating a new map every time. The
|
// prototype is set, rather than creating a new map every time. The
|
||||||
// transitions are in the form of a map where the keys are prototype objects
|
// transitions are in the form of a map where the keys are prototype objects
|
||||||
// and the values are the maps the are transitioned to. The special key
|
// and the values are the maps the are transitioned to.
|
||||||
// the_hole denotes the map we should transition to when the
|
|
||||||
// used_for_prototype flag is set.
|
|
||||||
static const int kMaxCachedPrototypeTransitions = 256;
|
static const int kMaxCachedPrototypeTransitions = 256;
|
||||||
|
|
||||||
Map* GetPrototypeTransition(Object* prototype);
|
Map* GetPrototypeTransition(Object* prototype);
|
||||||
@ -5042,7 +5032,6 @@ class Map: public HeapObject {
|
|||||||
// Bit positions for bit field 3
|
// Bit positions for bit field 3
|
||||||
static const int kIsShared = 0;
|
static const int kIsShared = 0;
|
||||||
static const int kFunctionWithPrototype = 1;
|
static const int kFunctionWithPrototype = 1;
|
||||||
static const int kUsedForPrototype = 2;
|
|
||||||
|
|
||||||
typedef FixedBodyDescriptor<kPointerFieldsBeginOffset,
|
typedef FixedBodyDescriptor<kPointerFieldsBeginOffset,
|
||||||
kPointerFieldsEndOffset,
|
kPointerFieldsEndOffset,
|
||||||
|
@ -1579,13 +1579,10 @@ TEST(PrototypeTransitionClearing) {
|
|||||||
*v8::Handle<v8::Object>::Cast(
|
*v8::Handle<v8::Object>::Cast(
|
||||||
v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
|
v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
|
||||||
|
|
||||||
// Verify that only dead prototype transitions are cleared. There is an
|
// Verify that only dead prototype transitions are cleared.
|
||||||
// extra, 11th, prototype transition on the Object map, which is the
|
CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
|
||||||
// transition to a map with the used_for_prototype flag set (the key is
|
|
||||||
// the_hole).
|
|
||||||
CHECK_EQ(11, baseObject->map()->NumberOfProtoTransitions());
|
|
||||||
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
|
HEAP->CollectAllGarbage(Heap::kNoGCFlags);
|
||||||
const int transitions = 11 - 3;
|
const int transitions = 10 - 3;
|
||||||
CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
|
CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
|
||||||
|
|
||||||
// Verify that prototype transitions array was compacted.
|
// Verify that prototype transitions array was compacted.
|
||||||
|
@ -71,8 +71,8 @@ function test(use_new, add_first, set__proto__, same_map_as) {
|
|||||||
// Still fast
|
// Still fast
|
||||||
assertTrue(%HasFastProperties(proto));
|
assertTrue(%HasFastProperties(proto));
|
||||||
AddProps(proto);
|
AddProps(proto);
|
||||||
// Setting the bit means it is still fast with all these properties.
|
// After we add all those properties it went slow mode again :-(
|
||||||
assertTrue(%HasFastProperties(proto));
|
assertFalse(%HasFastProperties(proto));
|
||||||
}
|
}
|
||||||
if (same_map_as && !add_first) {
|
if (same_map_as && !add_first) {
|
||||||
assertTrue(%HaveSameMap(same_map_as, proto));
|
assertTrue(%HaveSameMap(same_map_as, proto));
|
||||||
|
Loading…
Reference in New Issue
Block a user