Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(516)

Unified Diff: src/ic.cc

Issue 39973003: Merge bleeding_edge. (Closed) Base URL: https://v8.googlecode.com/svn/branches/experimental/parser
Patch Set: again Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ic.h ('k') | src/isolate.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ic.cc
diff --git a/src/ic.cc b/src/ic.cc
index be362d2a4b90967be70fa4d46939123a37006be0..4bff543a733305ec33c966e5a890195013e538c5 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -117,7 +117,9 @@ void IC::TraceIC(const char* type,
#define TRACE_IC(type, name) \
ASSERT((TraceIC(type, name), true))
-IC::IC(FrameDepth depth, Isolate* isolate) : isolate_(isolate) {
+IC::IC(FrameDepth depth, Isolate* isolate)
+ : isolate_(isolate),
+ target_set_(false) {
// To improve the performance of the (much used) IC code, we unfold a few
// levels of the stack frame iteration code. This yields a ~35% speedup when
// running DeltaBlue and a ~25% speedup of gbemu with the '--nouse-ic' flag.
@@ -300,7 +302,8 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
break;
}
- Map* map = IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map();
+ Handle<Map> map(
+ IC::GetCodeCacheHolder(isolate(), *receiver, cache_holder)->map());
// Decide whether the inline cache failed because of changes to the
// receiver itself or changes to one of its prototypes.
@@ -314,13 +317,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
if (index >= 0) {
map->RemoveFromCodeCache(*name, *target(), index);
// Handlers are stored in addition to the ICs on the map. Remove those, too.
- Code* handler = target()->FindFirstHandler();
- if (handler != NULL) {
- index = map->IndexInCodeCache(*name, handler);
- if (index >= 0) {
- map->RemoveFromCodeCache(*name, handler, index);
- }
- }
+ TryRemoveInvalidHandlers(map, name);
return true;
}
@@ -334,7 +331,7 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
// the map cannot be deprecated and the stub invalidated.
if (cache_holder == OWN_MAP) {
Map* old_map = target()->FindFirstMap();
- if (old_map == map) return true;
+ if (old_map == *map) return true;
if (old_map != NULL) {
if (old_map->is_deprecated()) return true;
if (IsMoreGeneralElementsKindTransition(old_map->elements_kind(),
@@ -357,8 +354,30 @@ bool IC::TryRemoveInvalidPrototypeDependentStub(Handle<Object> receiver,
}
+void IC::TryRemoveInvalidHandlers(Handle<Map> map, Handle<String> name) {
+ CodeHandleList handlers;
+ target()->FindHandlers(&handlers);
+ for (int i = 0; i < handlers.length(); i++) {
+ Handle<Code> handler = handlers.at(i);
+ int index = map->IndexInCodeCache(*name, *handler);
+ if (index >= 0) {
+ map->RemoveFromCodeCache(*name, *handler, index);
+ return;
+ }
+ }
+}
+
+
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
- if (state() != MONOMORPHIC || !name->IsString()) return;
+ if (!name->IsString()) return;
+ if (state() != MONOMORPHIC) {
+ if (state() == POLYMORPHIC && receiver->IsHeapObject()) {
+ TryRemoveInvalidHandlers(
+ handle(Handle<HeapObject>::cast(receiver)->map()),
+ Handle<String>::cast(name));
+ }
+ return;
+ }
if (receiver->IsUndefined() || receiver->IsNull()) return;
// Remove the target from the code cache if it became invalid
@@ -1088,6 +1107,18 @@ void IC::PatchCache(Handle<HeapObject> receiver,
}
+Handle<Code> LoadIC::SimpleFieldLoad(int offset,
+ bool inobject,
+ Representation representation) {
+ if (kind() == Code::LOAD_IC) {
+ LoadFieldStub stub(inobject, offset, representation);
+ return stub.GetCode(isolate());
+ } else {
+ KeyedLoadFieldStub stub(inobject, offset, representation);
+ return stub.GetCode(isolate());
+ }
+}
+
void LoadIC::UpdateCaches(LookupResult* lookup,
Handle<Object> object,
Handle<String> name) {
@@ -1109,20 +1140,18 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
} else if (object->IsString() &&
name->Equals(isolate()->heap()->length_string())) {
int length_index = String::kLengthOffset / kPointerSize;
- if (target()->is_load_stub()) {
- LoadFieldStub stub(true, length_index, Representation::Tagged());
- code = stub.GetCode(isolate());
- } else {
- KeyedLoadFieldStub stub(true, length_index, Representation::Tagged());
- code = stub.GetCode(isolate());
- }
+ code = SimpleFieldLoad(length_index);
} else if (!object->IsJSObject()) {
// TODO(jkummerow): It would be nice to support non-JSObjects in
// ComputeLoadHandler, then we wouldn't need to go generic here.
code = slow_stub();
+ } else if (!lookup->IsProperty()) {
+ code = kind() == Code::LOAD_IC
+ ? isolate()->stub_cache()->ComputeLoadNonexistent(
+ name, Handle<JSObject>::cast(receiver))
+ : slow_stub();
} else {
- code = ComputeLoadHandler(lookup, Handle<JSObject>::cast(receiver), name);
- if (code.is_null()) code = slow_stub();
+ code = ComputeHandler(lookup, Handle<JSObject>::cast(receiver), name);
}
PatchCache(receiver, name, code);
@@ -1137,34 +1166,56 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
}
-Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
- if (!lookup->IsProperty()) {
- // Nonexistent property. The result is undefined.
- return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver);
+Handle<Code> IC::ComputeHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Object> value) {
+ Handle<Code> code = isolate()->stub_cache()->FindHandler(
+ name, receiver, kind());
+ if (!code.is_null()) return code;
+
+ code = CompileHandler(lookup, receiver, name, value);
+
+ if (code->is_handler() && code->type() != Code::NORMAL) {
+ HeapObject::UpdateMapCodeCache(receiver, name, code);
}
- // Compute monomorphic stub.
+ return code;
+}
+
+
+Handle<Code> LoadIC::CompileHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Object> unused) {
Handle<JSObject> holder(lookup->holder());
+ LoadStubCompiler compiler(isolate(), kind());
+
switch (lookup->type()) {
- case FIELD:
- return isolate()->stub_cache()->ComputeLoadField(
- name, receiver, holder,
- lookup->GetFieldIndex(), lookup->representation());
+ case FIELD: {
+ PropertyIndex field = lookup->GetFieldIndex();
+ if (receiver.is_identical_to(holder)) {
+ return SimpleFieldLoad(field.translate(holder),
+ field.is_inobject(holder),
+ lookup->representation());
+ }
+ return compiler.CompileLoadField(
+ receiver, holder, name, field, lookup->representation());
+ }
case CONSTANT: {
Handle<Object> constant(lookup->GetConstant(), isolate());
// TODO(2803): Don't compute a stub for cons strings because they cannot
// be embedded into code.
- if (constant->IsConsString()) return Handle<Code>::null();
- return isolate()->stub_cache()->ComputeLoadConstant(
- name, receiver, holder, constant);
+ if (constant->IsConsString()) break;
+ return compiler.CompileLoadConstant(receiver, holder, name, constant);
}
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());
+ // TODO(verwaest): Turn into a handler.
return isolate()->stub_cache()->ComputeLoadGlobal(
name, receiver, global, cell, lookup->IsDontDelete());
}
@@ -1173,18 +1224,16 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
// property must be found in the receiver for the stub to be
// applicable.
if (!holder.is_identical_to(receiver)) break;
- return isolate()->stub_cache()->ComputeLoadNormal(name, receiver);
+ return isolate()->builtins()->LoadIC_Normal();
case CALLBACKS: {
- {
- // Use simple field loads for some well-known callback properties.
- int object_offset;
- Handle<Map> map(receiver->map());
- if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
- PropertyIndex index =
- PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
- return isolate()->stub_cache()->ComputeLoadField(
- name, receiver, receiver, index, Representation::Tagged());
- }
+ // Use simple field loads for some well-known callback properties.
+ int object_offset;
+ Handle<Map> map(receiver->map());
+ if (Accessors::IsJSObjectFieldAccessor(map, name, &object_offset)) {
+ PropertyIndex index =
+ PropertyIndex::NewHeaderIndex(object_offset / kPointerSize);
+ return compiler.CompileLoadField(
+ receiver, receiver, name, index, Representation::Tagged());
}
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
@@ -1193,8 +1242,7 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
Handle<ExecutableAccessorInfo>::cast(callback);
if (v8::ToCData<Address>(info->getter()) == 0) break;
if (!info->IsCompatibleReceiver(*receiver)) break;
- return isolate()->stub_cache()->ComputeLoadCallback(
- name, receiver, holder, info);
+ return compiler.CompileLoadCallback(receiver, holder, name, info);
} else if (callback->IsAccessorPair()) {
Handle<Object> getter(Handle<AccessorPair>::cast(callback)->getter(),
isolate());
@@ -1205,11 +1253,10 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
CallOptimization call_optimization(function);
if (call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiver(*receiver)) {
- return isolate()->stub_cache()->ComputeLoadCallback(
- name, receiver, holder, call_optimization);
+ return compiler.CompileLoadCallback(
+ receiver, holder, name, call_optimization);
}
- return isolate()->stub_cache()->ComputeLoadViaGetter(
- name, receiver, holder, function);
+ return compiler.CompileLoadViaGetter(receiver, holder, name, function);
}
// TODO(dcarney): Handle correctly.
if (callback->IsDeclaredAccessorInfo()) break;
@@ -1219,12 +1266,12 @@ Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup,
}
case INTERCEPTOR:
ASSERT(HasInterceptorGetter(*holder));
- return isolate()->stub_cache()->ComputeLoadInterceptor(
- name, receiver, holder);
+ return compiler.CompileLoadInterceptor(receiver, holder, name);
default:
break;
}
- return Handle<Code>::null();
+
+ return slow_stub();
}
@@ -1318,105 +1365,50 @@ MaybeObject* KeyedLoadIC::Load(Handle<Object> object,
return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
}
+ MaybeObject* maybe_object = NULL;
+ Handle<Code> stub = generic_stub();
+
// Check for values that can be converted into an internalized string directly
// or is representable as a smi.
key = TryConvertKey(key, isolate());
if (key->IsInternalizedString()) {
- return LoadIC::Load(object, Handle<String>::cast(key));
- }
-
- if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
+ maybe_object = LoadIC::Load(object, Handle<String>::cast(key));
+ if (maybe_object->IsFailure()) return maybe_object;
+ } else if (FLAG_use_ic && !object->IsAccessCheckNeeded()) {
ASSERT(!object->IsJSGlobalProxy());
- Handle<Code> stub = generic_stub();
- if (miss_mode == MISS_FORCE_GENERIC) {
- TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "force generic");
- } else if (object->IsString() && key->IsNumber()) {
- if (state() == UNINITIALIZED) stub = string_stub();
- } else if (object->IsJSObject()) {
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- if (receiver->elements()->map() ==
- isolate()->heap()->non_strict_arguments_elements_map()) {
- stub = non_strict_arguments_stub();
- } else if (receiver->HasIndexedInterceptor()) {
- stub = indexed_interceptor_stub();
- } else if (!key->ToSmi()->IsFailure() &&
- (!target().is_identical_to(non_strict_arguments_stub()))) {
- stub = LoadElementStub(receiver);
+ if (miss_mode != MISS_FORCE_GENERIC) {
+ if (object->IsString() && key->IsNumber()) {
+ if (state() == UNINITIALIZED) stub = string_stub();
+ } else if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
+ stub = non_strict_arguments_stub();
+ } else if (receiver->HasIndexedInterceptor()) {
+ stub = indexed_interceptor_stub();
+ } else if (!key->ToSmi()->IsFailure() &&
+ (!target().is_identical_to(non_strict_arguments_stub()))) {
+ stub = LoadElementStub(receiver);
+ }
}
}
+ }
+ if (!is_target_set()) {
+ if (*stub == *generic_stub()) {
+ TRACE_GENERIC_IC(isolate(), "KeyedLoadIC", "set generic");
+ }
ASSERT(!stub.is_null());
set_target(*stub);
TRACE_IC("LoadIC", key);
}
-
+ if (maybe_object != NULL) return maybe_object;
return Runtime::GetObjectPropertyOrFail(isolate(), object, key);
}
-Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name) {
- // Bail out if we didn't find a result.
- if (!lookup->IsProperty()) return Handle<Code>::null();
-
- // Compute a monomorphic stub.
- Handle<JSObject> holder(lookup->holder(), isolate());
- switch (lookup->type()) {
- case FIELD:
- return isolate()->stub_cache()->ComputeKeyedLoadField(
- name, receiver, holder,
- lookup->GetFieldIndex(), lookup->representation());
- case CONSTANT: {
- Handle<Object> constant(lookup->GetConstant(), isolate());
- // TODO(2803): Don't compute a stub for cons strings because they cannot
- // be embedded into code.
- if (constant->IsConsString()) return Handle<Code>::null();
- return isolate()->stub_cache()->ComputeKeyedLoadConstant(
- name, receiver, holder, constant);
- }
- case CALLBACKS: {
- Handle<Object> callback_object(lookup->GetCallbackObject(), isolate());
- // TODO(dcarney): Handle DeclaredAccessorInfo correctly.
- if (callback_object->IsExecutableAccessorInfo()) {
- Handle<ExecutableAccessorInfo> callback =
- Handle<ExecutableAccessorInfo>::cast(callback_object);
- if (v8::ToCData<Address>(callback->getter()) == 0) break;
- if (!callback->IsCompatibleReceiver(*receiver)) break;
- return isolate()->stub_cache()->ComputeKeyedLoadCallback(
- name, receiver, holder, callback);
- } else if (callback_object->IsAccessorPair()) {
- Handle<Object> getter(
- Handle<AccessorPair>::cast(callback_object)->getter(),
- isolate());
- if (!getter->IsJSFunction()) break;
- if (holder->IsGlobalObject()) break;
- if (!holder->HasFastProperties()) break;
- Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
- CallOptimization call_optimization(function);
- if (call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiver(*receiver)) {
- return isolate()->stub_cache()->ComputeKeyedLoadCallback(
- name, receiver, holder, call_optimization);
- }
- }
- break;
- }
- case INTERCEPTOR:
- ASSERT(HasInterceptorGetter(lookup->holder()));
- return isolate()->stub_cache()->ComputeKeyedLoadInterceptor(
- name, receiver, holder);
- default:
- // Always rewrite to the generic case so that we do not
- // repeatedly try to rewrite.
- return generic_stub();
- }
- return Handle<Code>::null();
-}
-
-
static bool LookupForWrite(Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value,
@@ -1602,27 +1594,39 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
// These are not cacheable, so we never see such LookupResults here.
ASSERT(!lookup->IsHandler());
- Handle<Code> code = ComputeStoreHandler(lookup, receiver, name, value);
- if (code.is_null()) {
- set_target(*generic_stub());
- return;
- }
+ Handle<Code> code = ComputeHandler(lookup, receiver, name, value);
PatchCache(receiver, name, code);
TRACE_IC("StoreIC", name);
}
-Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value) {
+Handle<Code> StoreIC::CompileHandler(LookupResult* lookup,
+ Handle<JSObject> receiver,
+ Handle<String> name,
+ Handle<Object> value) {
Handle<JSObject> holder(lookup->holder());
+ StoreStubCompiler compiler(isolate(), strict_mode(), kind());
switch (lookup->type()) {
case FIELD:
- return isolate()->stub_cache()->ComputeStoreField(
- name, receiver, lookup, strict_mode());
+ return compiler.CompileStoreField(receiver, lookup, name);
+ case TRANSITION: {
+ // Explicitly pass in the receiver map since LookupForWrite may have
+ // stored something else than the receiver in the holder.
+ Handle<Map> transition(
+ lookup->GetTransitionTarget(receiver->map()), isolate());
+ int descriptor = transition->LastAdded();
+
+ DescriptorArray* target_descriptors = transition->instance_descriptors();
+ PropertyDetails details = target_descriptors->GetDetails(descriptor);
+
+ if (details.type() == CALLBACKS || details.attributes() != NONE) break;
+
+ return compiler.CompileStoreTransition(
+ receiver, lookup, transition, name);
+ }
case NORMAL:
+ if (kind() == Code::KEYED_STORE_IC) break;
if (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
@@ -1630,12 +1634,16 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver);
Handle<PropertyCell> cell(
global->GetPropertyCell(lookup), isolate());
+ // TODO(verwaest): Turn into a handler.
return isolate()->stub_cache()->ComputeStoreGlobal(
name, global, cell, value, strict_mode());
}
ASSERT(holder.is_identical_to(receiver));
- return isolate()->stub_cache()->ComputeStoreNormal(strict_mode());
+ return strict_mode() == kStrictMode
+ ? isolate()->builtins()->StoreIC_Normal_Strict()
+ : isolate()->builtins()->StoreIC_Normal();
case CALLBACKS: {
+ if (kind() == Code::KEYED_STORE_IC) break;
Handle<Object> callback(lookup->GetCallbackObject(), isolate());
if (callback->IsExecutableAccessorInfo()) {
Handle<ExecutableAccessorInfo> info =
@@ -1643,8 +1651,7 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
if (v8::ToCData<Address>(info->setter()) == 0) break;
if (!holder->HasFastProperties()) break;
if (!info->IsCompatibleReceiver(*receiver)) break;
- return isolate()->stub_cache()->ComputeStoreCallback(
- name, receiver, holder, info, strict_mode());
+ return compiler.CompileStoreCallback(receiver, holder, name, info);
} else if (callback->IsAccessorPair()) {
Handle<Object> setter(
Handle<AccessorPair>::cast(callback)->setter(), isolate());
@@ -1655,12 +1662,11 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
CallOptimization call_optimization(function);
if (call_optimization.is_simple_api_call() &&
call_optimization.IsCompatibleReceiver(*receiver)) {
- return isolate()->stub_cache()->ComputeStoreCallback(
- name, receiver, holder, call_optimization, strict_mode());
+ return compiler.CompileStoreCallback(
+ receiver, holder, name, call_optimization);
}
- return isolate()->stub_cache()->ComputeStoreViaSetter(
- name, receiver, holder, Handle<JSFunction>::cast(setter),
- strict_mode());
+ return compiler.CompileStoreViaSetter(
+ receiver, holder, name, Handle<JSFunction>::cast(setter));
}
// TODO(dcarney): Handle correctly.
if (callback->IsDeclaredAccessorInfo()) break;
@@ -1669,32 +1675,17 @@ Handle<Code> StoreIC::ComputeStoreHandler(LookupResult* lookup,
break;
}
case INTERCEPTOR:
+ if (kind() == Code::KEYED_STORE_IC) break;
ASSERT(HasInterceptorSetter(*receiver));
- return isolate()->stub_cache()->ComputeStoreInterceptor(
- name, receiver, strict_mode());
+ return compiler.CompileStoreInterceptor(receiver, name);
case CONSTANT:
break;
- case TRANSITION: {
- // Explicitly pass in the receiver map since LookupForWrite may have
- // stored something else than the receiver in the holder.
- Handle<Map> transition(
- lookup->GetTransitionTarget(receiver->map()), isolate());
- int descriptor = transition->LastAdded();
-
- DescriptorArray* target_descriptors = transition->instance_descriptors();
- PropertyDetails details = target_descriptors->GetDetails(descriptor);
-
- if (details.type() == CALLBACKS || details.attributes() != NONE) break;
-
- return isolate()->stub_cache()->ComputeStoreTransition(
- name, receiver, lookup, transition, strict_mode());
- }
case NONEXISTENT:
case HANDLER:
UNREACHABLE();
break;
}
- return Handle<Code>::null();
+ return slow_stub();
}
@@ -1953,101 +1944,63 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
// or is representable as a smi.
key = TryConvertKey(key, isolate());
- if (key->IsInternalizedString()) {
- return StoreIC::Store(object,
- Handle<String>::cast(key),
- value,
- JSReceiver::MAY_BE_STORE_FROM_KEYED);
- }
+ MaybeObject* maybe_object = NULL;
+ Handle<Code> stub = generic_stub();
- bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
- !(FLAG_harmony_observation && object->IsJSObject() &&
- JSObject::cast(*object)->map()->is_observed());
- if (use_ic && !object->IsSmi()) {
- // Don't use ICs for maps of the objects in Array's prototype chain. We
- // expect to be able to trap element sets to objects with those maps in the
- // runtime to enable optimization of element hole access.
- Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
- if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
- }
-
- if (use_ic) {
- ASSERT(!object->IsJSGlobalProxy());
+ if (key->IsInternalizedString()) {
+ maybe_object = StoreIC::Store(object,
+ Handle<String>::cast(key),
+ value,
+ JSReceiver::MAY_BE_STORE_FROM_KEYED);
+ if (maybe_object->IsFailure()) return maybe_object;
+ } else {
+ bool use_ic = FLAG_use_ic && !object->IsAccessCheckNeeded() &&
+ !(FLAG_harmony_observation && object->IsJSObject() &&
+ JSObject::cast(*object)->map()->is_observed());
+ if (use_ic && !object->IsSmi()) {
+ // Don't use ICs for maps of the objects in Array's prototype chain. We
+ // expect to be able to trap element sets to objects with those maps in
+ // the runtime to enable optimization of element hole access.
+ Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
+ if (heap_object->map()->IsMapInArrayPrototypeChain()) use_ic = false;
+ }
- Handle<Code> stub = generic_stub();
- if (miss_mode != MISS_FORCE_GENERIC) {
- if (object->IsJSObject()) {
- Handle<JSObject> receiver = Handle<JSObject>::cast(object);
- bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
- if (receiver->elements()->map() ==
- isolate()->heap()->non_strict_arguments_elements_map()) {
- stub = non_strict_arguments_stub();
- } else if (key_is_smi_like &&
- (!target().is_identical_to(non_strict_arguments_stub()))) {
- KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
- stub = StoreElementStub(receiver, store_mode);
- } else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "key not a number");
+ if (use_ic) {
+ ASSERT(!object->IsJSGlobalProxy());
+
+ if (miss_mode != MISS_FORCE_GENERIC) {
+ if (object->IsJSObject()) {
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object);
+ bool key_is_smi_like = key->IsSmi() || !key->ToSmi()->IsFailure();
+ if (receiver->elements()->map() ==
+ isolate()->heap()->non_strict_arguments_elements_map()) {
+ stub = non_strict_arguments_stub();
+ } else if (key_is_smi_like &&
+ (!target().is_identical_to(non_strict_arguments_stub()))) {
+ KeyedAccessStoreMode store_mode =
+ GetStoreMode(receiver, key, value);
+ stub = StoreElementStub(receiver, store_mode);
+ }
}
- } else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "not an object");
}
- } else {
- TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "force generic");
+ }
+ }
+
+ if (!is_target_set()) {
+ if (*stub == *generic_stub()) {
+ TRACE_GENERIC_IC(isolate(), "KeyedStoreIC", "set generic");
}
ASSERT(!stub.is_null());
set_target(*stub);
TRACE_IC("StoreIC", key);
}
+ if (maybe_object) return maybe_object;
return Runtime::SetObjectPropertyOrFail(
isolate(), object , key, value, NONE, strict_mode());
}
-Handle<Code> KeyedStoreIC::ComputeStoreHandler(LookupResult* lookup,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value) {
- // If the property has a non-field type allowing map transitions
- // where there is extra room in the object, we leave the IC in its
- // current state.
- switch (lookup->type()) {
- case FIELD:
- return isolate()->stub_cache()->ComputeKeyedStoreField(
- name, receiver, lookup, strict_mode());
- case TRANSITION: {
- // Explicitly pass in the receiver map since LookupForWrite may have
- // stored something else than the receiver in the holder.
- Handle<Map> transition(
- lookup->GetTransitionTarget(receiver->map()), isolate());
- int descriptor = transition->LastAdded();
-
- DescriptorArray* target_descriptors = transition->instance_descriptors();
- PropertyDetails details = target_descriptors->GetDetails(descriptor);
-
- if (details.type() != CALLBACKS && details.attributes() == NONE) {
- return isolate()->stub_cache()->ComputeKeyedStoreTransition(
- name, receiver, lookup, transition, strict_mode());
- }
- // fall through.
- }
- case NORMAL:
- case CONSTANT:
- case CALLBACKS:
- case INTERCEPTOR:
- // Always rewrite to the generic case so that we do not
- // repeatedly try to rewrite.
- return generic_stub();
- case HANDLER:
- case NONEXISTENT:
- UNREACHABLE();
- break;
- }
- return Handle<Code>::null();
-}
-
-
#undef TRACE_IC
« no previous file with comments | « src/ic.h ('k') | src/isolate.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698