Index: src/ic.cc |
=================================================================== |
--- src/ic.cc (revision 331) |
+++ src/ic.cc (working copy) |
@@ -61,7 +61,7 @@ |
State old_state, |
Code* new_target) { |
if (FLAG_trace_ic) { |
- State new_state = new_target->ic_state(); |
+ State new_state = StateFrom(new_target, Heap::undefined_value()); |
PrintF("[%s (%c->%c) ", type, |
TransitionMarkFromState(old_state), |
TransitionMarkFromState(new_state)); |
@@ -127,17 +127,12 @@ |
} |
-IC::State IC::ComputeCacheState(Code* target, Object* receiver, |
- Object* name, Object** new_target) { |
- // Get the raw state from the target. |
- State target_state = target->ic_state(); |
+IC::State IC::StateFrom(Code* target, Object* receiver) { |
+ IC::State state = target->ic_state(); |
- // Assume that no new target exists in the cache. |
- *new_target = Heap::undefined_value(); |
+ if (state != MONOMORPHIC) return state; |
+ if (receiver->IsUndefined() || receiver->IsNull()) return state; |
- if (target_state != MONOMORPHIC) return target_state; |
- if (receiver->IsUndefined() || receiver->IsNull()) return target_state; |
- |
Map* map = GetCodeCacheMapForObject(receiver); |
// Decide whether the inline cache failed because of changes to the |
@@ -148,14 +143,8 @@ |
// the receiver map's code cache. Therefore, if the current target |
// is in the receiver map's code cache, the inline cache failed due |
// to prototype check failure. |
- int index = -1; |
- Object* code = NULL; |
- if (name->IsString()) { |
- code = map->FindIndexInCodeCache(String::cast(name), |
- target->flags(), |
- &index); |
- } |
- if (index >= 0 && code == target) { |
+ int index = map->IndexInCodeCache(target); |
+ if (index >= 0) { |
// For keyed load/store, the most likely cause of cache failure is |
// that the key has changed. We do not distinguish between |
// prototype and non-prototype failures for keyed access. |
@@ -183,7 +172,6 @@ |
return UNINITIALIZED; |
} |
- *new_target = code; |
return MONOMORPHIC; |
} |
@@ -287,7 +275,8 @@ |
} |
-Object* CallIC::LoadFunction(Handle<Object> object, |
+Object* CallIC::LoadFunction(State state, |
+ Handle<Object> object, |
Handle<String> name) { |
// If the object is undefined or null it's illegal to try to get any |
// of its properties; throw a TypeError in that case. |
@@ -326,7 +315,7 @@ |
// Lookup is valid: Update inline cache and stub cache. |
if (FLAG_use_ic && lookup.IsLoaded()) { |
- UpdateCaches(&lookup, object, name); |
+ UpdateCaches(&lookup, state, object, name); |
} |
if (lookup.type() == INTERCEPTOR) { |
@@ -385,6 +374,7 @@ |
void CallIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
Handle<Object> object, |
Handle<String> name) { |
ASSERT(lookup->IsLoaded()); |
@@ -393,55 +383,52 @@ |
// Compute the number of arguments. |
int argc = target()->arguments_count(); |
+ Object* code = NULL; |
- Object* code = Heap::undefined_value(); |
- State state = ComputeCacheState(target(), *object, *name, &code); |
- |
- switch (state) { |
- case UNINITIALIZED: |
- code = StubCache::ComputeCallPreMonomorphic(argc); |
- break; |
- case MONOMORPHIC: |
- if (code->IsUndefined()) code = StubCache::ComputeCallMegamorphic(argc); |
- break; |
- default: |
- // Compute monomorphic stub. |
- switch (lookup->type()) { |
- case FIELD: { |
- int index = lookup->GetFieldIndex(); |
- code = StubCache::ComputeCallField(argc, *name, *object, |
- lookup->holder(), index); |
- break; |
- } |
- case CONSTANT_FUNCTION: { |
- // Get the constant function and compute the code stub for this |
- // call; used for rewriting to monomorphic state and making sure |
- // that the code stub is in the stub cache. |
- JSFunction* function = lookup->GetConstantFunction(); |
- code = StubCache::ComputeCallConstant(argc, *name, *object, |
- lookup->holder(), function); |
- break; |
- } |
- case NORMAL: { |
- // There is only one shared stub for calling normalized |
- // properties. It does not traverse the prototype chain, so the |
- // property must be found in the receiver for the stub to be |
- // applicable. |
- if (!object->IsJSObject()) return; |
- Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
- if (lookup->holder() != *receiver) return; |
- code = StubCache::ComputeCallNormal(argc, *name, *receiver); |
- break; |
- } |
- case INTERCEPTOR: { |
- code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
- lookup->holder()); |
- break; |
- } |
- default: |
- return; |
+ 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 = StubCache::ComputeCallPreMonomorphic(argc); |
+ } else if (state == MONOMORPHIC) { |
+ code = StubCache::ComputeCallMegamorphic(argc); |
+ } else { |
+ // Compute monomorphic stub. |
+ switch (lookup->type()) { |
+ case FIELD: { |
+ int index = lookup->GetFieldIndex(); |
+ code = StubCache::ComputeCallField(argc, *name, *object, |
+ lookup->holder(), index); |
+ break; |
} |
- break; |
+ case CONSTANT_FUNCTION: { |
+ // Get the constant function and compute the code stub for this |
+ // call; used for rewriting to monomorphic state and making sure |
+ // that the code stub is in the stub cache. |
+ JSFunction* function = lookup->GetConstantFunction(); |
+ code = StubCache::ComputeCallConstant(argc, *name, *object, |
+ lookup->holder(), function); |
+ break; |
+ } |
+ case NORMAL: { |
+ // There is only one shared stub for calling normalized |
+ // properties. It does not traverse the prototype chain, so the |
+ // property must be found in the receiver for the stub to be |
+ // applicable. |
+ if (!object->IsJSObject()) return; |
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (lookup->holder() != *receiver) return; |
+ code = StubCache::ComputeCallNormal(argc, *name, *receiver); |
+ break; |
+ } |
+ case INTERCEPTOR: { |
+ code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
+ lookup->holder()); |
+ break; |
+ } |
+ default: |
+ return; |
+ } |
} |
// If we're unable to compute the stub (not enough memory left), we |
@@ -460,7 +447,7 @@ |
} |
-Object* LoadIC::Load(Handle<Object> object, Handle<String> name) { |
+Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { |
// If the object is undefined or null it's illegal to try to get any |
// of its properties; throw a TypeError in that case. |
if (object->IsUndefined() || object->IsNull()) { |
@@ -533,7 +520,7 @@ |
// Update inline cache and stub cache. |
if (FLAG_use_ic && lookup.IsLoaded()) { |
- UpdateCaches(&lookup, object, name); |
+ UpdateCaches(&lookup, state, object, name); |
} |
PropertyAttributes attr; |
@@ -555,6 +542,7 @@ |
void LoadIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
Handle<Object> object, |
Handle<String> name) { |
ASSERT(lookup->IsLoaded()); |
@@ -567,15 +555,13 @@ |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
// Compute the code stub for this load. |
- Object* code = Heap::undefined_value(); |
- State state = ComputeCacheState(target(), *object, *name, &code); |
- |
+ Object* code = NULL; |
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 if (state != MONOMORPHIC) { |
+ } else { |
// Compute monomorphic stub. |
switch (lookup->type()) { |
case FIELD: { |
@@ -616,20 +602,18 @@ |
default: |
return; |
} |
- |
- // If we're unable to compute the stub (not enough memory left), we |
- // simply avoid updating the caches. |
- if (code->IsFailure()) return; |
} |
+ // If we're unable to compute the stub (not enough memory left), we |
+ // simply avoid updating the caches. |
+ if (code->IsFailure()) return; |
+ |
// Patch the call site depending on the state of the cache. |
if (state == UNINITIALIZED || state == PREMONOMORPHIC || |
state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
set_target(Code::cast(code)); |
- } else if (state == MONOMORPHIC && code->IsUndefined()) { |
- set_target(megamorphic_stub()); |
} else if (state == MONOMORPHIC) { |
- set_target(Code::cast(code)); |
+ set_target(megamorphic_stub()); |
} |
#ifdef DEBUG |
@@ -638,7 +622,8 @@ |
} |
-Object* KeyedLoadIC::Load(Handle<Object> object, |
+Object* KeyedLoadIC::Load(State state, |
+ Handle<Object> object, |
Handle<Object> key) { |
if (key->IsSymbol()) { |
Handle<String> name = Handle<String>::cast(key); |
@@ -666,7 +651,7 @@ |
if (code->IsFailure()) return code; |
set_target(Code::cast(code)); |
#ifdef DEBUG |
- if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /string]\n"); |
+ TraceIC("KeyedLoadIC", name, state, target()); |
#endif |
return Smi::FromInt(string->length()); |
} |
@@ -678,7 +663,7 @@ |
if (code->IsFailure()) return code; |
set_target(Code::cast(code)); |
#ifdef DEBUG |
- if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /array]\n"); |
+ TraceIC("KeyedLoadIC", name, state, target()); |
#endif |
return JSArray::cast(*object)->length(); |
} |
@@ -691,7 +676,7 @@ |
if (code->IsFailure()) return code; |
set_target(Code::cast(code)); |
#ifdef DEBUG |
- if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#prototype /function]\n"); |
+ TraceIC("KeyedLoadIC", name, state, target()); |
#endif |
return Accessors::FunctionGetPrototype(*object, 0); |
} |
@@ -720,7 +705,7 @@ |
// Update the inline cache. |
if (FLAG_use_ic && lookup.IsLoaded()) { |
- UpdateCaches(&lookup, object, name); |
+ UpdateCaches(&lookup, state, object, name); |
} |
PropertyAttributes attr; |
@@ -750,9 +735,8 @@ |
} |
-void KeyedLoadIC::UpdateCaches(LookupResult* lookup, |
- Handle<Object> object, |
- Handle<String> name) { |
+void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state, |
+ Handle<Object> object, Handle<String> name) { |
ASSERT(lookup->IsLoaded()); |
// Bail out if we didn't find a result. |
if (!lookup->IsValid() || !lookup->IsCacheable()) return; |
@@ -760,11 +744,9 @@ |
if (!object->IsJSObject()) return; |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
- // Compute the state of the current inline cache. |
- Object* code = Heap::undefined_value(); |
- State state = ComputeCacheState(target(), *object, *name, &code); |
- |
// Compute the code stub for this load. |
+ Object* code = NULL; |
+ |
if (state == UNINITIALIZED) { |
// This is the first time we execute this inline cache. |
// Set the target to the pre monomorphic stub to delay |
@@ -827,7 +809,8 @@ |
} |
-Object* StoreIC::Store(Handle<Object> object, |
+Object* StoreIC::Store(State state, |
+ Handle<Object> object, |
Handle<String> name, |
Handle<Object> value) { |
// If the object is undefined or null it's illegal to try to set any |
@@ -855,7 +838,7 @@ |
// Update inline cache and stub cache. |
if (FLAG_use_ic && lookup.IsLoaded()) { |
- UpdateCaches(&lookup, receiver, name, value); |
+ UpdateCaches(&lookup, state, receiver, name, value); |
} |
// Set the property. |
@@ -864,6 +847,7 @@ |
void StoreIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
Handle<JSObject> receiver, |
Handle<String> name, |
Handle<Object> value) { |
@@ -880,13 +864,10 @@ |
// current state. |
PropertyType type = lookup->type(); |
- // Compute the state of the current inline cache. |
- Object* code = Heap::undefined_value(); |
- State state = ComputeCacheState(target(), *receiver, *name, &code); |
- |
// 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. |
+ Object* code = NULL; |
switch (type) { |
case FIELD: { |
code = StubCache::ComputeStoreField(*name, *receiver, |
@@ -936,7 +917,8 @@ |
} |
-Object* KeyedStoreIC::Store(Handle<Object> object, |
+Object* KeyedStoreIC::Store(State state, |
+ Handle<Object> object, |
Handle<Object> key, |
Handle<Object> value) { |
if (key->IsSymbol()) { |
@@ -967,7 +949,7 @@ |
// Update inline cache and stub cache. |
if (FLAG_use_ic && lookup.IsLoaded()) { |
- UpdateCaches(&lookup, receiver, name, value); |
+ UpdateCaches(&lookup, state, receiver, name, value); |
} |
// Set the property. |
@@ -986,6 +968,7 @@ |
void KeyedStoreIC::UpdateCaches(LookupResult* lookup, |
+ State state, |
Handle<JSObject> receiver, |
Handle<String> name, |
Handle<Object> value) { |
@@ -1005,8 +988,7 @@ |
// 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. |
- Object* code = Heap::undefined_value(); |
- State state = ComputeCacheState(target(), *receiver, *name, &code); |
+ Object* code = NULL; |
switch (type) { |
case FIELD: { |
@@ -1064,7 +1046,8 @@ |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
CallIC ic; |
- return ic.LoadFunction(args.at<Object>(0), args.at<String>(1)); |
+ IC::State state = IC::StateFrom(ic.target(), args[0]); |
+ return ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
} |
@@ -1088,7 +1071,8 @@ |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
LoadIC ic; |
- return ic.Load(args.at<Object>(0), args.at<String>(1)); |
+ IC::State state = IC::StateFrom(ic.target(), args[0]); |
+ return ic.Load(state, args.at<Object>(0), args.at<String>(1)); |
} |
@@ -1107,7 +1091,8 @@ |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
KeyedLoadIC ic; |
- return ic.Load(args.at<Object>(0), args.at<Object>(1)); |
+ IC::State state = IC::StateFrom(ic.target(), args[0]); |
+ return ic.Load(state, args.at<Object>(0), args.at<Object>(1)); |
} |
@@ -1126,7 +1111,9 @@ |
NoHandleAllocation na; |
ASSERT(args.length() == 3); |
StoreIC ic; |
- return ic.Store(args.at<Object>(0), args.at<String>(1), args.at<Object>(2)); |
+ IC::State state = IC::StateFrom(ic.target(), args[0]); |
+ return ic.Store(state, args.at<Object>(0), args.at<String>(1), |
+ args.at<Object>(2)); |
} |
@@ -1145,7 +1132,9 @@ |
NoHandleAllocation na; |
ASSERT(args.length() == 3); |
KeyedStoreIC ic; |
- return ic.Store(args.at<Object>(0), args.at<Object>(1), args.at<Object>(2)); |
+ IC::State state = IC::StateFrom(ic.target(), args[0]); |
+ return ic.Store(state, args.at<Object>(0), args.at<Object>(1), |
+ args.at<Object>(2)); |
} |