add transitions for global properties in ics

R=verwaest@chromium.org

BUG=

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

Cr-Commit-Position: refs/heads/master@{#26569}
This commit is contained in:
dcarney 2015-02-11 01:15:19 -08:00 committed by Commit bot
parent 85ed0097d5
commit 307d2bdd81
6 changed files with 67 additions and 36 deletions

View File

@ -1676,6 +1676,19 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
}
static Handle<Code> PropertyCellStoreHandler(
Isolate* isolate, Handle<JSObject> receiver, Handle<GlobalObject> holder,
Handle<Name> name, Handle<PropertyCell> cell, Handle<Object> value) {
auto union_type = PropertyCell::UpdatedType(cell, value);
StoreGlobalStub stub(isolate, union_type->IsConstant(),
receiver->IsJSGlobalProxy());
auto code = stub.GetCodeCopyFromTemplate(holder, cell);
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
HeapObject::UpdateMapCodeCache(receiver, name, code);
return code;
}
Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
Handle<Object> value,
CacheHolderFlag cache_holder) {
@ -1688,6 +1701,13 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
switch (lookup->state()) {
case LookupIterator::TRANSITION: {
auto store_target = lookup->GetStoreTarget();
if (store_target->IsGlobalObject()) {
auto cell = lookup->GetTransitionPropertyCell();
return PropertyCellStoreHandler(
isolate(), store_target, Handle<GlobalObject>::cast(store_target),
lookup->name(), cell, value);
}
Handle<Map> transition = lookup->transition_map();
// Currently not handled by CompileStoreTransition.
if (!holder->HasFastProperties()) {
@ -1754,17 +1774,12 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
case LookupIterator::DATA: {
if (lookup->is_dictionary_holder()) {
if (holder->IsGlobalObject()) {
Handle<PropertyCell> cell = lookup->GetPropertyCell();
Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
DCHECK(holder.is_identical_to(receiver) ||
receiver->map()->prototype() == *holder);
StoreGlobalStub stub(isolate(), union_type->IsConstant(),
receiver->IsJSGlobalProxy());
Handle<Code> code = stub.GetCodeCopyFromTemplate(
Handle<GlobalObject>::cast(holder), cell);
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
HeapObject::UpdateMapCodeCache(receiver, lookup->name(), code);
return code;
auto cell = lookup->GetPropertyCell();
return PropertyCellStoreHandler(isolate(), receiver,
Handle<GlobalObject>::cast(holder),
lookup->name(), cell, value);
}
DCHECK(holder.is_identical_to(receiver));
return isolate()->builtins()->StoreIC_Normal();

View File

@ -131,9 +131,22 @@ void LookupIterator::PrepareTransitionToDataProperty(
return;
}
transition_map_ = Map::TransitionToDataProperty(
auto transition = Map::TransitionToDataProperty(
handle(receiver->map(), isolate_), name_, value, attributes, store_mode);
state_ = TRANSITION;
transition_ = transition;
if (receiver->IsGlobalObject()) {
// Install a property cell.
InternalizeName();
auto cell = GlobalObject::EnsurePropertyCell(
Handle<GlobalObject>::cast(receiver), name());
DCHECK(cell->value()->IsTheHole());
transition_ = cell;
} else if (transition->GetBackPointer()->IsMap()) {
property_details_ = transition->GetLastDescriptorDetails();
has_property_ = true;
}
}
@ -141,8 +154,9 @@ void LookupIterator::ApplyTransitionToDataProperty() {
DCHECK_EQ(TRANSITION, state_);
Handle<JSObject> receiver = GetStoreTarget();
if (receiver->IsGlobalObject()) return;
holder_ = receiver;
holder_map_ = transition_map_;
holder_map_ = transition_map();
JSObject::MigrateToMap(receiver, holder_map_);
ReloadPropertyInformation();
}

View File

@ -88,7 +88,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
bool is_dictionary_holder() const { return holder_map_->is_dictionary_map(); }
Handle<Map> transition_map() const {
DCHECK_EQ(TRANSITION, state_);
return transition_map_;
return Handle<Map>::cast(transition_);
}
template <class T>
Handle<T> GetHolder() const {
@ -107,13 +107,9 @@ class LookupIterator FINAL BASE_EMBEDDED {
PropertyAttributes attributes,
Object::StoreFromKeyed store_mode);
bool IsCacheableTransition() {
bool cacheable =
state_ == TRANSITION && transition_map()->GetBackPointer()->IsMap();
if (cacheable) {
property_details_ = transition_map_->GetLastDescriptorDetails();
has_property_ = true;
}
return cacheable;
if (state_ != TRANSITION) return false;
return transition_->IsPropertyCell() ||
transition_map()->GetBackPointer()->IsMap();
}
void ApplyTransitionToDataProperty();
void ReconfigureDataProperty(Handle<Object> value,
@ -135,6 +131,10 @@ class LookupIterator FINAL BASE_EMBEDDED {
int GetAccessorIndex() const;
int GetConstantIndex() const;
Handle<PropertyCell> GetPropertyCell() const;
Handle<PropertyCell> GetTransitionPropertyCell() const {
DCHECK_EQ(TRANSITION, state_);
return Handle<PropertyCell>::cast(transition_);
}
Handle<Object> GetAccessors() const;
Handle<Object> GetDataValue() const;
// Usually returns the value that was passed in, but may perform
@ -194,7 +194,7 @@ class LookupIterator FINAL BASE_EMBEDDED {
Isolate* isolate_;
Handle<Name> name_;
Handle<Map> holder_map_;
Handle<Map> transition_map_;
Handle<Object> transition_;
Handle<Object> receiver_;
Handle<JSReceiver> holder_;

View File

@ -1752,9 +1752,7 @@ void JSObject::AddSlowProperty(Handle<JSObject> object,
dict->SetEntry(entry, name, cell, details);
return;
}
Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(value);
PropertyCell::SetValueInferType(cell, value);
value = cell;
value = isolate->factory()->NewPropertyCell(value);
}
PropertyDetails details(attributes, DATA, 0);
Handle<NameDictionary> result =
@ -3056,6 +3054,7 @@ MaybeHandle<Object> Object::AddDataProperty(LookupIterator* it,
if (receiver->map()->is_dictionary_map()) {
// TODO(verwaest): Probably should ensure this is done beforehand.
it->InternalizeName();
// TODO(dcarney): just populate TransitionPropertyCell here?
JSObject::AddSlowProperty(receiver, it->name(), value, attributes);
} else {
// Write the property value.
@ -15113,15 +15112,13 @@ void GlobalObject::InvalidatePropertyCell(Handle<GlobalObject> global,
}
Handle<PropertyCell> JSGlobalObject::EnsurePropertyCell(
Handle<JSGlobalObject> global,
Handle<Name> name) {
Handle<PropertyCell> GlobalObject::EnsurePropertyCell(
Handle<GlobalObject> global, Handle<Name> name) {
DCHECK(!global->HasFastProperties());
int entry = global->property_dictionary()->FindEntry(name);
if (entry == NameDictionary::kNotFound) {
Isolate* isolate = global->GetIsolate();
Handle<PropertyCell> cell = isolate->factory()->NewPropertyCell(
isolate->factory()->the_hole_value());
Handle<PropertyCell> cell = isolate->factory()->NewPropertyCellWithHole();
PropertyDetails details(NONE, DATA, 0);
details = details.AsDeleted();
Handle<NameDictionary> dictionary = NameDictionary::Add(
@ -16920,10 +16917,12 @@ Handle<Object> PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
const int kMaxLengthForInternalization = 200;
if ((cell->type()->Is(HeapType::None()) ||
cell->type()->Is(HeapType::Undefined())) &&
value->IsString() &&
Handle<String>::cast(value)->length() <= kMaxLengthForInternalization) {
value = cell->GetIsolate()->factory()->InternalizeString(
Handle<String>::cast(value));
value->IsString()) {
auto string = Handle<String>::cast(value);
if (string->length() <= kMaxLengthForInternalization &&
!string->map()->is_undetectable()) {
value = cell->GetIsolate()->factory()->InternalizeString(string);
}
}
cell->set_value(*value);
if (!HeapType::Any()->Is(cell->type())) {

View File

@ -7643,6 +7643,9 @@ class GlobalObject: public JSObject {
static void InvalidatePropertyCell(Handle<GlobalObject> object,
Handle<Name> name);
// Ensure that the global object has a cell for the given property name.
static Handle<PropertyCell> EnsurePropertyCell(Handle<GlobalObject> global,
Handle<Name> name);
// Layout description.
static const int kBuiltinsOffset = JSObject::kHeaderSize;
@ -7660,10 +7663,6 @@ class JSGlobalObject: public GlobalObject {
public:
DECLARE_CAST(JSGlobalObject)
// Ensure that the global object has a cell for the given property name.
static Handle<PropertyCell> EnsurePropertyCell(Handle<JSGlobalObject> global,
Handle<Name> name);
inline bool IsDetached();
// Dispatched behavior.

View File

@ -407,6 +407,10 @@ TEST(HeapSnapshotSlicedString) {
"parent_string = \"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789."
"123456789.123456789.123456789.123456789.123456789.\";"
"child_string = parent_string.slice(100);");
const v8::HeapSnapshot* snapshot =