Revision: 22802
Author: [email protected]
Date: Mon Aug 4 08:34:56 2014 UTC
Log: Avoid one repeated property lookup when computing load ICs.
[email protected]
Review URL: https://codereview.chromium.org/429053005
http://code.google.com/p/v8/source/detail?r=22802
Modified:
/branches/bleeding_edge/src/arm/stub-cache-arm.cc
/branches/bleeding_edge/src/arm64/stub-cache-arm64.cc
/branches/bleeding_edge/src/ia32/stub-cache-ia32.cc
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/ic.h
/branches/bleeding_edge/src/lookup.cc
/branches/bleeding_edge/src/lookup.h
/branches/bleeding_edge/src/mips/stub-cache-mips.cc
/branches/bleeding_edge/src/mips64/stub-cache-mips64.cc
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/stub-cache.h
/branches/bleeding_edge/src/x64/stub-cache-x64.cc
/branches/bleeding_edge/src/x87/stub-cache-x87.cc
=======================================
--- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 30 12:21:41
2014 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Mon Aug 4 08:34:56
2014 UTC
@@ -1221,7 +1221,7 @@
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 @@
__ 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);
=======================================
--- /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Wed Jul 30
12:44:50 2014 UTC
+++ /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Mon Aug 4
08:34:56 2014 UTC
@@ -1195,7 +1195,7 @@
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 @@
__ 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);
}
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 30 12:21:41
2014 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 4 08:34:56
2014 UTC
@@ -1245,7 +1245,7 @@
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 @@
}
// 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) {
=======================================
--- /branches/bleeding_edge/src/ic.cc Wed Jul 30 12:01:48 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc Mon Aug 4 08:34:56 2014 UTC
@@ -188,11 +188,6 @@
ASSERT(original_code->IsCode());
return original_code;
}
-
-
-static bool HasInterceptorGetter(JSObject* object) {
- return !object->GetNamedInterceptor()->getter()->IsUndefined();
-}
static bool HasInterceptorSetter(JSObject* object) {
@@ -200,38 +195,27 @@
}
-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 @@
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 @@
}
// 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 @@
}
-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 @@
}
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 @@
}
-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 @@
}
}
- 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> 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<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);
}
+ return compiler.CompileLoadViaGetter(name, function);
+ }
+ // TODO(dcarney): Handle correctly.
+ ASSERT(accessors->IsDeclaredAccessorInfo());
+ return slow_stub();
+ }
- 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;
+ // -------------- 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);
}
- case INTERCEPTOR:
- ASSERT(HasInterceptorGetter(*holder));
- return compiler.CompileLoadInterceptor(name);
- default:
- break;
+ 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 @@
// 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()));
=======================================
--- /branches/bleeding_edge/src/ic.h Wed Jul 30 12:21:41 2014 UTC
+++ /branches/bleeding_edge/src/ic.h Mon Aug 4 08:34:56 2014 UTC
@@ -179,17 +179,29 @@
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 @@
// 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 @@
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) {
=======================================
--- /branches/bleeding_edge/src/lookup.cc Thu Jul 24 11:33:46 2014 UTC
+++ /branches/bleeding_edge/src/lookup.cc Mon Aug 4 08:34:56 2014 UTC
@@ -120,8 +120,9 @@
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 @@
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::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 @@
}
-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 @@
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);
}
@@ -237,6 +239,23 @@
}
return handle(result, isolate_);
}
+
+
+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 {
@@ -262,13 +281,13 @@
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());
}
=======================================
--- /branches/bleeding_edge/src/lookup.h Thu Jul 24 11:33:46 2014 UTC
+++ /branches/bleeding_edge/src/lookup.h Mon Aug 4 08:34:56 2014 UTC
@@ -99,7 +99,7 @@
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 @@
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 @@
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_;
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Jul 30 17:46:10
2014 UTC
+++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Aug 4 08:34:56
2014 UTC
@@ -1210,7 +1210,7 @@
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 @@
__ 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));
}
=======================================
--- /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Wed Jul 30
17:46:10 2014 UTC
+++ /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Mon Aug 4
08:34:56 2014 UTC
@@ -1211,7 +1211,7 @@
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 @@
__ 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));
}
=======================================
--- /branches/bleeding_edge/src/objects.cc Wed Jul 30 13:54:45 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Mon Aug 4 08:34:56 2014 UTC
@@ -3011,7 +3011,7 @@
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 @@
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 @@
}
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 @@
}
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 @@
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
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Wed Jul 30 12:01:48 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Mon Aug 4 08:34:56 2014 UTC
@@ -478,7 +478,7 @@
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,
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Wed Jul 30 12:21:41
2014 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Aug 4 08:34:56
2014 UTC
@@ -1180,7 +1180,7 @@
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 @@
__ 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) {
=======================================
--- /branches/bleeding_edge/src/x87/stub-cache-x87.cc Fri Aug 1 01:58:56
2014 UTC
+++ /branches/bleeding_edge/src/x87/stub-cache-x87.cc Mon Aug 4 08:34:56
2014 UTC
@@ -1258,7 +1258,7 @@
}
// 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) {
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.