Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 65d3f659320948a2ea57a16bdc8630bcc2eafaa0..30117c9f7aa0c0ae090eca63566c957f81b16f67 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -963,39 +963,20 @@ MaybeObject* LoadIC::Load(State state, |
} |
-void LoadIC::UpdateCaches(LookupResult* lookup, |
- State state, |
- Handle<Object> object, |
- Handle<String> name) { |
- // Bail out if the result is not cacheable. |
- if (!lookup->IsCacheable()) return; |
- |
- // Loading properties from values is not common, so don't try to |
- // deal with non-JS objects here. |
- if (!object->IsJSObject()) return; |
- |
- if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
- |
- Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
- Handle<Code> code; |
- 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. |
- code = pre_monomorphic_stub(); |
- } else { |
- code = ComputeLoadMonomorphic(lookup, receiver, name); |
- if (code.is_null()) return; |
- } |
- |
- // Patch the call site depending on the state of the cache. |
+void IC::PatchCache(State state, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name, |
+ Handle<Code> code) { |
switch (state) { |
case UNINITIALIZED: |
case PREMONOMORPHIC: |
case MONOMORPHIC_PROTOTYPE_FAILURE: |
+ case POLYMORPHIC: |
set_target(*code); |
break; |
case MONOMORPHIC: |
+ // Only move to megamorphic if the target changes. |
if (target() != *code) { |
// We are transitioning from monomorphic to megamorphic case. |
// Place the current monomorphic stub and stub compiled for |
@@ -1005,25 +986,53 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
UpdateMegamorphicCache(map, *name, target()); |
} |
UpdateMegamorphicCache(receiver->map(), *name, *code); |
- set_target(*megamorphic_stub()); |
+ set_target((strict_mode == kStrictMode) |
+ ? *megamorphic_stub_strict() |
+ : *megamorphic_stub()); |
} |
break; |
case MEGAMORPHIC: |
+ // Update the stub cache. |
UpdateMegamorphicCache(receiver->map(), *name, *code); |
break; |
- case DEBUG_STUB: |
- break; |
- case POLYMORPHIC: |
case GENERIC: |
- UNREACHABLE(); |
+ case DEBUG_STUB: |
break; |
} |
+} |
+ |
+ |
+void LoadIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
+ Handle<Object> object, |
+ Handle<String> name) { |
+ // Bail out if the result is not cacheable. |
+ if (!lookup->IsCacheable()) return; |
+ |
+ // Loading properties from values is not common, so don't try to |
+ // deal with non-JS objects here. |
+ if (!object->IsJSObject()) return; |
+ |
+ if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return; |
+ |
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ Handle<Code> code; |
+ 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. |
+ code = pre_monomorphic_stub(); |
+ } else { |
+ code = ComputeLoadMonomorphic(lookup, receiver, name); |
+ if (code.is_null()) return; |
+ } |
+ PatchCache(state, kNonStrictMode, receiver, name, code); |
TRACE_IC("LoadIC", name, state, target()); |
} |
-void LoadIC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { |
+void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { |
// Cache code holding map should be consistent with |
// GenerateMonomorphicCacheProbe. |
isolate()->stub_cache()->Set(name, map, code); |
@@ -1424,7 +1433,7 @@ MaybeObject* StoreIC::Store(State state, |
LookupResult lookup(isolate()); |
if (LookupForWrite(receiver, name, &lookup)) { |
if (FLAG_use_ic) { |
- UpdateStoreCaches(&lookup, state, strict_mode, receiver, name, value); |
+ UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
} |
} else if (strict_mode == kStrictMode && |
!(lookup.IsProperty() && lookup.IsReadOnly()) && |
@@ -1438,12 +1447,12 @@ MaybeObject* StoreIC::Store(State state, |
} |
-void StoreIC::UpdateStoreCaches(LookupResult* lookup, |
- State state, |
- StrictModeFlag strict_mode, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
+void StoreIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name, |
+ Handle<Object> value) { |
ASSERT(!receiver->IsJSGlobalProxy()); |
ASSERT(StoreICableLookup(lookup)); |
ASSERT(lookup->IsFound()); |
@@ -1451,22 +1460,25 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup, |
// These are not cacheable, so we never see such LookupResults here. |
ASSERT(!lookup->IsHandler()); |
- // 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. |
- PropertyType type = lookup->type(); |
+ Handle<Code> code = |
+ ComputeStoreMonomorphic(lookup, strict_mode, receiver, name); |
+ if (code.is_null()) return; |
- // Compute the code stub for this store; used for rewriting to |
- // monomorphic state and making sure that the code stub is in the |
- // stub cache. |
+ PatchCache(state, strict_mode, receiver, name, code); |
+ TRACE_IC("StoreIC", name, state, target()); |
+} |
+ |
+ |
+Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name) { |
Handle<JSObject> holder(lookup->holder()); |
- Handle<Code> code; |
- switch (type) { |
+ switch (lookup->type()) { |
case FIELD: |
- code = isolate()->stub_cache()->ComputeStoreField( |
+ return isolate()->stub_cache()->ComputeStoreField( |
name, receiver, lookup->GetFieldIndex().field_index(), |
Handle<Map>::null(), strict_mode); |
- break; |
case NORMAL: |
if (receiver->IsGlobalObject()) { |
// The stub generated for the global object picks the value directly |
@@ -1474,44 +1486,39 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup, |
// global object. |
Handle<GlobalObject> global = Handle<GlobalObject>::cast(receiver); |
Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(lookup)); |
- code = isolate()->stub_cache()->ComputeStoreGlobal( |
+ return isolate()->stub_cache()->ComputeStoreGlobal( |
name, global, cell, strict_mode); |
- } else { |
- if (!holder.is_identical_to(receiver)) return; |
- code = isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
} |
- break; |
+ if (!holder.is_identical_to(receiver)) break; |
+ return isolate()->stub_cache()->ComputeStoreNormal(strict_mode); |
case CALLBACKS: { |
Handle<Object> callback(lookup->GetCallbackObject()); |
if (callback->IsAccessorInfo()) { |
Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(callback); |
- if (v8::ToCData<Address>(info->setter()) == 0) return; |
- if (!holder->HasFastProperties()) return; |
- if (!info->IsCompatibleReceiver(*receiver)) return; |
- code = isolate()->stub_cache()->ComputeStoreCallback( |
+ 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); |
} else if (callback->IsAccessorPair()) { |
Handle<Object> setter(Handle<AccessorPair>::cast(callback)->setter()); |
- if (!setter->IsJSFunction()) return; |
- if (holder->IsGlobalObject()) return; |
- if (!holder->HasFastProperties()) return; |
- code = isolate()->stub_cache()->ComputeStoreViaSetter( |
+ if (!setter->IsJSFunction()) break; |
+ if (holder->IsGlobalObject()) break; |
+ if (!holder->HasFastProperties()) break; |
+ return isolate()->stub_cache()->ComputeStoreViaSetter( |
name, receiver, holder, Handle<JSFunction>::cast(setter), |
strict_mode); |
- } else { |
- ASSERT(callback->IsForeign()); |
- // No IC support for old-style native accessors. |
- return; |
} |
+ ASSERT(callback->IsForeign()); |
+ // No IC support for old-style native accessors. |
break; |
} |
case INTERCEPTOR: |
ASSERT(!receiver->GetNamedInterceptor()->setter()->IsUndefined()); |
- code = isolate()->stub_cache()->ComputeStoreInterceptor( |
+ return isolate()->stub_cache()->ComputeStoreInterceptor( |
name, receiver, strict_mode); |
- break; |
case CONSTANT_FUNCTION: |
- return; |
+ break; |
case TRANSITION: { |
Handle<Map> transition(lookup->GetTransitionTarget()); |
int descriptor = transition->LastAdded(); |
@@ -1519,56 +1526,18 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup, |
DescriptorArray* target_descriptors = transition->instance_descriptors(); |
PropertyDetails details = target_descriptors->GetDetails(descriptor); |
- if (details.type() != FIELD || details.attributes() != NONE) return; |
+ if (details.type() != FIELD || details.attributes() != NONE) break; |
int field_index = target_descriptors->GetFieldIndex(descriptor); |
- code = isolate()->stub_cache()->ComputeStoreField( |
+ return isolate()->stub_cache()->ComputeStoreField( |
name, receiver, field_index, transition, strict_mode); |
- |
- break; |
} |
case NONEXISTENT: |
case HANDLER: |
UNREACHABLE(); |
- return; |
- } |
- |
- // Patch the call site depending on the state of the cache. |
- switch (state) { |
- case UNINITIALIZED: |
- case PREMONOMORPHIC: |
- case MONOMORPHIC_PROTOTYPE_FAILURE: |
- set_target(*code); |
- break; |
- case MONOMORPHIC: |
- // Only move to megamorphic if the target changes. |
- if (target() != *code) { |
- // We are transitioning from monomorphic to megamorphic case. |
- // Place the current monomorphic stub and stub compiled for |
- // the receiver into stub cache. |
- Map* map = target()->FindFirstMap(); |
- if (map != NULL) { |
- isolate()->stub_cache()->Set(*name, map, target()); |
- } |
- isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
- set_target((strict_mode == kStrictMode) |
- ? *megamorphic_stub_strict() |
- : *megamorphic_stub()); |
- } |
- break; |
- case MEGAMORPHIC: |
- // Update the stub cache. |
- isolate()->stub_cache()->Set(*name, receiver->map(), *code); |
- break; |
- case DEBUG_STUB: |
- break; |
- case POLYMORPHIC: |
- case GENERIC: |
- UNREACHABLE(); |
break; |
} |
- |
- TRACE_IC("StoreIC", name, state, target()); |
+ return Handle<Code>::null(); |
} |
@@ -1804,35 +1773,18 @@ MaybeObject* KeyedStoreIC::Store(State state, |
} |
-void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup, |
- State state, |
- StrictModeFlag strict_mode, |
- Handle<JSObject> receiver, |
- Handle<String> name, |
- Handle<Object> value) { |
- ASSERT(!receiver->IsJSGlobalProxy()); |
- ASSERT(StoreICableLookup(lookup)); |
- ASSERT(lookup->IsFound()); |
- |
- // These are not cacheable, so we never see such LookupResults here. |
- ASSERT(!lookup->IsHandler()); |
- |
+Handle<Code> KeyedStoreIC::ComputeStoreMonomorphic(LookupResult* lookup, |
+ StrictModeFlag strict_mode, |
+ Handle<JSObject> receiver, |
+ Handle<String> name) { |
// 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. |
- PropertyType type = lookup->type(); |
- |
- // Compute the code stub for this store; used for rewriting to |
- // monomorphic state and making sure that the code stub is in the |
- // stub cache. |
- Handle<Code> code; |
- |
- switch (type) { |
+ switch (lookup->type()) { |
case FIELD: |
- code = isolate()->stub_cache()->ComputeKeyedStoreField( |
+ return isolate()->stub_cache()->ComputeKeyedStoreField( |
name, receiver, lookup->GetFieldIndex().field_index(), |
Handle<Map>::null(), strict_mode); |
- break; |
case TRANSITION: { |
Handle<Map> transition(lookup->GetTransitionTarget()); |
int descriptor = transition->LastAdded(); |
@@ -1842,9 +1794,8 @@ void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup, |
if (details.type() == FIELD && details.attributes() == NONE) { |
int field_index = target_descriptors->GetFieldIndex(descriptor); |
- code = isolate()->stub_cache()->ComputeKeyedStoreField( |
+ return isolate()->stub_cache()->ComputeKeyedStoreField( |
name, receiver, field_index, transition, strict_mode); |
- break; |
} |
// fall through. |
} |
@@ -1854,43 +1805,15 @@ void KeyedStoreIC::UpdateStoreCaches(LookupResult* lookup, |
case INTERCEPTOR: |
// Always rewrite to the generic case so that we do not |
// repeatedly try to rewrite. |
- code = (strict_mode == kStrictMode) |
+ return (strict_mode == kStrictMode) |
? generic_stub_strict() |
: generic_stub(); |
- break; |
case HANDLER: |
case NONEXISTENT: |
UNREACHABLE(); |
- return; |
- } |
- |
- ASSERT(!code.is_null()); |
- |
- // Patch the call site depending on the state of the cache. |
- switch (state) { |
- case UNINITIALIZED: |
- case PREMONOMORPHIC: |
- case POLYMORPHIC: |
- set_target(*code); |
- break; |
- case MONOMORPHIC: |
- // Only move to megamorphic if the target changes. |
- if (target() != *code) { |
- set_target((strict_mode == kStrictMode) |
- ? *megamorphic_stub_strict() |
- : *megamorphic_stub()); |
- } |
- break; |
- case MEGAMORPHIC: |
- case GENERIC: |
- case DEBUG_STUB: |
- break; |
- case MONOMORPHIC_PROTOTYPE_FAILURE: |
- UNREACHABLE(); |
break; |
} |
- |
- TRACE_IC("KeyedStoreIC", name, state, target()); |
+ return Handle<Code>::null(); |
} |