Avoid one repeated property lookup when computing load ICs.

R=verwaest@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22802 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent f66ddb18
......@@ -1221,7 +1221,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1231,7 +1231,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
__ ldr(result, FieldMemOperand(result, Cell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
__ cmp(result, ip);
__ b(eq, &miss);
......
......@@ -1195,7 +1195,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1205,7 +1205,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
__ Ldr(result, FieldMemOperand(result, Cell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
}
......
......@@ -1245,7 +1245,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1259,7 +1259,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
}
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ cmp(result, factory()->the_hole_value());
__ j(equal, &miss);
} else if (FLAG_debug_code) {
......
......@@ -190,48 +190,32 @@ Code* IC::GetOriginalCode() const {
}
static bool HasInterceptorGetter(JSObject* object) {
return !object->GetNamedInterceptor()->getter()->IsUndefined();
}
static bool HasInterceptorSetter(JSObject* object) {
return !object->GetNamedInterceptor()->setter()->IsUndefined();
}
static void LookupForRead(Handle<Object> object,
Handle<String> name,
LookupResult* lookup) {
// Skip all the objects with named interceptors, but
// without actual getter.
while (true) {
object->Lookup(name, lookup);
// Besides normal conditions (property not found or it's not
// an interceptor), bail out if lookup is not cacheable: we won't
// be able to IC it anyway and regular lookup should work fine.
if (!lookup->IsInterceptor() || !lookup->IsCacheable()) {
return;
}
Handle<JSObject> holder(lookup->holder(), lookup->isolate());
if (HasInterceptorGetter(*holder)) {
return;
}
holder->LookupOwnRealNamedProperty(name, lookup);
if (lookup->IsFound()) {
ASSERT(!lookup->IsInterceptor());
return;
}
PrototypeIterator iter(lookup->isolate(), holder);
if (iter.IsAtEnd()) {
ASSERT(!lookup->IsFound());
return;
static void LookupForRead(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
UNREACHABLE();
case LookupIterator::JSPROXY:
return;
case LookupIterator::INTERCEPTOR: {
// If there is a getter, return; otherwise loop to perform the lookup.
Handle<JSObject> holder = it->GetHolder<JSObject>();
if (!holder->GetNamedInterceptor()->getter()->IsUndefined()) {
return;
}
break;
}
case LookupIterator::ACCESS_CHECK:
return;
case LookupIterator::PROPERTY:
if (it->HasProperty()) return; // Yay!
break;
}
object = PrototypeIterator::GetCurrent(iter);
}
}
......@@ -574,11 +558,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<String> name) {
bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
// Named lookup in the object.
LookupResult lookup(isolate());
LookupForRead(object, name, &lookup);
LookupIterator it(object, name);
LookupForRead(&it);
// If we did not find a property, check if we need to throw an exception.
if (!lookup.IsFound()) {
if (!it.IsFound()) {
if (IsUndeclaredGlobal(object)) {
return ReferenceError("not_defined", name);
}
......@@ -586,16 +570,14 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<String> name) {
}
// Update inline cache and stub cache.
if (use_ic) UpdateCaches(&lookup, object, name);
if (use_ic) UpdateCaches(&it, object, name);
// Get the property.
LookupIterator it(object, name);
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Object::GetProperty(&it), Object);
// If the property is not present, check if we need to throw an exception.
if ((lookup.IsInterceptor() || lookup.IsHandler()) &&
!it.IsFound() && IsUndeclaredGlobal(object)) {
if (!it.IsFound() && IsUndeclaredGlobal(object)) {
return ReferenceError("not_defined", name);
}
......@@ -828,8 +810,7 @@ Handle<Code> LoadIC::SimpleFieldLoad(FieldIndex index) {
}
void LoadIC::UpdateCaches(LookupResult* lookup,
Handle<Object> object,
void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
Handle<String> name) {
if (state() == UNINITIALIZED) {
// This is the first time we execute this inline cache.
......@@ -841,10 +822,10 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
}
Handle<Code> code;
if (!lookup->IsCacheable()) {
// Bail out if the result is not cacheable.
if (lookup->state() == LookupIterator::JSPROXY ||
lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub();
} else if (!lookup->IsProperty()) {
} else if (!lookup->IsFound()) {
if (kind() == Code::LOAD_IC) {
code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name,
receiver_type());
......@@ -869,10 +850,53 @@ void IC::UpdateMegamorphicCache(HeapType* type, Name* name, Code* code) {
}
Handle<Code> IC::ComputeHandler(LookupResult* lookup,
Handle<Object> object,
Handle<String> name,
Handle<Object> value) {
Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> object,
Handle<String> name, Handle<Object> value) {
bool receiver_is_holder =
object.is_identical_to(lookup->GetHolder<JSObject>());
CacheHolderFlag flag;
Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
*receiver_type(), receiver_is_holder, isolate(), &flag);
Handle<Code> code = PropertyHandlerCompiler::Find(
name, stub_holder_map, kind(), flag,
lookup->holder_map()->is_dictionary_map() ? Code::NORMAL : Code::FAST);
// Use the cached value if it exists, and if it is different from the
// handler that just missed.
if (!code.is_null()) {
if (!maybe_handler_.is_null() &&
!maybe_handler_.ToHandleChecked().is_identical_to(code)) {
return code;
}
if (maybe_handler_.is_null()) {
// maybe_handler_ is only populated for MONOMORPHIC and POLYMORPHIC ICs.
// In MEGAMORPHIC case, check if the handler in the megamorphic stub
// cache (which just missed) is different from the cached handler.
if (state() == MEGAMORPHIC && object->IsHeapObject()) {
Map* map = Handle<HeapObject>::cast(object)->map();
Code* megamorphic_cached_code =
isolate()->stub_cache()->Get(*name, map, code->flags());
if (megamorphic_cached_code != *code) return code;
} else {
return code;
}
}
}
code = CompileHandler(lookup, object, name, value, flag);
ASSERT(code->is_handler());
if (code->type() != Code::NORMAL) {
Map::UpdateCodeCache(stub_holder_map, name, code);
}
return code;
}
Handle<Code> IC::ComputeStoreHandler(LookupResult* lookup,
Handle<Object> object, Handle<String> name,
Handle<Object> value) {
bool receiver_is_holder = lookup->ReceiverIsHolder(object);
CacheHolderFlag flag;
Handle<Map> stub_holder_map = IC::GetHandlerCacheHolder(
......@@ -903,7 +927,7 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
}
}
code = CompileHandler(lookup, object, name, value, flag);
code = CompileStoreHandler(lookup, object, name, value, flag);
ASSERT(code->is_handler());
if (code->type() != Code::NORMAL) {
......@@ -914,8 +938,9 @@ Handle<Code> IC::ComputeHandler(LookupResult* lookup,
}
Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
Handle<String> name, Handle<Object> unused,
Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
Handle<Object> object, Handle<String> name,
Handle<Object> unused,
CacheHolderFlag cache_holder) {
if (object->IsString() &&
String::Equals(isolate()->factory()->length_string(), name)) {
......@@ -940,102 +965,107 @@ Handle<Code> LoadIC::CompileHandler(LookupResult* lookup, Handle<Object> object,
}
Handle<HeapType> type = receiver_type();
Handle<JSObject> holder(lookup->holder());
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
bool receiver_is_holder = object.is_identical_to(holder);
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
switch (lookup->type()) {
case FIELD: {
FieldIndex field = lookup->GetFieldIndex();
if (receiver_is_holder) {
return SimpleFieldLoad(field);
// -------------- Interceptors --------------
if (lookup->state() == LookupIterator::INTERCEPTOR) {
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
return compiler.CompileLoadInterceptor(name);
}
ASSERT(lookup->state() == LookupIterator::PROPERTY);
// -------------- Accessors --------------
if (lookup->property_kind() == LookupIterator::ACCESSOR) {
// Use simple field loads for some well-known callback properties.
if (receiver_is_holder) {
ASSERT(object->IsJSObject());
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
int object_offset;
if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name,
&object_offset)) {
FieldIndex index =
FieldIndex::ForInObjectOffset(object_offset, receiver->map());
return SimpleFieldLoad(index);
}
return compiler.CompileLoadField(name, field, lookup->representation());
}
case CONSTANT: {
Handle<Object> constant(lookup->GetConstant(), isolate());
return compiler.CompileLoadConstant(name, constant);
Handle<Object> accessors = lookup->GetAccessors();
if (accessors->IsExecutableAccessorInfo()) {
Handle<ExecutableAccessorInfo> info =
Handle<ExecutableAccessorInfo>::cast(accessors);
if (v8::ToCData<Address>(info->getter()) == 0) return slow_stub();
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
type)) {
return slow_stub();
}
if (holder->IsGlobalObject()) return slow_stub();
return compiler.CompileLoadCallback(name, info);
}
case NORMAL:
if (kind() != Code::LOAD_IC) break;
if (holder->IsGlobalObject()) {
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
Handle<Code> code =
compiler.CompileLoadGlobal(cell, name, lookup->IsDontDelete());
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
CacheHolderFlag flag;
Handle<Map> stub_holder_map =
GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
Map::UpdateCodeCache(stub_holder_map, name, code);
return code;
if (accessors->IsAccessorPair()) {
Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
isolate());
if (!getter->IsJSFunction()) return slow_stub();
if (holder->IsGlobalObject()) return slow_stub();
if (!holder->HasFastProperties()) return slow_stub();
Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
if (!object->IsJSObject() && !function->IsBuiltin() &&
function->shared()->strict_mode() == SLOPPY) {
// Calling sloppy non-builtins with a value as the receiver
// requires boxing.
return slow_stub();
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the object for the stub to be
// applicable.
if (!receiver_is_holder) break;
return isolate()->builtins()->LoadIC_Normal();
case CALLBACKS: {
// Use simple field loads for some well-known callback properties.
if (receiver_is_holder) {
ASSERT(object->IsJSObject());
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
int object_offset;
if (Accessors::IsJSObjectFieldAccessor<HeapType>(
type, name, &object_offset)) {
FieldIndex index = FieldIndex::ForInObjectOffset(
object_offset, receiver->map());
return SimpleFieldLoad(index);
}
CallOptimization call_optimization(function);
if (call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiver(object, holder)) {
return compiler.CompileLoadCallback(name, call_optimization);
}
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (callback->IsExecutableAccessorInfo()) {
Handle<ExecutableAccessorInfo> info =
Handle<ExecutableAccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->getter()) == 0) break;
if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(), info,
type)) {
break;
}
if (holder->IsGlobalObject()) break;
return compiler.CompileLoadCallback(name, info);
} else if (callback->IsAccessorPair()) {
Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
isolate());
if (!getter->IsJSFunction()) break;
if (holder->IsGlobalObject()) break;
if (!holder->HasFastProperties()) break;
Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
if (!object->IsJSObject() &&
!function->IsBuiltin() &&
function->shared()->strict_mode() == SLOPPY) {
// Calling sloppy non-builtins with a value as the receiver
// requires boxing.
break;
}
CallOptimization call_optimization(function);
if (call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiver(object, holder)) {
return compiler.CompileLoadCallback(name, call_optimization);
}
return compiler.CompileLoadViaGetter(name, function);
}
// TODO(dcarney): Handle correctly.
ASSERT(callback->IsDeclaredAccessorInfo());
break;
return compiler.CompileLoadViaGetter(name, function);
}
case INTERCEPTOR:
ASSERT(HasInterceptorGetter(*holder));
return compiler.CompileLoadInterceptor(name);
default:
break;
// TODO(dcarney): Handle correctly.
ASSERT(accessors->IsDeclaredAccessorInfo());
return slow_stub();
}
// -------------- Dictionary properties --------------
ASSERT(lookup->property_kind() == LookupIterator::DATA);
if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
if (kind() != Code::LOAD_IC) return slow_stub();
if (holder->IsGlobalObject()) {
Handle<PropertyCell> cell = lookup->GetPropertyCell();
Handle<Code> code =
compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable());
// TODO(verwaest): Move caching of these NORMAL stubs outside as well.
CacheHolderFlag flag;
Handle<Map> stub_holder_map =
GetHandlerCacheHolder(*type, receiver_is_holder, isolate(), &flag);
Map::UpdateCodeCache(stub_holder_map, name, code);
return code;
}
// There is only one shared stub for loading normalized
// properties. It does not traverse the prototype chain, so the
// property must be found in the object for the stub to be
// applicable.
if (!receiver_is_holder) return slow_stub();
return isolate()->builtins()->LoadIC_Normal();
}
// -------------- Fields --------------
ASSERT(lookup->property_encoding() == LookupIterator::DESCRIPTOR);
if (lookup->property_details().type() == FIELD) {
FieldIndex field = lookup->GetFieldIndex();
if (receiver_is_holder) {
return SimpleFieldLoad(field);
}
return compiler.CompileLoadField(name, field, lookup->representation());
}
return slow_stub();
// -------------- Constant properties --------------
ASSERT(lookup->property_details().type() == CONSTANT);
Handle<Object> constant = lookup->GetDataValue();
return compiler.CompileLoadConstant(name, constant);
}
......@@ -1377,17 +1407,18 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
PatchCache(name, code);
TRACE_IC("StoreIC", name);
}
Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
Handle<Object> object, Handle<String> name,
Handle<Object> value,
CacheHolderFlag cache_holder) {
Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
Handle<Object> object,
Handle<String> name,
Handle<Object> value,
CacheHolderFlag cache_holder) {
if (object->IsAccessCheckNeeded()) return slow_stub();
ASSERT(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
(object->IsJSGlobalProxy() && lookup->holder()->IsJSGlobalObject()));
......
......@@ -179,17 +179,29 @@ class IC {
static void PostPatching(Address address, Code* target, Code* old_target);
// Compute the handler either by compiling or by retrieving a cached version.
Handle<Code> ComputeHandler(LookupResult* lookup,
Handle<Object> object,
Handle<Code> ComputeHandler(LookupIterator* lookup, Handle<Object> object,
Handle<String> name,
Handle<Object> value = Handle<Code>::null());
virtual Handle<Code> CompileHandler(LookupResult* lookup,
virtual Handle<Code> CompileHandler(LookupIterator* lookup,
Handle<Object> object,
Handle<String> name, Handle<Object> value,
CacheHolderFlag cache_holder) {
UNREACHABLE();
return Handle<Code>::null();
}
// Temporary copy of the above, but using a LookupResult.
// TODO(jkummerow): Migrate callers to LookupIterator and delete these.
Handle<Code> ComputeStoreHandler(LookupResult* lookup, Handle<Object> object,
Handle<String> name,
Handle<Object> value = Handle<Code>::null());
virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
Handle<Object> object,
Handle<String> name,
Handle<Object> value,
CacheHolderFlag cache_holder) {
UNREACHABLE();
return Handle<Code>::null();
}
void UpdateMonomorphicIC(Handle<Code> handler, Handle<String> name);
bool UpdatePolymorphicIC(Handle<String> name, Handle<Code> code);
......@@ -474,11 +486,10 @@ class LoadIC: public IC {
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
Handle<Object> object,
void UpdateCaches(LookupIterator* lookup, Handle<Object> object,
Handle<String> name);
virtual Handle<Code> CompileHandler(LookupResult* lookup,
virtual Handle<Code> CompileHandler(LookupIterator* lookup,
Handle<Object> object,
Handle<String> name,
Handle<Object> unused,
......@@ -638,10 +649,11 @@ class StoreIC: public IC {
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
virtual Handle<Code> CompileHandler(LookupResult* lookup,
Handle<Object> object,
Handle<String> name, Handle<Object> value,
CacheHolderFlag cache_holder);
virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
Handle<Object> object,
Handle<String> name,
Handle<Object> value,
CacheHolderFlag cache_holder);
private:
void set_target(Code* code) {
......
......@@ -120,8 +120,9 @@ bool LookupIterator::HasProperty() {
return false;
}
} else {
property_details_ = holder_map_->instance_descriptors()->GetDetails(
number_);
// Can't use descriptor_number() yet because has_property_ is still false.
property_details_ =
holder_map_->instance_descriptors()->GetDetails(number_);
}
switch (property_details_.type()) {
......@@ -146,9 +147,10 @@ bool LookupIterator::HasProperty() {
void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
ASSERT(has_property_);
ASSERT(HolderIsReceiver());
ASSERT(HolderIsReceiverOrHiddenPrototype());
if (property_encoding_ == DICTIONARY) return;
holder_map_ = Map::PrepareForDataProperty(holder_map_, number_, value);
holder_map_ =
Map::PrepareForDataProperty(holder_map_, descriptor_number(), value);
JSObject::MigrateToMap(GetHolder<JSObject>(), holder_map_);
// Reload property information.
if (holder_map_->is_dictionary_map()) {
......@@ -163,7 +165,7 @@ void LookupIterator::PrepareForDataProperty(Handle<Object> value) {
void LookupIterator::TransitionToDataProperty(
Handle<Object> value, PropertyAttributes attributes,
Object::StoreFromKeyed store_mode) {
ASSERT(!has_property_ || !HolderIsReceiver());
ASSERT(!has_property_ || !HolderIsReceiverOrHiddenPrototype());
// Can only be called when the receiver is a JSObject. JSProxy has to be
// handled via a trap. Adding properties to primitive values is not
......@@ -194,7 +196,7 @@ void LookupIterator::TransitionToDataProperty(
}
bool LookupIterator::HolderIsReceiver() const {
bool LookupIterator::HolderIsReceiverOrHiddenPrototype() const {
ASSERT(has_property_ || state_ == INTERCEPTOR || state_ == JSPROXY);
DisallowHeapAllocation no_gc;
Handle<Object> receiver = GetReceiver();
......@@ -228,8 +230,8 @@ Handle<Object> LookupIterator::FetchValue() const {
break;
case DESCRIPTOR:
if (property_details_.type() == v8::internal::FIELD) {
FieldIndex field_index = FieldIndex::ForDescriptor(
*holder_map_, number_);
FieldIndex field_index =
FieldIndex::ForDescriptor(*holder_map_, number_);
return JSObject::FastPropertyAt(
holder, property_details_.representation(), field_index);
}
......@@ -239,6 +241,23 @@ Handle<Object> LookupIterator::FetchValue() const {
}
FieldIndex LookupIterator::GetFieldIndex() const {
ASSERT_EQ(PROPERTY, state_);
int index =
holder_map()->instance_descriptors()->GetFieldIndex(descriptor_number());
bool is_double = representation().IsDouble();
return FieldIndex::ForPropertyIndex(*holder_map(), index, is_double);
}
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
Handle<JSObject> holder = GetHolder<JSObject>();
Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
Object* value = global->property_dictionary()->ValueAt(dictionary_entry());
return Handle<PropertyCell>(PropertyCell::cast(value));
}
Handle<Object> LookupIterator::GetAccessors() const {
ASSERT(has_property_);
ASSERT_EQ(ACCESSOR, property_kind_);
......@@ -262,13 +281,13 @@ void LookupIterator::WriteDataValue(Handle<Object> value) {
NameDictionary* property_dictionary = holder->property_dictionary();
if (holder->IsGlobalObject()) {
Handle<PropertyCell> cell(
PropertyCell::cast(property_dictionary->ValueAt(number_)));
PropertyCell::cast(property_dictionary->ValueAt(dictionary_entry())));
PropertyCell::SetValueInferType(cell, value);
} else {
property_dictionary->ValueAtPut(number_, *value);
property_dictionary->ValueAtPut(dictionary_entry(), *value);
}
} else if (property_details_.type() == v8::internal::FIELD) {
holder->WriteToField(number_, *value);
holder->WriteToField(descriptor_number(), *value);
} else {
ASSERT_EQ(v8::internal::CONSTANT, property_details_.type());
}
......
......@@ -99,7 +99,7 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
return Handle<T>::cast(maybe_holder_.ToHandleChecked());
}
Handle<JSReceiver> GetRoot() const;
bool HolderIsReceiver() const;
bool HolderIsReceiverOrHiddenPrototype() const;
/* Dynamically reduce the trapped types. */
void skip_interceptor() {
......@@ -127,15 +127,20 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
ASSERT(has_property_);
return property_kind_;
}
PropertyEncoding property_encoding() const {
ASSERT(has_property_);
return property_encoding_;
}
PropertyDetails property_details() const {
ASSERT(has_property_);
return property_details_;
}
int descriptor_number() const {
ASSERT(has_property_);
ASSERT_EQ(DESCRIPTOR, property_encoding_);
return number_;
bool IsConfigurable() const { return !property_details().IsDontDelete(); }
Representation representation() const {
return property_details().representation();
}
FieldIndex GetFieldIndex() const;
Handle<PropertyCell> GetPropertyCell() const;
Handle<Object> GetAccessors() const;
Handle<Object> GetDataValue() const;
void WriteDataValue(Handle<Object> value);
......@@ -170,6 +175,16 @@ class LookupIterator V8_FINAL BASE_EMBEDDED {
bool check_access_check() const {
return (configuration_ & CHECK_ACCESS_CHECK) != 0;
}
int descriptor_number() const {
ASSERT(has_property_);
ASSERT_EQ(DESCRIPTOR, property_encoding_);
return number_;
}
int dictionary_entry() const {
ASSERT(has_property_);
ASSERT_EQ(DICTIONARY, property_encoding_);
return number_;
}
Configuration configuration_;
State state_;
......
......@@ -1210,7 +1210,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1221,7 +1221,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
__ lw(result, FieldMemOperand(result, Cell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(&miss, eq, result, Operand(at));
}
......
......@@ -1211,7 +1211,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1222,7 +1222,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
__ ld(result, FieldMemOperand(result, Cell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ LoadRoot(at, Heap::kTheHoleValueRootIndex);
__ Branch(&miss, eq, result, Operand(at));
}
......
......@@ -3011,7 +3011,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
strict_mode);
case LookupIterator::JSPROXY:
if (it->HolderIsReceiver()) {
if (it->HolderIsReceiverOrHiddenPrototype()) {
return JSProxy::SetPropertyWithHandler(it->GetHolder<JSProxy>(),
it->GetReceiver(), it->name(),
value, strict_mode);
......@@ -3028,7 +3028,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
break;
case LookupIterator::INTERCEPTOR:
if (it->HolderIsReceiver()) {
if (it->HolderIsReceiverOrHiddenPrototype()) {
MaybeHandle<Object> maybe_result =
JSObject::SetPropertyWithInterceptor(it, value);
if (!maybe_result.is_null()) return maybe_result;
......@@ -3052,7 +3052,7 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
}
switch (it->property_kind()) {
case LookupIterator::ACCESSOR:
if (it->HolderIsReceiver() ||
if (it->HolderIsReceiverOrHiddenPrototype() ||
!it->GetAccessors()->IsDeclaredAccessorInfo()) {
return SetPropertyWithAccessor(it->GetReceiver(), it->name(),
value, it->GetHolder<JSObject>(),
......@@ -3060,7 +3060,9 @@ MaybeHandle<Object> Object::SetProperty(LookupIterator* it,
}
break;
case LookupIterator::DATA:
if (it->HolderIsReceiver()) return SetDataProperty(it, value);
if (it->HolderIsReceiverOrHiddenPrototype()) {
return SetDataProperty(it, value);
}
}
done = true;
break;
......@@ -3092,7 +3094,7 @@ MaybeHandle<Object> Object::SetDataProperty(LookupIterator* it,
Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
// Store on the holder which may be hidden behind the receiver.
ASSERT(it->HolderIsReceiver());
ASSERT(it->HolderIsReceiverOrHiddenPrototype());
// Old value for the observation change record.
// Fetch before transforming the object since the encoding may become
......
......@@ -478,7 +478,7 @@ class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
Handle<JSFunction> getter);
Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
bool is_dont_delete);
bool is_configurable);
// Static interface
static Handle<Code> ComputeLoadNonexistent(Handle<Name> name,
......
......@@ -1180,7 +1180,7 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
Handle<PropertyCell> cell, Handle<Name> name, bool is_dont_delete) {
Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
Label miss;
FrontendHeader(receiver(), name, &miss);
......@@ -1190,7 +1190,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
__ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ CompareRoot(result, Heap::kTheHoleValueRootIndex);
__ j(equal, &miss);
} else if (FLAG_debug_code) {
......
......@@ -1258,7 +1258,7 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
}
// Check for deleted property if property can actually be deleted.
if (!is_dont_delete) {
if (is_configurable) {
__ cmp(result, factory()->the_hole_value());
__ j(equal, &miss);
} else if (FLAG_debug_code) {
......
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