Directly store the transition target on LookupResult in TransitionResult.
BUG=chromium:343964 LOG=N R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/170343003 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@19440 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
45452cc3db
commit
60c08a8bf2
@ -4376,14 +4376,14 @@ HObjectAccess HObjectAccess::ForBackingStoreOffset(int offset,
|
||||
HObjectAccess HObjectAccess::ForField(Handle<Map> map,
|
||||
LookupResult* lookup,
|
||||
Handle<String> name) {
|
||||
ASSERT(lookup->IsField() || lookup->IsTransitionToField(*map));
|
||||
ASSERT(lookup->IsField() || lookup->IsTransitionToField());
|
||||
int index;
|
||||
Representation representation;
|
||||
if (lookup->IsField()) {
|
||||
index = lookup->GetLocalFieldIndexFromMap(*map);
|
||||
representation = lookup->representation();
|
||||
} else {
|
||||
Map* transition = lookup->GetTransitionMapFromMap(*map);
|
||||
Map* transition = lookup->GetTransitionTarget();
|
||||
int descriptor = transition->LastAdded();
|
||||
index = transition->instance_descriptors()->GetFieldIndex(descriptor) -
|
||||
map->inobject_properties();
|
||||
|
@ -5555,8 +5555,7 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
|
||||
if (lookup_.IsPropertyCallbacks()) return true;
|
||||
Handle<Map> map = this->map();
|
||||
map->LookupTransition(NULL, *name_, &lookup_);
|
||||
if (lookup_.IsTransitionToField(*map) && map->unused_property_fields() > 0) {
|
||||
transition_ = handle(lookup_.GetTransitionMapFromMap(*map));
|
||||
if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -2408,7 +2408,7 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
Handle<JSObject> holder() { return holder_; }
|
||||
Handle<JSFunction> accessor() { return accessor_; }
|
||||
Handle<Object> constant() { return constant_; }
|
||||
Handle<Object> transition() { return transition_; }
|
||||
Handle<Map> transition() { return handle(lookup_.GetTransitionTarget()); }
|
||||
HObjectAccess access() { return access_; }
|
||||
|
||||
private:
|
||||
@ -2435,7 +2435,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
Handle<JSFunction> accessor_;
|
||||
Handle<JSObject> api_holder_;
|
||||
Handle<Object> constant_;
|
||||
Handle<Map> transition_;
|
||||
HObjectAccess access_;
|
||||
};
|
||||
|
||||
|
13
src/ic.cc
13
src/ic.cc
@ -1134,8 +1134,7 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
||||
// receiver when trying to fetch extra information from the transition.
|
||||
receiver->map()->LookupTransition(*holder, *name, lookup);
|
||||
if (!lookup->IsTransition()) return false;
|
||||
PropertyDetails target_details =
|
||||
lookup->GetTransitionDetails(receiver->map());
|
||||
PropertyDetails target_details = lookup->GetTransitionDetails();
|
||||
if (target_details.IsReadOnly()) return false;
|
||||
|
||||
// If the value that's being stored does not fit in the field that the
|
||||
@ -1146,7 +1145,7 @@ static bool LookupForWrite(Handle<JSObject> receiver,
|
||||
// transition target.
|
||||
ASSERT(!receiver->map()->is_deprecated());
|
||||
if (!value->FitsRepresentation(target_details.representation())) {
|
||||
Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
|
||||
Handle<Map> target(lookup->GetTransitionTarget());
|
||||
Map::GeneralizeRepresentation(
|
||||
target, target->LastAdded(),
|
||||
value->OptimalRepresentation(), FORCE_FIELD);
|
||||
@ -1319,12 +1318,8 @@ Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
|
||||
case TRANSITION: {
|
||||
// Explicitly pass in the receiver map since LookupForWrite may have
|
||||
// stored something else than the receiver in the holder.
|
||||
Handle<Map> transition(
|
||||
lookup->GetTransitionTarget(receiver->map()), isolate());
|
||||
int descriptor = transition->LastAdded();
|
||||
|
||||
DescriptorArray* target_descriptors = transition->instance_descriptors();
|
||||
PropertyDetails details = target_descriptors->GetDetails(descriptor);
|
||||
Handle<Map> transition(lookup->GetTransitionTarget());
|
||||
PropertyDetails details = transition->GetLastDescriptorDetails();
|
||||
|
||||
if (details.type() == CALLBACKS || details.attributes() != NONE) break;
|
||||
|
||||
|
@ -2497,6 +2497,11 @@ int DescriptorArray::SearchWithCache(Name* name, Map* map) {
|
||||
}
|
||||
|
||||
|
||||
PropertyDetails Map::GetLastDescriptorDetails() {
|
||||
return instance_descriptors()->GetDetails(LastAdded());
|
||||
}
|
||||
|
||||
|
||||
void Map::LookupDescriptor(JSObject* holder,
|
||||
Name* name,
|
||||
LookupResult* result) {
|
||||
@ -2514,7 +2519,8 @@ void Map::LookupTransition(JSObject* holder,
|
||||
TransitionArray* transition_array = transitions();
|
||||
int number = transition_array->Search(name);
|
||||
if (number != TransitionArray::kNotFound) {
|
||||
return result->TransitionResult(holder, number);
|
||||
return result->TransitionResult(
|
||||
holder, transition_array->GetTarget(number));
|
||||
}
|
||||
}
|
||||
result->NotFound();
|
||||
|
@ -6088,6 +6088,8 @@ class Map: public HeapObject {
|
||||
Name* name,
|
||||
LookupResult* result);
|
||||
|
||||
inline PropertyDetails GetLastDescriptorDetails();
|
||||
|
||||
// The size of transition arrays are limited so they do not end up in large
|
||||
// object space. Otherwise ClearNonLiveTransitions would leak memory while
|
||||
// applying in-place right trimming.
|
||||
|
@ -35,6 +35,7 @@ void LookupResult::Iterate(ObjectVisitor* visitor) {
|
||||
LookupResult* current = this; // Could be NULL.
|
||||
while (current != NULL) {
|
||||
visitor->VisitPointer(BitCast<Object**>(¤t->holder_));
|
||||
visitor->VisitPointer(BitCast<Object**>(¤t->transition_));
|
||||
current = current->next_;
|
||||
}
|
||||
}
|
||||
@ -82,13 +83,13 @@ void LookupResult::Print(FILE* out) {
|
||||
case FIELD:
|
||||
PrintF(out, " -type = map transition\n");
|
||||
PrintF(out, " -map:\n");
|
||||
GetTransitionMap()->Print(out);
|
||||
GetTransitionTarget()->Print(out);
|
||||
PrintF(out, "\n");
|
||||
return;
|
||||
case CONSTANT:
|
||||
PrintF(out, " -type = constant property transition\n");
|
||||
PrintF(out, " -map:\n");
|
||||
GetTransitionMap()->Print(out);
|
||||
GetTransitionTarget()->Print(out);
|
||||
PrintF(out, "\n");
|
||||
return;
|
||||
case CALLBACKS:
|
||||
|
@ -184,6 +184,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
next_(isolate->top_lookup_result()),
|
||||
lookup_type_(NOT_FOUND),
|
||||
holder_(NULL),
|
||||
transition_(NULL),
|
||||
cacheable_(true),
|
||||
details_(NONE, NONEXISTENT, Representation::None()) {
|
||||
isolate->set_top_lookup_result(this);
|
||||
@ -199,6 +200,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
void DescriptorResult(JSObject* holder, PropertyDetails details, int number) {
|
||||
lookup_type_ = DESCRIPTOR_TYPE;
|
||||
holder_ = holder;
|
||||
transition_ = NULL;
|
||||
details_ = details;
|
||||
number_ = number;
|
||||
}
|
||||
@ -209,16 +211,18 @@ class LookupResult BASE_EMBEDDED {
|
||||
return value->FitsRepresentation(details_.representation());
|
||||
}
|
||||
|
||||
void TransitionResult(JSObject* holder, int number) {
|
||||
void TransitionResult(JSObject* holder, Map* target) {
|
||||
lookup_type_ = TRANSITION_TYPE;
|
||||
details_ = PropertyDetails(NONE, TRANSITION, Representation::None());
|
||||
holder_ = holder;
|
||||
number_ = number;
|
||||
transition_ = target;
|
||||
number_ = 0xAAAA;
|
||||
}
|
||||
|
||||
void DictionaryResult(JSObject* holder, int entry) {
|
||||
lookup_type_ = DICTIONARY_TYPE;
|
||||
holder_ = holder;
|
||||
transition_ = NULL;
|
||||
details_ = holder->property_dictionary()->DetailsAt(entry);
|
||||
number_ = entry;
|
||||
}
|
||||
@ -226,6 +230,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
void HandlerResult(JSProxy* proxy) {
|
||||
lookup_type_ = HANDLER_TYPE;
|
||||
holder_ = proxy;
|
||||
transition_ = NULL;
|
||||
details_ = PropertyDetails(NONE, HANDLER, Representation::Tagged());
|
||||
cacheable_ = false;
|
||||
}
|
||||
@ -233,6 +238,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
void InterceptorResult(JSObject* holder) {
|
||||
lookup_type_ = INTERCEPTOR_TYPE;
|
||||
holder_ = holder;
|
||||
transition_ = NULL;
|
||||
details_ = PropertyDetails(NONE, INTERCEPTOR, Representation::Tagged());
|
||||
}
|
||||
|
||||
@ -240,6 +246,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
lookup_type_ = NOT_FOUND;
|
||||
details_ = PropertyDetails(NONE, NONEXISTENT, Representation::None());
|
||||
holder_ = NULL;
|
||||
transition_ = NULL;
|
||||
}
|
||||
|
||||
JSObject* holder() const {
|
||||
@ -248,7 +255,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
}
|
||||
|
||||
JSProxy* proxy() const {
|
||||
ASSERT(IsFound());
|
||||
ASSERT(IsHandler());
|
||||
return JSProxy::cast(holder_);
|
||||
}
|
||||
|
||||
@ -373,47 +380,21 @@ class LookupResult BASE_EMBEDDED {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Map* GetTransitionTarget(Map* map) const {
|
||||
ASSERT(IsTransition());
|
||||
TransitionArray* transitions = map->transitions();
|
||||
return transitions->GetTarget(number_);
|
||||
}
|
||||
|
||||
Map* GetTransitionTarget() const {
|
||||
return GetTransitionTarget(holder()->map());
|
||||
}
|
||||
|
||||
PropertyDetails GetTransitionDetails(Map* map) const {
|
||||
ASSERT(IsTransition());
|
||||
TransitionArray* transitions = map->transitions();
|
||||
return transitions->GetTargetDetails(number_);
|
||||
return transition_;
|
||||
}
|
||||
|
||||
PropertyDetails GetTransitionDetails() const {
|
||||
return GetTransitionDetails(holder()->map());
|
||||
}
|
||||
|
||||
bool IsTransitionToField(Map* map) const {
|
||||
return IsTransition() && GetTransitionDetails(map).type() == FIELD;
|
||||
}
|
||||
|
||||
bool IsTransitionToConstant(Map* map) const {
|
||||
return IsTransition() && GetTransitionDetails(map).type() == CONSTANT;
|
||||
}
|
||||
|
||||
Map* GetTransitionMap() const {
|
||||
ASSERT(IsTransition());
|
||||
return Map::cast(GetValue());
|
||||
return transition_->GetLastDescriptorDetails();
|
||||
}
|
||||
|
||||
Map* GetTransitionMapFromMap(Map* map) const {
|
||||
ASSERT(IsTransition());
|
||||
return map->transitions()->GetTarget(number_);
|
||||
bool IsTransitionToField() const {
|
||||
return IsTransition() && GetTransitionDetails().type() == FIELD;
|
||||
}
|
||||
|
||||
int GetTransitionIndex() const {
|
||||
ASSERT(IsTransition());
|
||||
return number_;
|
||||
bool IsTransitionToConstant() const {
|
||||
return IsTransition() && GetTransitionDetails().type() == CONSTANT;
|
||||
}
|
||||
|
||||
int GetDescriptorIndex() const {
|
||||
@ -501,6 +482,7 @@ class LookupResult BASE_EMBEDDED {
|
||||
} lookup_type_;
|
||||
|
||||
JSReceiver* holder_;
|
||||
Map* transition_;
|
||||
int number_;
|
||||
bool cacheable_;
|
||||
PropertyDetails details_;
|
||||
|
@ -160,9 +160,7 @@ void TransitionArray::SetTarget(int transition_number, Map* value) {
|
||||
|
||||
PropertyDetails TransitionArray::GetTargetDetails(int transition_number) {
|
||||
Map* map = GetTarget(transition_number);
|
||||
DescriptorArray* descriptors = map->instance_descriptors();
|
||||
int descriptor = map->LastAdded();
|
||||
return descriptors->GetDetails(descriptor);
|
||||
return map->GetLastDescriptorDetails();
|
||||
}
|
||||
|
||||
|
||||
|
14
test/mjsunit/regress/regress-lookup-transition.js
Normal file
14
test/mjsunit/regress/regress-lookup-transition.js
Normal file
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-proxies --expose-gc
|
||||
|
||||
var proxy = Proxy.create({ getPropertyDescriptor:function(key) {
|
||||
gc();
|
||||
}});
|
||||
|
||||
function f() { this.x = 23; }
|
||||
f.prototype = proxy;
|
||||
new f();
|
||||
new f();
|
Loading…
Reference in New Issue
Block a user