Author: [EMAIL PROTECTED]
Date: Thu Sep 18 03:22:46 2008
New Revision: 338
Modified:
branches/bleeding_edge/src/ic.cc
branches/bleeding_edge/src/ic.h
branches/bleeding_edge/src/objects-inl.h
branches/bleeding_edge/src/objects.cc
branches/bleeding_edge/src/objects.h
Log:
Revert revision 331. The propagation of monomorphic prototype failure
information does not work. In certains situations, it will keep
alternating between unrelated monomorphic states instead of going
megamorphic.
Review URL: http://codereview.chromium.org/2959
Modified: branches/bleeding_edge/src/ic.cc
==============================================================================
--- branches/bleeding_edge/src/ic.cc (original)
+++ branches/bleeding_edge/src/ic.cc Thu Sep 18 03:22:46 2008
@@ -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,16 +127,11 @@
}
-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 (target_state != MONOMORPHIC) return target_state;
- if (receiver->IsUndefined() || receiver->IsNull()) return target_state;
+ if (state != MONOMORPHIC) return state;
+ if (receiver->IsUndefined() || receiver->IsNull()) return state;
Map* map = GetCodeCacheMapForObject(receiver);
@@ -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));
}
Modified: branches/bleeding_edge/src/ic.h
==============================================================================
--- branches/bleeding_edge/src/ic.h (original)
+++ branches/bleeding_edge/src/ic.h Thu Sep 18 03:22:46 2008
@@ -81,12 +81,8 @@
Code* target() { return GetTargetAtAddress(address()); }
inline Address address();
- // Compute the state of the current inline cache. If the current
- // inline cache is monomorphic, this might change the code cache in
- // the receiver map and it might return a code object from the code
- // cache in the receiver map that should be used as the new target.
- static State ComputeCacheState(Code* target, Object* receiver,
- Object* name, Object** new_target);
+ // Compute the current IC state based on the target stub and the
receiver.
+ static State StateFrom(Code* target, Object* receiver);
// Clear the inline cache to initial state.
static void Clear(Address address);
@@ -165,7 +161,7 @@
public:
CallIC() : IC(EXTRA_CALL_FRAME) { ASSERT(target()->is_call_stub()); }
- Object* LoadFunction(Handle<Object> object, Handle<String> name);
+ Object* LoadFunction(State state, Handle<Object> object, Handle<String>
name);
// Code generator routines.
@@ -183,6 +179,7 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
+ State state,
Handle<Object> object,
Handle<String> name);
@@ -200,7 +197,7 @@
public:
LoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_load_stub()); }
- Object* Load(Handle<Object> object, Handle<String> name);
+ Object* Load(State state, Handle<Object> object, Handle<String> name);
// Code generator routines.
static void GenerateInitialize(MacroAssembler* masm);
@@ -222,6 +219,7 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
+ State state,
Handle<Object> object,
Handle<String> name);
@@ -245,7 +243,7 @@
public:
KeyedLoadIC() : IC(NO_EXTRA_FRAME) {
ASSERT(target()->is_keyed_load_stub()); }
- Object* Load(Handle<Object> object, Handle<Object> key);
+ Object* Load(State state, Handle<Object> object, Handle<Object> key);
// Code generator routines.
static void GenerateMiss(MacroAssembler* masm);
@@ -258,6 +256,7 @@
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
+ State state,
Handle<Object> object,
Handle<String> name);
@@ -284,7 +283,8 @@
public:
StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
- Object* Store(Handle<Object> object,
+ Object* Store(State state,
+ Handle<Object> object,
Handle<String> name,
Handle<Object> value);
@@ -299,7 +299,7 @@
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupResult* lookup,
- Handle<JSObject> receiver,
+ State state, Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
@@ -320,7 +320,8 @@
public:
KeyedStoreIC() : IC(NO_EXTRA_FRAME) { }
- Object* Store(Handle<Object> object,
+ Object* Store(State state,
+ Handle<Object> object,
Handle<Object> name,
Handle<Object> value);
@@ -334,6 +335,7 @@
// Update the inline cache.
void UpdateCaches(LookupResult* lookup,
+ State state,
Handle<JSObject> receiver,
Handle<String> name,
Handle<Object> value);
Modified: branches/bleeding_edge/src/objects-inl.h
==============================================================================
--- branches/bleeding_edge/src/objects-inl.h (original)
+++ branches/bleeding_edge/src/objects-inl.h Thu Sep 18 03:22:46 2008
@@ -2109,20 +2109,6 @@
}
-Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
- int index;
- return FindIndexInCodeCache(name, flags, &index);
-}
-
-
-void Map::RemoveFromCodeCache(int index) {
- FixedArray* array = code_cache();
- ASSERT(array->length() >= index && array->get(index)->IsCode());
- array->set_undefined(index - 1); // key
- array->set_undefined(index); // code
-}
-
-
#undef CAST_ACCESSOR
#undef INT_ACCESSORS
#undef SMI_ACCESSORS
Modified: branches/bleeding_edge/src/objects.cc
==============================================================================
--- branches/bleeding_edge/src/objects.cc (original)
+++ branches/bleeding_edge/src/objects.cc Thu Sep 18 03:22:46 2008
@@ -2410,24 +2410,38 @@
}
-Object* Map::FindIndexInCodeCache(String* name, Code::Flags flags, int*
index) {
+Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
FixedArray* cache = code_cache();
int length = cache->length();
for (int i = 0; i < length; i += 2) {
Object* key = cache->get(i);
if (key->IsUndefined()) {
- continue;
+ return key;
}
if (name->Equals(String::cast(key))) {
Code* code = Code::cast(cache->get(i + 1));
- if (code->flags() == flags) {
- *index = i + 1;
- return code;
- }
+ if (code->flags() == flags) return code;
}
}
- *index = -1;
return Heap::undefined_value();
+}
+
+
+int Map::IndexInCodeCache(Code* code) {
+ FixedArray* array = code_cache();
+ int len = array->length();
+ for (int i = 0; i < len; i += 2) {
+ if (array->get(i + 1) == code) return i + 1;
+ }
+ return -1;
+}
+
+
+void Map::RemoveFromCodeCache(int index) {
+ FixedArray* array = code_cache();
+ ASSERT(array->length() >= index && array->get(index)->IsCode());
+ array->set_undefined(index - 1); // key
+ array->set_undefined(index); // code
}
Modified: branches/bleeding_edge/src/objects.h
==============================================================================
--- branches/bleeding_edge/src/objects.h (original)
+++ branches/bleeding_edge/src/objects.h Thu Sep 18 03:22:46 2008
@@ -2342,14 +2342,14 @@
Object* UpdateCodeCache(String* name, Code* code);
// Returns the found code or undefined if absent.
- inline Object* FindInCodeCache(String* name, Code::Flags flags);
+ Object* FindInCodeCache(String* name, Code::Flags flags);
- // Returns the found code or undefined if absent. Also returns the
- // index at which the code was found or -1 if absent.
- Object* FindIndexInCodeCache(String* name, Code::Flags flags, int*
index);
+ // Returns the non-negative index of the code object if it is in the
+ // cache and -1 otherwise.
+ int IndexInCodeCache(Code* code);
// Removes a code object from the code cache at the given index.
- inline void RemoveFromCodeCache(int index);
+ void RemoveFromCodeCache(int index);
// Dispatched behavior.
void MapIterateBody(ObjectVisitor* v);
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---