Revision: 23305
Author: [email protected]
Date: Fri Aug 22 11:38:21 2014 UTC
Log: Rewrite StoreIC handling using the LookupIterator. Continued from
patch 494153002
BUG=
[email protected]
Review URL: https://codereview.chromium.org/478043006
https://code.google.com/p/v8/source/detail?r=23305
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-inl.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/objects.h
/branches/bleeding_edge/src/runtime.cc
/branches/bleeding_edge/src/stub-cache.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 Mon Aug 18 15:03:13
2014 UTC
+++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Fri Aug 22 11:38:21
2014 UTC
@@ -581,7 +581,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Mon Aug 18
15:03:13 2014 UTC
+++ /branches/bleeding_edge/src/arm64/stub-cache-arm64.cc Fri Aug 22
11:38:21 2014 UTC
@@ -531,7 +531,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Mon Aug 18 15:03:13
2014 UTC
+++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Fri Aug 22 11:38:21
2014 UTC
@@ -568,7 +568,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/ic.cc Thu Aug 21 08:16:06 2014 UTC
+++ /branches/bleeding_edge/src/ic.cc Fri Aug 22 11:38:21 2014 UTC
@@ -200,17 +200,13 @@
DCHECK(original_code->IsCode());
return original_code;
}
-
-
-static bool HasInterceptorSetter(JSObject* object) {
- return !object->GetNamedInterceptor()->setter()->IsUndefined();
-}
static void LookupForRead(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
return;
@@ -302,7 +298,7 @@
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
- receiver_type_ = CurrentTypeOf(receiver, isolate());
+ update_receiver_type(receiver);
if (!name->IsString()) return;
if (state() != MONOMORPHIC && state() != POLYMORPHIC) return;
if (receiver->IsUndefined() || receiver->IsNull()) return;
@@ -621,27 +617,22 @@
LookupIterator it(object, name);
LookupForRead(&it);
- // If we did not find a property, check if we need to throw an exception.
- if (!it.IsFound()) {
- if (IsUndeclaredGlobal(object)) {
- return ReferenceError("not_defined", name);
+ if (it.IsFound() || !IsUndeclaredGlobal(object)) {
+ // Update inline cache and stub cache.
+ if (use_ic) UpdateCaches(&it);
+
+ // Get the property.
+ Handle<Object> result;
+ ASSIGN_RETURN_ON_EXCEPTION(isolate(), result, Object::GetProperty(&it),
+ Object);
+ if (it.IsFound()) {
+ return result;
+ } else if (!IsUndeclaredGlobal(object)) {
+ LOG(isolate(), SuspectReadEvent(*name, *object));
+ return result;
}
- LOG(isolate(), SuspectReadEvent(*name, *object));
}
-
- // Update inline cache and stub cache.
- if (use_ic) UpdateCaches(&it, object, name);
-
- // Get the property.
- 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 (!it.IsFound() && IsUndeclaredGlobal(object)) {
- return ReferenceError("not_defined", name);
- }
-
- return result;
+ return ReferenceError("not_defined", name);
}
@@ -871,14 +862,12 @@
}
-void LoadIC::UpdateCaches(LookupIterator* lookup, Handle<Object> object,
- Handle<Name> name) {
+void LoadIC::UpdateCaches(LookupIterator* lookup) {
if (state() == UNINITIALIZED) {
- // This is the first time we execute this inline cache.
- // Set the target to the pre monomorphic stub to delay
- // setting the monomorphic state.
+ // This is the first time we execute this inline cache. Set the target
to
+ // the pre monomorphic stub to delay setting the monomorphic state.
set_target(*pre_monomorphic_stub());
- TRACE_IC("LoadIC", name);
+ TRACE_IC("LoadIC", lookup->name());
return;
}
@@ -888,7 +877,7 @@
code = slow_stub();
} else if (!lookup->IsFound()) {
if (kind() == Code::LOAD_IC) {
- code = NamedLoadHandlerCompiler::ComputeLoadNonexistent(name,
+ code =
NamedLoadHandlerCompiler::ComputeLoadNonexistent(lookup->name(),
receiver_type());
// TODO(jkummerow/verwaest): Introduce a builtin that handles this
case.
if (code.is_null()) code = slow_stub();
@@ -896,11 +885,11 @@
code = slow_stub();
}
} else {
- code = ComputeHandler(lookup, object, name);
+ code = ComputeHandler(lookup);
}
- PatchCache(name, code);
- TRACE_IC("LoadIC", name);
+ PatchCache(lookup->name(), code);
+ TRACE_IC("LoadIC", lookup->name());
}
@@ -911,16 +900,15 @@
}
-Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object>
object,
- Handle<Name> name, Handle<Object> value) {
+Handle<Code> IC::ComputeHandler(LookupIterator* lookup, Handle<Object>
value) {
bool receiver_is_holder =
- object.is_identical_to(lookup->GetHolder<JSObject>());
+ lookup->GetReceiver().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->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.
@@ -933,54 +921,10 @@
// 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);
- DCHECK(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<Name>
name,
- Handle<Object> value) {
- bool receiver_is_holder = lookup->ReceiverIsHolder(object);
- 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, handler_kind(), flag,
- lookup->holder()->HasFastProperties() ? Code::FAST : Code::NORMAL);
- // 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();
+ if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject())
{
+ Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
Code* megamorphic_cached_code =
- isolate()->stub_cache()->Get(*name, map, code->flags());
+ isolate()->stub_cache()->Get(*lookup->name(), map,
code->flags());
if (megamorphic_cached_code != *code) return code;
} else {
return code;
@@ -988,11 +932,11 @@
}
}
- code = CompileStoreHandler(lookup, object, name, value, flag);
+ code = CompileHandler(lookup, value, flag);
DCHECK(code->is_handler());
if (code->type() != Code::NORMAL) {
- Map::UpdateCodeCache(stub_holder_map, name, code);
+ Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
}
return code;
@@ -1000,26 +944,28 @@
Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
- Handle<Object> object, Handle<Name>
name,
Handle<Object> unused,
CacheHolderFlag cache_holder) {
- if (object->IsString() &&
- Name::Equals(isolate()->factory()->length_string(), name)) {
+ Handle<Object> receiver = lookup->GetReceiver();
+ if (receiver->IsString() &&
+ Name::Equals(isolate()->factory()->length_string(), lookup->name()))
{
FieldIndex index =
FieldIndex::ForInObjectOffset(String::kLengthOffset);
return SimpleFieldLoad(index);
}
- if (object->IsStringWrapper() &&
- Name::Equals(isolate()->factory()->length_string(), name)) {
+ if (receiver->IsStringWrapper() &&
+ Name::Equals(isolate()->factory()->length_string(), lookup->name()))
{
StringLengthStub string_length_stub(isolate());
return string_length_stub.GetCode();
}
// Use specialized code for getting prototype of functions.
- if (object->IsJSFunction() &&
- Name::Equals(isolate()->factory()->prototype_string(), name) &&
- Handle<JSFunction>::cast(object)->should_have_prototype() &&
- !Handle<JSFunction>::cast(object)->map()->has_non_instance_prototype())
{
+ if (receiver->IsJSFunction() &&
+ Name::Equals(isolate()->factory()->prototype_string(),
lookup->name()) &&
+ Handle<JSFunction>::cast(receiver)->should_have_prototype() &&
+ !Handle<JSFunction>::cast(receiver)
+ ->map()
+ ->has_non_instance_prototype()) {
Handle<Code> stub;
FunctionPrototypeStub function_prototype_stub(isolate());
return function_prototype_stub.GetCode();
@@ -1027,7 +973,7 @@
Handle<HeapType> type = receiver_type();
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
- bool receiver_is_holder = object.is_identical_to(holder);
+ bool receiver_is_holder = receiver.is_identical_to(holder);
// -------------- Interceptors --------------
if (lookup->state() == LookupIterator::INTERCEPTOR) {
DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined());
@@ -1038,21 +984,21 @@
LookupIterator it(lookup);
it.Next();
LookupForRead(&it);
- return compiler.CompileLoadInterceptor(&it, name);
+ return compiler.CompileLoadInterceptor(&it);
}
- DCHECK(lookup->state() == LookupIterator::PROPERTY);
// -------------- Accessors --------------
+ DCHECK(lookup->state() == LookupIterator::PROPERTY);
if (lookup->property_kind() == LookupIterator::ACCESSOR) {
// Use simple field loads for some well-known callback properties.
if (receiver_is_holder) {
- DCHECK(object->IsJSObject());
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ DCHECK(receiver->IsJSObject());
+ Handle<JSObject> js_receiver = Handle<JSObject>::cast(receiver);
int object_offset;
- if (Accessors::IsJSObjectFieldAccessor<HeapType>(type, name,
+ if (Accessors::IsJSObjectFieldAccessor<HeapType>(type,
lookup->name(),
&object_offset)) {
FieldIndex index =
- FieldIndex::ForInObjectOffset(object_offset, receiver->map());
+ FieldIndex::ForInObjectOffset(object_offset,
js_receiver->map());
return SimpleFieldLoad(index);
}
}
@@ -1069,7 +1015,7 @@
if (!holder->HasFastProperties()) return slow_stub();
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
- return compiler.CompileLoadCallback(name, info);
+ return compiler.CompileLoadCallback(lookup->name(), info);
}
if (accessors->IsAccessorPair()) {
Handle<Object>
getter(Handle<AccessorPair>::cast(accessors)->getter(),
@@ -1077,7 +1023,7 @@
if (!getter->IsJSFunction()) return slow_stub();
if (!holder->HasFastProperties()) return slow_stub();
Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
- if (!object->IsJSObject() && !function->IsBuiltin() &&
+ if (!receiver->IsJSObject() && !function->IsBuiltin() &&
function->shared()->strict_mode() == SLOPPY) {
// Calling sloppy non-builtins with a value as the receiver
// requires boxing.
@@ -1087,10 +1033,10 @@
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(object, holder)) {
- return compiler.CompileLoadCallback(name, call_optimization);
+ call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ return compiler.CompileLoadCallback(lookup->name(),
call_optimization);
}
- return compiler.CompileLoadViaGetter(name, function);
+ return compiler.CompileLoadViaGetter(lookup->name(), function);
}
// TODO(dcarney): Handle correctly.
DCHECK(accessors->IsDeclaredAccessorInfo());
@@ -1105,13 +1051,13 @@
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
Handle<PropertyCell> cell = lookup->GetPropertyCell();
- Handle<Code> code =
- compiler.CompileLoadGlobal(cell, name, lookup->IsConfigurable());
+ Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->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);
+ Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
return code;
}
// There is only one shared stub for loading normalized
@@ -1131,7 +1077,7 @@
}
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
- return compiler.CompileLoadField(name, field);
+ return compiler.CompileLoadField(lookup->name(), field);
}
// -------------- Constant properties --------------
@@ -1142,7 +1088,8 @@
}
NamedLoadHandlerCompiler compiler(isolate(), receiver_type(), holder,
cache_holder);
- return compiler.CompileLoadConstant(name, lookup->GetConstantIndex());
+ return compiler.CompileLoadConstant(lookup->name(),
+ lookup->GetConstantIndex());
}
@@ -1284,70 +1231,60 @@
}
-static bool LookupForWrite(Handle<Object> object, Handle<Name> name,
- Handle<Object> value, LookupResult* lookup, IC*
ic) {
+bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode) {
// Disable ICs for non-JSObjects for now.
- if (!object->IsJSObject()) return false;
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ Handle<Object> receiver = it->GetReceiver();
+ if (!receiver->IsJSObject()) return false;
+ DCHECK(!Handle<JSObject>::cast(receiver)->map()->is_deprecated());
- Handle<JSObject> holder = receiver;
- receiver->Lookup(name, lookup);
- if (lookup->IsFound()) {
- if (lookup->IsInterceptor()
&& !HasInterceptorSetter(lookup->holder())) {
- receiver->LookupOwnRealNamedProperty(name, lookup);
- if (!lookup->IsFound()) return false;
- }
-
- if (lookup->IsReadOnly() || !lookup->IsCacheable()) return false;
- if (lookup->holder() == *receiver) return lookup->CanHoldValue(value);
- if (lookup->IsPropertyCallbacks()) return true;
- // JSGlobalProxy either stores on the global object in the prototype,
or
- // goes into the runtime if access checks are needed, so this is always
- // safe.
- if (receiver->IsJSGlobalProxy()) {
- PrototypeIterator iter(lookup->isolate(), receiver);
- return lookup->holder() == *PrototypeIterator::GetCurrent(iter);
- }
- // Currently normal holders in the prototype chain are not supported.
They
- // would require a runtime positive lookup and verification that the
details
- // have not changed.
- if (lookup->IsInterceptor() || lookup->IsNormal()) return false;
- holder = Handle<JSObject>(lookup->holder(), lookup->isolate());
- }
+ for (; it->IsFound(); it->Next()) {
+ switch (it->state()) {
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
+ UNREACHABLE();
+ case LookupIterator::JSPROXY:
+ return false;
+ case LookupIterator::INTERCEPTOR: {
+ Handle<JSObject> holder = it->GetHolder<JSObject>();
+ InterceptorInfo* info = holder->GetNamedInterceptor();
+ if (it->HolderIsReceiverOrHiddenPrototype()) {
+ if (!info->setter()->IsUndefined()) return true;
+ } else if (!info->getter()->IsUndefined() ||
+ !info->query()->IsUndefined()) {
+ return false;
+ }
+ break;
+ }
+ case LookupIterator::ACCESS_CHECK:
+ if (it->GetHolder<JSObject>()->IsAccessCheckNeeded()) return false;
+ break;
+ case LookupIterator::PROPERTY:
+ if (!it->HasProperty()) break;
+ if (it->IsReadOnly()) return false;
+ if (it->property_kind() == LookupIterator::ACCESSOR) return true;
+ if (it->GetHolder<Object>().is_identical_to(receiver)) {
+ it->PrepareForDataProperty(value);
+ // The previous receiver map might just have been deprecated,
+ // so reload it.
+ update_receiver_type(receiver);
+ return true;
+ }
- // While normally LookupTransition gets passed the receiver, in this
case we
- // pass the holder of the property that we overwrite. This keeps the
holder in
- // the LookupResult intact so we can later use it to generate a prototype
- // chain check. This avoids a double lookup, but requires us to pass in
the
- // receiver when trying to fetch extra information from the transition.
- receiver->map()->LookupTransition(*holder, *name, lookup);
- if (!lookup->IsTransition() || lookup->IsReadOnly()) return false;
+ // Receiver != holder.
+ if (receiver->IsJSGlobalProxy()) {
+ PrototypeIterator iter(it->isolate(), receiver);
+ return it->GetHolder<Object>().is_identical_to(
+ PrototypeIterator::GetCurrent(iter));
+ }
- // If the value that's being stored does not fit in the field that the
- // instance would transition to, create a new transition that fits the
value.
- // This has to be done before generating the IC, since that IC will
embed the
- // transition target.
- // Ensure the instance and its map were migrated before trying to update
the
- // transition target.
- DCHECK(!receiver->map()->is_deprecated());
- if (!lookup->CanHoldValue(value)) {
- Handle<Map> target(lookup->GetTransitionTarget());
- Representation field_representation = value->OptimalRepresentation();
- Handle<HeapType> field_type = value->OptimalType(
- lookup->isolate(), field_representation);
- Map::GeneralizeRepresentation(
- target, target->LastAdded(),
- field_representation, field_type, FORCE_FIELD);
- // Lookup the transition again since the transition tree may have
changed
- // entirely by the migration above.
- receiver->map()->LookupTransition(*holder, *name, lookup);
- if (!lookup->IsTransition()) return false;
- if (!ic->IsNameCompatibleWithPrototypeFailure(name)) return false;
- ic->MarkPrototypeFailure(name);
- return true;
+ it->PrepareTransitionToDataProperty(value, NONE, store_mode);
+ return it->IsCacheableTransition();
+ }
}
- return true;
+ it->PrepareTransitionToDataProperty(value, NONE, store_mode);
+ return it->IsCacheableTransition();
}
@@ -1399,35 +1336,14 @@
return result;
}
- LookupResult lookup(isolate());
- bool can_store = LookupForWrite(object, name, value, &lookup, this);
- if (!can_store &&
- strict_mode() == STRICT &&
- !(lookup.IsProperty() && lookup.IsReadOnly()) &&
- object->IsGlobalObject()) {
- // Strict mode doesn't allow setting non-existent global property.
- return ReferenceError("not_defined", name);
- }
- if (FLAG_use_ic) {
- if (state() == UNINITIALIZED) {
- Handle<Code> stub = pre_monomorphic_stub();
- set_target(*stub);
- TRACE_IC("StoreIC", name);
- } else if (can_store) {
- UpdateCaches(&lookup, Handle<JSObject>::cast(object), name, value);
- } else if (lookup.IsNormal() ||
- (lookup.IsField() && lookup.CanHoldValue(value))) {
- Handle<Code> stub = generic_stub();
- set_target(*stub);
- }
- }
+ LookupIterator it(object, name);
+ if (FLAG_use_ic) UpdateCaches(&it, value, store_mode);
// Set the property.
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result,
- Object::SetProperty(object, name, value, strict_mode(), store_mode),
- Object);
+ Object::SetProperty(&it, value, strict_mode(), store_mode), Object);
return result;
}
@@ -1475,133 +1391,127 @@
}
-void StoreIC::UpdateCaches(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<Name> name,
- Handle<Object> value) {
- DCHECK(lookup->IsFound());
+void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode) {
+ if (state() == UNINITIALIZED) {
+ // This is the first time we execute this inline cache. Set the target
to
+ // the pre monomorphic stub to delay setting the monomorphic state.
+ set_target(*pre_monomorphic_stub());
+ TRACE_IC("StoreIC", lookup->name());
+ return;
+ }
- // These are not cacheable, so we never see such LookupResults here.
- DCHECK(!lookup->IsHandler());
+ Handle<Code> code = LookupForWrite(lookup, value, store_mode)
+ ? ComputeHandler(lookup, value)
+ : slow_stub();
- Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
-
- PatchCache(name, code);
- TRACE_IC("StoreIC", name);
+ PatchCache(lookup->name(), code);
+ TRACE_IC("StoreIC", lookup->name());
}
-Handle<Code> StoreIC::CompileStoreHandler(LookupResult* lookup,
- Handle<Object> object,
- Handle<Name> name,
- Handle<Object> value,
- CacheHolderFlag cache_holder) {
- if (object->IsAccessCheckNeeded()) return slow_stub();
- DCHECK(cache_holder == kCacheOnReceiver || lookup->type() == CALLBACKS ||
- (object->IsJSGlobalProxy() &&
lookup->holder()->IsJSGlobalObject()));
+Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup,
+ Handle<Object> value,
+ CacheHolderFlag cache_holder) {
+ DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
+
// This is currently guaranteed by checks in StoreIC::Store.
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ Handle<JSObject> receiver =
Handle<JSObject>::cast(lookup->GetReceiver());
+ Handle<JSObject> holder = lookup->GetHolder<JSObject>();
+ DCHECK(!receiver->IsAccessCheckNeeded());
- Handle<JSObject> holder(lookup->holder());
+ // -------------- Transition --------------
+ if (lookup->state() == LookupIterator::TRANSITION) {
+ Handle<Map> transition = lookup->transition_map();
+ // Currently not handled by CompileStoreTransition.
+ if (!holder->HasFastProperties()) return slow_stub();
- if (lookup->IsTransition()) {
- // Explicitly pass in the receiver map since LookupForWrite may have
- // stored something else than the receiver in the holder.
- Handle<Map> transition(lookup->GetTransitionTarget());
- PropertyDetails details = lookup->GetPropertyDetails();
+ DCHECK(lookup->IsCacheableTransition());
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+ return compiler.CompileStoreTransition(transition, lookup->name());
+ }
- if (details.type() != CALLBACKS && details.attributes() == NONE &&
- holder->HasFastProperties()) {
+ // -------------- Interceptors --------------
+ if (lookup->state() == LookupIterator::INTERCEPTOR) {
+ DCHECK(!holder->GetNamedInterceptor()->setter()->IsUndefined());
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+ return compiler.CompileStoreInterceptor(lookup->name());
+ }
+
+ // -------------- Accessors --------------
+ DCHECK(lookup->state() == LookupIterator::PROPERTY);
+ if (lookup->property_kind() == LookupIterator::ACCESSOR) {
+ if (!holder->HasFastProperties()) return slow_stub();
+ Handle<Object> accessors = lookup->GetAccessors();
+ if (accessors->IsExecutableAccessorInfo()) {
+ Handle<ExecutableAccessorInfo> info =
+ Handle<ExecutableAccessorInfo>::cast(accessors);
+ if (v8::ToCData<Address>(info->setter()) == 0) return slow_stub();
+ if (!ExecutableAccessorInfo::IsCompatibleReceiverType(isolate(),
info,
+
receiver_type())) {
+ return slow_stub();
+ }
NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
holder);
- return compiler.CompileStoreTransition(transition, name);
+ return compiler.CompileStoreCallback(receiver, lookup->name(), info);
+ } else if (accessors->IsAccessorPair()) {
+ Handle<Object>
setter(Handle<AccessorPair>::cast(accessors)->setter(),
+ isolate());
+ if (!setter->IsJSFunction()) return slow_stub();
+ Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
+ CallOptimization call_optimization(function);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
holder);
+ if (call_optimization.is_simple_api_call() &&
+ call_optimization.IsCompatibleReceiver(receiver, holder)) {
+ return compiler.CompileStoreCallback(receiver, lookup->name(),
+ call_optimization);
+ }
+ return compiler.CompileStoreViaSetter(receiver, lookup->name(),
+
Handle<JSFunction>::cast(setter));
+ }
+ // TODO(dcarney): Handle correctly.
+ DCHECK(accessors->IsDeclaredAccessorInfo());
+ return slow_stub();
+ }
+
+ // -------------- Dictionary properties --------------
+ DCHECK(lookup->property_kind() == LookupIterator::DATA);
+ if (lookup->property_encoding() == LookupIterator::DICTIONARY) {
+ if (holder->IsGlobalObject()) {
+ Handle<PropertyCell> cell = lookup->GetPropertyCell();
+ Handle<HeapType> union_type = PropertyCell::UpdatedType(cell, value);
+ 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;
+ }
+ DCHECK(holder.is_identical_to(receiver));
+ return isolate()->builtins()->StoreIC_Normal();
+ }
+
+ // -------------- Fields --------------
+ DCHECK(lookup->property_encoding() == LookupIterator::DESCRIPTOR);
+ if (lookup->property_details().type() == FIELD) {
+ bool use_stub = true;
+ if (lookup->representation().IsHeapObject()) {
+ // Only use a generic stub if no types need to be tracked.
+ Handle<HeapType> field_type = lookup->GetFieldType();
+ HeapType::Iterator<Map> it = field_type->Classes();
+ use_stub = it.Done();
}
- } else {
- switch (lookup->type()) {
- case FIELD: {
- bool use_stub = true;
- if (lookup->representation().IsHeapObject()) {
- // Only use a generic stub if no types need to be tracked.
- HeapType* field_type = lookup->GetFieldType();
- HeapType::Iterator<Map> it = field_type->Classes();
- use_stub = it.Done();
- }
- if (use_stub) {
- StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
- lookup->representation());
- return stub.GetCode();
- }
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
holder);
- return compiler.CompileStoreField(lookup, name);
- }
- case NORMAL:
- if (receiver->IsJSGlobalProxy() || receiver->IsGlobalObject()) {
- // The stub generated for the global object picks the value
directly
- // from the property cell. So the property must be directly on
the
- // global object.
- PrototypeIterator iter(isolate(), receiver);
- Handle<GlobalObject> global =
- receiver->IsJSGlobalProxy()
- ? Handle<GlobalObject>::cast(
- PrototypeIterator::GetCurrent(iter))
- : Handle<GlobalObject>::cast(receiver);
- Handle<PropertyCell> cell(global->GetPropertyCell(lookup),
isolate());
- Handle<HeapType> union_type = PropertyCell::UpdatedType(cell,
value);
- StoreGlobalStub stub(
- isolate(), union_type->IsConstant(),
receiver->IsJSGlobalProxy());
- Handle<Code> code = stub.GetCodeCopyFromTemplate(global, cell);
- // TODO(verwaest): Move caching of these NORMAL stubs outside as
well.
- HeapObject::UpdateMapCodeCache(receiver, name, code);
- return code;
- }
- DCHECK(holder.is_identical_to(receiver));
- return isolate()->builtins()->StoreIC_Normal();
- case CALLBACKS: {
- if (!holder->HasFastProperties()) break;
- Handle<Object> callback(lookup->GetValueFromMap(holder->map()),
- isolate());
- if (callback->IsExecutableAccessorInfo()) {
- Handle<ExecutableAccessorInfo> info =
- Handle<ExecutableAccessorInfo>::cast(callback);
- if (v8::ToCData<Address>(info->setter()) == 0) break;
- if (!ExecutableAccessorInfo::IsCompatibleReceiverType(
- isolate(), info, receiver_type())) {
- break;
- }
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
- holder);
- return compiler.CompileStoreCallback(receiver, name, info);
- } else if (callback->IsAccessorPair()) {
- Handle<Object> setter(
- Handle<AccessorPair>::cast(callback)->setter(), isolate());
- if (!setter->IsJSFunction()) break;
- Handle<JSFunction> function = Handle<JSFunction>::cast(setter);
- CallOptimization call_optimization(function);
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
- holder);
- if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(receiver, holder)) {
- return compiler.CompileStoreCallback(receiver, name,
- call_optimization);
- }
- return compiler.CompileStoreViaSetter(
- receiver, name, Handle<JSFunction>::cast(setter));
- }
- // TODO(dcarney): Handle correctly.
- DCHECK(callback->IsDeclaredAccessorInfo());
- break;
- }
- case INTERCEPTOR: {
- DCHECK(HasInterceptorSetter(*holder));
- NamedStoreHandlerCompiler compiler(isolate(), receiver_type(),
holder);
- return compiler.CompileStoreInterceptor(name);
- }
- case CONSTANT:
- break;
- case HANDLER:
- UNREACHABLE();
- break;
+ if (use_stub) {
+ StoreFieldStub stub(isolate(), lookup->GetFieldIndex(),
+ lookup->representation());
+ return stub.GetCode();
}
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_type(), holder);
+ return compiler.CompileStoreField(lookup);
}
+
+ // -------------- Constant properties --------------
+ DCHECK(lookup->property_details().type() == CONSTANT);
return slow_stub();
}
=======================================
--- /branches/bleeding_edge/src/ic.h Mon Aug 11 12:57:25 2014 UTC
+++ /branches/bleeding_edge/src/ic.h Fri Aug 22 11:38:21 2014 UTC
@@ -183,29 +183,14 @@
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(LookupIterator* lookup, Handle<Object>
object,
- Handle<Name> name,
+ Handle<Code> ComputeHandler(LookupIterator* lookup,
Handle<Object> value = Handle<Code>::null());
virtual Handle<Code> CompileHandler(LookupIterator* lookup,
- Handle<Object> object,
- Handle<Name> name, Handle<Object>
value,
+ 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<Name> name,
- Handle<Object> value =
Handle<Code>::null());
- virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
- Handle<Object> object,
- Handle<Name> name,
- Handle<Object> value,
- CacheHolderFlag cache_holder) {
- UNREACHABLE();
- return Handle<Code>::null();
- }
void UpdateMonomorphicIC(Handle<Code> handler, Handle<Name> name);
bool UpdatePolymorphicIC(Handle<Name> name, Handle<Code> code);
@@ -235,6 +220,9 @@
}
Handle<HeapType> receiver_type() { return receiver_type_; }
+ void update_receiver_type(Handle<Object> receiver) {
+ receiver_type_ = CurrentTypeOf(receiver, isolate_);
+ }
void TargetMaps(MapHandleList* list) {
FindTargetMaps();
@@ -493,12 +481,9 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
- void UpdateCaches(LookupIterator* lookup, Handle<Object> object,
- Handle<Name> name);
+ void UpdateCaches(LookupIterator* lookup);
virtual Handle<Code> CompileHandler(LookupIterator* lookup,
- Handle<Object> object,
- Handle<Name> name,
Handle<Object> unused,
CacheHolderFlag cache_holder);
@@ -633,6 +618,9 @@
JSReceiver::StoreFromKeyed store_mode =
JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
+ bool LookupForWrite(LookupIterator* it, Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode);
+
protected:
virtual Handle<Code> megamorphic_stub();
@@ -652,15 +640,11 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
- void UpdateCaches(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<Name> name,
- Handle<Object> value);
- virtual Handle<Code> CompileStoreHandler(LookupResult* lookup,
- Handle<Object> object,
- Handle<Name> name,
- Handle<Object> value,
- CacheHolderFlag cache_holder);
+ void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode);
+ virtual Handle<Code> CompileHandler(LookupIterator* lookup,
+ Handle<Object> value,
+ CacheHolderFlag cache_holder);
private:
void set_target(Code* code) {
=======================================
--- /branches/bleeding_edge/src/lookup-inl.h Thu Aug 21 08:26:42 2014 UTC
+++ /branches/bleeding_edge/src/lookup-inl.h Fri Aug 22 11:38:21 2014 UTC
@@ -61,6 +61,7 @@
case PROPERTY:
return NOT_FOUND;
case JSPROXY:
+ case TRANSITION:
UNREACHABLE();
}
UNREACHABLE();
=======================================
--- /branches/bleeding_edge/src/lookup.cc Thu Aug 21 08:16:06 2014 UTC
+++ /branches/bleeding_edge/src/lookup.cc Fri Aug 22 11:38:21 2014 UTC
@@ -55,6 +55,18 @@
if (receiver->IsNumber()) return isolate_->factory()->heap_number_map();
return handle(Handle<HeapObject>::cast(receiver)->map());
}
+
+
+Handle<JSObject> LookupIterator::GetStoreTarget() const {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
+
+ if (receiver->IsJSGlobalProxy()) {
+ PrototypeIterator iter(isolate(), receiver);
+ if (iter.IsAtEnd()) return receiver;
+ return
Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+ }
+ return receiver;
+}
bool LookupIterator::IsBootstrapping() const {
@@ -90,6 +102,14 @@
holder_map_->instance_descriptors()->GetDetails(number_);
}
+ LoadPropertyKind();
+
+ has_property_ = true;
+ return true;
+}
+
+
+void LookupIterator::LoadPropertyKind() {
switch (property_details_.type()) {
case v8::internal::FIELD:
case v8::internal::NORMAL:
@@ -103,9 +123,6 @@
case v8::internal::INTERCEPTOR:
UNREACHABLE();
}
-
- has_property_ = true;
- return true;
}
@@ -148,27 +165,37 @@
}
-void LookupIterator::TransitionToDataProperty(
+void LookupIterator::PrepareTransitionToDataProperty(
Handle<Object> value, PropertyAttributes attributes,
Object::StoreFromKeyed store_mode) {
- DCHECK(!has_property_ || !HolderIsReceiverOrHiddenPrototype());
+ if (state_ == TRANSITION) return;
+ DCHECK(!has_property_ || property_kind_ != ACCESSOR);
+ DCHECK(!(has_property_ || state_ == JSPROXY) ||
+ !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
// observable.
- Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
+ Handle<JSObject> receiver = GetStoreTarget();
- if (receiver->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate(), receiver);
- receiver =
- Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
+ if (!name().is_identical_to(isolate()->factory()->hidden_string()) &&
+ !receiver->map()->is_extensible()) {
+ return;
}
+ transition_map_ = Map::TransitionToDataProperty(
+ handle(receiver->map()), name_, value, attributes, store_mode);
+ state_ = TRANSITION;
+}
+
+
+void LookupIterator::ApplyTransitionToDataProperty() {
+ DCHECK_EQ(TRANSITION, state_);
+
+ Handle<JSObject> receiver = GetStoreTarget();
maybe_holder_ = receiver;
- holder_map_ = Map::TransitionToDataProperty(handle(receiver->map()),
name_,
- value, attributes,
store_mode);
+ holder_map_ = transition_map_;
JSObject::MigrateToMap(receiver, holder_map_);
-
ReloadPropertyInformation();
}
@@ -180,14 +207,7 @@
// 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
// observable.
- Handle<JSObject> receiver = Handle<JSObject>::cast(GetReceiver());
-
- if (receiver->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate(), receiver);
- receiver =
- Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
- }
-
+ Handle<JSObject> receiver = GetStoreTarget();
maybe_holder_ = receiver;
holder_map_ = Map::TransitionToAccessorProperty(
handle(receiver->map()), name_, component, accessor, attributes);
@@ -302,6 +322,16 @@
bool is_double = representation().IsDouble();
return FieldIndex::ForPropertyIndex(*holder_map(), index, is_double);
}
+
+
+Handle<HeapType> LookupIterator::GetFieldType() const {
+ DCHECK(has_property_);
+ DCHECK_EQ(DESCRIPTOR, property_encoding_);
+ DCHECK_EQ(v8::internal::FIELD, property_details_.type());
+ return handle(
+
holder_map()->instance_descriptors()->GetFieldType(descriptor_number()),
+ isolate_);
+}
Handle<PropertyCell> LookupIterator::GetPropertyCell() const {
=======================================
--- /branches/bleeding_edge/src/lookup.h Thu Aug 21 09:34:47 2014 UTC
+++ /branches/bleeding_edge/src/lookup.h Fri Aug 22 11:38:21 2014 UTC
@@ -37,6 +37,7 @@
JSPROXY,
NOT_FOUND,
PROPERTY,
+ TRANSITION,
// Set state_ to BEFORE_PROPERTY to ensure that the next lookup will
be a
// PROPERTY lookup.
BEFORE_PROPERTY = INTERCEPTOR
@@ -114,7 +115,12 @@
Handle<Object> GetReceiver() const {
return maybe_receiver_.ToHandleChecked();
}
+ Handle<JSObject> GetStoreTarget() const;
Handle<Map> holder_map() const { return holder_map_; }
+ Handle<Map> transition_map() const {
+ DCHECK_EQ(TRANSITION, state_);
+ return transition_map_;
+ }
template <class T>
Handle<T> GetHolder() const {
DCHECK(IsFound());
@@ -133,9 +139,20 @@
// answer, and loads extra information about the property.
bool HasProperty();
void PrepareForDataProperty(Handle<Object> value);
- void TransitionToDataProperty(Handle<Object> value,
- PropertyAttributes attributes,
- Object::StoreFromKeyed store_mode);
+ void PrepareTransitionToDataProperty(Handle<Object> value,
+ PropertyAttributes attributes,
+ Object::StoreFromKeyed store_mode);
+ bool IsCacheableTransition() {
+ bool cacheable =
+ state_ == TRANSITION &&
transition_map()->GetBackPointer()->IsMap();
+ if (cacheable) {
+ property_details_ = transition_map_->GetLastDescriptorDetails();
+ LoadPropertyKind();
+ has_property_ = true;
+ }
+ return cacheable;
+ }
+ void ApplyTransitionToDataProperty();
void ReconfigureDataProperty(Handle<Object> value,
PropertyAttributes attributes);
void TransitionToAccessorProperty(AccessorComponent component,
@@ -159,6 +176,7 @@
return property_details().representation();
}
FieldIndex GetFieldIndex() const;
+ Handle<HeapType> GetFieldType() const;
int GetConstantIndex() const;
Handle<PropertyCell> GetPropertyCell() const;
Handle<Object> GetAccessors() const;
@@ -174,6 +192,7 @@
inline State LookupInHolder(Map* map);
Handle<Object> FetchValue() const;
void ReloadPropertyInformation();
+ void LoadPropertyKind();
bool IsBootstrapping() const;
@@ -227,6 +246,7 @@
Isolate* isolate_;
Handle<Name> name_;
Handle<Map> holder_map_;
+ Handle<Map> transition_map_;
MaybeHandle<Object> maybe_receiver_;
MaybeHandle<JSReceiver> maybe_holder_;
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Aug 18 19:37:49
2014 UTC
+++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Fri Aug 22 11:38:21
2014 UTC
@@ -576,7 +576,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Mon Aug 18
19:37:49 2014 UTC
+++ /branches/bleeding_edge/src/mips64/stub-cache-mips64.cc Fri Aug 22
11:38:21 2014 UTC
@@ -580,7 +580,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/objects.cc Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/objects.cc Fri Aug 22 11:38:21 2014 UTC
@@ -108,6 +108,7 @@
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
return JSProxy::GetPropertyWithHandler(it->GetHolder<JSProxy>(),
@@ -150,9 +151,10 @@
Handle<Object> JSObject::GetDataProperty(LookupIterator* it) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
- case LookupIterator::NOT_FOUND:
case LookupIterator::ACCESS_CHECK:
case LookupIterator::INTERCEPTOR:
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
it->NotFound();
@@ -2714,6 +2716,7 @@
// static
Handle<Map> Map::Update(Handle<Map> map) {
+ if (!map->is_deprecated()) return map;
return GeneralizeRepresentation(map, 0, Representation::None(),
HeapType::None(map->GetIsolate()),
ALLOW_AS_CONSTANT);
@@ -2894,10 +2897,24 @@
}
done = true;
break;
+
+ case LookupIterator::TRANSITION:
+ done = true;
+ break;
}
if (done) break;
}
+
+ // If the receiver is the JSGlobalObject, the store was contextual. In
case
+ // the property did not exist yet on the global object itself, we have to
+ // throw a reference error in strict mode.
+ if (it->GetReceiver()->IsJSGlobalObject() && strict_mode == STRICT) {
+ Handle<Object> args[1] = {it->name()};
+ Handle<Object> error = it->isolate()->factory()->NewReferenceError(
+ "not_defined", HandleVector(args, 1));
+ return it->isolate()->Throw<Object>(error);
+ }
return AddDataProperty(it, value, NONE, strict_mode, store_mode);
}
@@ -2960,20 +2977,17 @@
// TODO(verwaest): Throw a TypeError with a more specific message.
return WriteToReadOnlyProperty(it, value, strict_mode);
}
- Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver());
+
+ Handle<JSObject> receiver = it->GetStoreTarget();
// If the receiver is a JSGlobalProxy, store on the prototype
(JSGlobalObject)
// instead. If the prototype is Null, the proxy is detached.
- if (receiver->IsJSGlobalProxy()) {
- // Trying to assign to a detached proxy.
- PrototypeIterator iter(it->isolate(), receiver);
- if (iter.IsAtEnd()) return value;
- receiver =
- Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter));
- }
+ if (receiver->IsJSGlobalProxy()) return value;
- if
(!it->name().is_identical_to(it->isolate()->factory()->hidden_string()) &&
- !receiver->map()->is_extensible()) {
+ // Possibly migrate to the most up-to-date map that will be able to store
+ // |value| under it->name() with |attributes|.
+ it->PrepareTransitionToDataProperty(value, attributes, store_mode);
+ if (it->state() != LookupIterator::TRANSITION) {
if (strict_mode == SLOPPY) return value;
Handle<Object> args[1] = {it->name()};
@@ -2981,10 +2995,7 @@
"object_not_extensible", HandleVector(args, ARRAY_SIZE(args)));
return it->isolate()->Throw<Object>(error);
}
-
- // Possibly migrate to the most up-to-date map that will be able to store
- // |value| under it->name() with |attributes|.
- it->TransitionToDataProperty(value, attributes, store_mode);
+ it->ApplyTransitionToDataProperty();
// TODO(verwaest): Encapsulate dictionary handling better.
if (receiver->map()->is_dictionary_map()) {
@@ -3377,46 +3388,6 @@
Handle<Map> map(object->map());
return Map::TransitionElementsTo(map, to_kind);
}
-
-
-void JSObject::LookupOwnRealNamedProperty(Handle<Name> name,
- LookupResult* result) {
- DisallowHeapAllocation no_gc;
- if (IsJSGlobalProxy()) {
- PrototypeIterator iter(GetIsolate(), this);
- if (iter.IsAtEnd()) return result->NotFound();
- DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return JSObject::cast(iter.GetCurrent())
- ->LookupOwnRealNamedProperty(name, result);
- }
-
- if (HasFastProperties()) {
- map()->LookupDescriptor(this, *name, result);
- // A property or a map transition was found. We return all of these
result
- // types because LookupOwnRealNamedProperty is used when setting
- // properties where map transitions are handled.
- DCHECK(!result->IsFound() ||
- (result->holder() == this && result->IsFastPropertyType()));
- return;
- }
-
- int entry = property_dictionary()->FindEntry(name);
- if (entry != NameDictionary::kNotFound) {
- Object* value = property_dictionary()->ValueAt(entry);
- if (IsGlobalObject()) {
- PropertyDetails d = property_dictionary()->DetailsAt(entry);
- if (d.IsDeleted() ||
PropertyCell::cast(value)->value()->IsTheHole()) {
- result->NotFound();
- return;
- }
- value = PropertyCell::cast(value)->value();
- }
- result->DictionaryResult(this, entry);
- return;
- }
-
- result->NotFound();
-}
Maybe<bool> JSProxy::HasPropertyWithHandler(Handle<JSProxy> proxy,
@@ -3847,9 +3818,10 @@
*name != it.isolate()->heap()->hidden_string();
for (; it.IsFound(); it.Next()) {
switch (it.state()) {
- case LookupIterator::NOT_FOUND:
+ case LookupIterator::INTERCEPTOR:
case LookupIterator::JSPROXY:
- case LookupIterator::INTERCEPTOR:
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
@@ -4022,6 +3994,7 @@
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::JSPROXY:
return JSProxy::GetPropertyAttributesWithHandler(
@@ -4961,8 +4934,9 @@
for (; it.IsFound(); it.Next()) {
switch (it.state()) {
- case LookupIterator::NOT_FOUND:
case LookupIterator::JSPROXY:
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
if (it.HasAccess(v8::ACCESS_DELETE)) break;
@@ -5709,58 +5683,6 @@
return max_index + 1;
}
-
-void JSReceiver::LookupOwn(Handle<Name> name, LookupResult* result) {
- DisallowHeapAllocation no_gc;
- DCHECK(name->IsName());
-
- if (IsJSGlobalProxy()) {
- PrototypeIterator iter(GetIsolate(), this);
- if (iter.IsAtEnd()) return result->NotFound();
- DCHECK(iter.GetCurrent()->IsJSGlobalObject());
- return JSReceiver::cast(iter.GetCurrent())->LookupOwn(name, result);
- }
-
- if (IsJSProxy()) {
- result->HandlerResult(JSProxy::cast(this));
- return;
- }
-
- // Do not use inline caching if the object is a non-global object
- // that requires access checks.
- if (IsAccessCheckNeeded()) {
- result->DisallowCaching();
- }
-
- JSObject* js_object = JSObject::cast(this);
-
- // Check for lookup interceptor except when bootstrapping.
- if (js_object->HasNamedInterceptor() &&
- !GetIsolate()->bootstrapper()->IsActive()) {
- result->InterceptorResult(js_object);
- return;
- }
-
- js_object->LookupOwnRealNamedProperty(name, result);
-}
-
-
-void JSReceiver::Lookup(Handle<Name> name, LookupResult* result) {
- DisallowHeapAllocation no_gc;
- // Ecma-262 3rd 8.6.2.4
- for (PrototypeIterator iter(GetIsolate(), this,
- PrototypeIterator::START_AT_RECEIVER);
- !iter.IsAtEnd(); iter.Advance()) {
- JSReceiver::cast(iter.GetCurrent())->LookupOwn(name, result);
- if (result->IsFound()) return;
- if (name->IsOwn()) {
- result->NotFound();
- return;
- }
- }
- result->NotFound();
-}
-
static bool ContainsOnlyValidKeys(Handle<FixedArray> array) {
int len = array->length();
@@ -6397,8 +6319,9 @@
LookupIterator::CHECK_DERIVED_SKIP_INTERCEPTOR);
for (; it.IsFound(); it.Next()) {
switch (it.state()) {
- case LookupIterator::NOT_FOUND:
case LookupIterator::INTERCEPTOR:
+ case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
@@ -6835,7 +6758,7 @@
if (map->is_dictionary_map()) return map;
// Migrate to the newest map before storing the property.
- if (map->is_deprecated()) map = Update(map);
+ map = Update(map);
Handle<DescriptorArray> descriptors(map->instance_descriptors());
@@ -6857,8 +6780,8 @@
// Dictionary maps can always have additional data properties.
if (map->is_dictionary_map()) return map;
- // Migrate to the newest map before transitioning to the new property.
- if (map->is_deprecated()) map = Update(map);
+ // Migrate to the newest map before storing the property.
+ map = Update(map);
int index = map->SearchTransition(*name);
if (index != TransitionArray::kNotFound) {
@@ -6868,9 +6791,7 @@
// TODO(verwaest): Handle attributes better.
DescriptorArray* descriptors = transition->instance_descriptors();
if (descriptors->GetDetails(descriptor).attributes() != attributes) {
- return CopyGeneralizeAllRepresentations(transition, descriptor,
- FORCE_FIELD, attributes,
- "attributes mismatch");
+ return Map::Normalize(map, CLEAR_INOBJECT_PROPERTIES);
}
return Map::PrepareForDataProperty(transition, descriptor, value);
@@ -6925,7 +6846,7 @@
}
// Migrate to the newest map before transitioning to the new property.
- if (map->is_deprecated()) map = Update(map);
+ map = Update(map);
PropertyNormalizationMode mode = map->is_prototype_map()
? KEEP_INOBJECT_PROPERTIES
=======================================
--- /branches/bleeding_edge/src/objects.h Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/objects.h Fri Aug 22 11:38:21 2014 UTC
@@ -1997,10 +1997,6 @@
inline static Handle<Smi> GetOrCreateIdentityHash(
Handle<JSReceiver> object);
- // Lookup a property. If found, the result is valid and has
- // detailed information.
- void Lookup(Handle<Name> name, LookupResult* result);
-
enum KeyCollectionType { OWN_ONLY, INCLUDE_PROTOS };
// Computes the enumerable keys for a JSObject. Used for implementing
@@ -2010,7 +2006,6 @@
KeyCollectionType type);
private:
- void LookupOwn(Handle<Name> name, LookupResult* result);
DISALLOW_IMPLICIT_CONSTRUCTORS(JSReceiver);
};
@@ -2368,9 +2363,6 @@
inline void SetInternalField(int index, Object* value);
inline void SetInternalField(int index, Smi* value);
- // The following lookup functions skip interceptors.
- void LookupOwnRealNamedProperty(Handle<Name> name, LookupResult* result);
-
// Returns the number of properties on this object filtering out
properties
// with the specified attributes (ignoring interceptors).
int NumberOfOwnProperties(PropertyAttributes filter = NONE);
=======================================
--- /branches/bleeding_edge/src/runtime.cc Thu Aug 21 12:39:33 2014 UTC
+++ /branches/bleeding_edge/src/runtime.cc Fri Aug 22 11:38:21 2014 UTC
@@ -10900,6 +10900,7 @@
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
+ case LookupIterator::TRANSITION:
UNREACHABLE();
case LookupIterator::ACCESS_CHECK:
// Ignore access checks.
=======================================
--- /branches/bleeding_edge/src/stub-cache.cc Wed Aug 20 15:25:13 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.cc Fri Aug 22 11:38:21 2014 UTC
@@ -614,14 +614,18 @@
Handle<Name> name = args.at<Name>(1);
Handle<Object> value = args.at<Object>(2);
#ifdef DEBUG
- if (receiver->IsJSGlobalProxy()) {
- PrototypeIterator iter(isolate, receiver);
- DCHECK(iter.IsAtEnd() ||
-
Handle<JSGlobalObject>::cast(PrototypeIterator::GetCurrent(iter))
- ->HasNamedInterceptor());
- } else {
- DCHECK(receiver->HasNamedInterceptor());
+ PrototypeIterator iter(isolate, receiver,
+ PrototypeIterator::START_AT_RECEIVER);
+ bool found = false;
+ while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN)) {
+ Handle<Object> current = PrototypeIterator::GetCurrent(iter);
+ if (current->IsJSObject() &&
+ Handle<JSObject>::cast(current)->HasNamedInterceptor()) {
+ found = true;
+ break;
+ }
}
+ DCHECK(found);
#endif
Handle<Object> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
@@ -889,7 +893,7 @@
Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
- LookupIterator* it, Handle<Name> name) {
+ LookupIterator* it) {
// So far the most popular follow ups for interceptor loads are FIELD and
// ExecutableAccessorInfo, so inline only them. Other cases may be added
// later.
@@ -912,7 +916,7 @@
}
}
- Register reg = Frontend(receiver(), name);
+ Register reg = Frontend(receiver(), it->name());
if (inline_followup) {
// TODO(368): Compile in the whole chain: all the interceptors in
// prototypes and ultimate answer.
@@ -920,7 +924,7 @@
} else {
GenerateLoadInterceptor(reg);
}
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), Code::FAST, it->name());
}
@@ -1007,13 +1011,12 @@
}
-Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupResult*
lookup,
- Handle<Name>
name) {
+Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator*
it) {
Label miss;
- GenerateStoreField(lookup, value(), &miss);
+ GenerateStoreField(it, value(), &miss);
__ bind(&miss);
TailCallBuiltin(masm(), MissBuiltin(kind()));
- return GetCode(kind(), Code::FAST, name);
+ return GetCode(kind(), Code::FAST, it->name());
}
=======================================
--- /branches/bleeding_edge/src/stub-cache.h Tue Aug 19 17:02:04 2014 UTC
+++ /branches/bleeding_edge/src/stub-cache.h Fri Aug 22 11:38:21 2014 UTC
@@ -476,7 +476,7 @@
// The LookupIterator is used to perform a lookup behind the
interceptor. If
// the iterator points to a LookupIterator::PROPERTY, its access will be
// inlined.
- Handle<Code> CompileLoadInterceptor(LookupIterator* it, Handle<Name>
name);
+ Handle<Code> CompileLoadInterceptor(LookupIterator* it);
Handle<Code> CompileLoadViaGetter(Handle<Name> name,
Handle<JSFunction> getter);
@@ -558,7 +558,7 @@
Handle<Code> CompileStoreTransition(Handle<Map> transition,
Handle<Name> name);
- Handle<Code> CompileStoreField(LookupResult* lookup, Handle<Name> name);
+ Handle<Code> CompileStoreField(LookupIterator* it);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name>
name,
Handle<ExecutableAccessorInfo>
callback);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name>
name,
@@ -590,7 +590,7 @@
Register scratch2, Register scratch3,
Label* miss_label, Label* slow);
- void GenerateStoreField(LookupResult* lookup, Register value_reg,
+ void GenerateStoreField(LookupIterator* lookup, Register value_reg,
Label* miss_label);
static Builtins::Name SlowBuiltin(Code::Kind kind) {
=======================================
--- /branches/bleeding_edge/src/x64/stub-cache-x64.cc Mon Aug 18 15:03:13
2014 UTC
+++ /branches/bleeding_edge/src/x64/stub-cache-x64.cc Fri Aug 22 11:38:21
2014 UTC
@@ -516,7 +516,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
=======================================
--- /branches/bleeding_edge/src/x87/stub-cache-x87.cc Tue Aug 19 04:56:54
2014 UTC
+++ /branches/bleeding_edge/src/x87/stub-cache-x87.cc Fri Aug 22 11:38:21
2014 UTC
@@ -567,7 +567,7 @@
}
-void NamedStoreHandlerCompiler::GenerateStoreField(LookupResult* lookup,
+void NamedStoreHandlerCompiler::GenerateStoreField(LookupIterator* lookup,
Register value_reg,
Label* miss_label) {
DCHECK(lookup->representation().IsHeapObject());
--
--
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.