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 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@338 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
d6ae7d4d04
commit
6a3d1868e4
205
src/ic.cc
205
src/ic.cc
@ -61,7 +61,7 @@ void IC::TraceIC(const char* type,
|
|||||||
State old_state,
|
State old_state,
|
||||||
Code* new_target) {
|
Code* new_target) {
|
||||||
if (FLAG_trace_ic) {
|
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,
|
PrintF("[%s (%c->%c) ", type,
|
||||||
TransitionMarkFromState(old_state),
|
TransitionMarkFromState(old_state),
|
||||||
TransitionMarkFromState(new_state));
|
TransitionMarkFromState(new_state));
|
||||||
@ -127,16 +127,11 @@ Address IC::OriginalCodeAddress() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
IC::State IC::ComputeCacheState(Code* target, Object* receiver,
|
IC::State IC::StateFrom(Code* target, Object* receiver) {
|
||||||
Object* name, Object** new_target) {
|
IC::State state = target->ic_state();
|
||||||
// Get the raw state from the target.
|
|
||||||
State target_state = target->ic_state();
|
|
||||||
|
|
||||||
// Assume that no new target exists in the cache.
|
if (state != MONOMORPHIC) return state;
|
||||||
*new_target = Heap::undefined_value();
|
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);
|
Map* map = GetCodeCacheMapForObject(receiver);
|
||||||
|
|
||||||
@ -148,14 +143,8 @@ IC::State IC::ComputeCacheState(Code* target, Object* receiver,
|
|||||||
// the receiver map's code cache. Therefore, if the current target
|
// the receiver map's code cache. Therefore, if the current target
|
||||||
// is in the receiver map's code cache, the inline cache failed due
|
// is in the receiver map's code cache, the inline cache failed due
|
||||||
// to prototype check failure.
|
// to prototype check failure.
|
||||||
int index = -1;
|
int index = map->IndexInCodeCache(target);
|
||||||
Object* code = NULL;
|
if (index >= 0) {
|
||||||
if (name->IsString()) {
|
|
||||||
code = map->FindIndexInCodeCache(String::cast(name),
|
|
||||||
target->flags(),
|
|
||||||
&index);
|
|
||||||
}
|
|
||||||
if (index >= 0 && code == target) {
|
|
||||||
// For keyed load/store, the most likely cause of cache failure is
|
// For keyed load/store, the most likely cause of cache failure is
|
||||||
// that the key has changed. We do not distinguish between
|
// that the key has changed. We do not distinguish between
|
||||||
// prototype and non-prototype failures for keyed access.
|
// prototype and non-prototype failures for keyed access.
|
||||||
@ -183,7 +172,6 @@ IC::State IC::ComputeCacheState(Code* target, Object* receiver,
|
|||||||
return UNINITIALIZED;
|
return UNINITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
*new_target = code;
|
|
||||||
return MONOMORPHIC;
|
return MONOMORPHIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,7 +275,8 @@ Object* CallIC::TryCallAsFunction(Object* object) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* CallIC::LoadFunction(Handle<Object> object,
|
Object* CallIC::LoadFunction(State state,
|
||||||
|
Handle<Object> object,
|
||||||
Handle<String> name) {
|
Handle<String> name) {
|
||||||
// If the object is undefined or null it's illegal to try to get any
|
// If the object is undefined or null it's illegal to try to get any
|
||||||
// of its properties; throw a TypeError in that case.
|
// of its properties; throw a TypeError in that case.
|
||||||
@ -326,7 +315,7 @@ Object* CallIC::LoadFunction(Handle<Object> object,
|
|||||||
|
|
||||||
// Lookup is valid: Update inline cache and stub cache.
|
// Lookup is valid: Update inline cache and stub cache.
|
||||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||||
UpdateCaches(&lookup, object, name);
|
UpdateCaches(&lookup, state, object, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lookup.type() == INTERCEPTOR) {
|
if (lookup.type() == INTERCEPTOR) {
|
||||||
@ -385,6 +374,7 @@ Object* CallIC::LoadFunction(Handle<Object> object,
|
|||||||
|
|
||||||
|
|
||||||
void CallIC::UpdateCaches(LookupResult* lookup,
|
void CallIC::UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object,
|
||||||
Handle<String> name) {
|
Handle<String> name) {
|
||||||
ASSERT(lookup->IsLoaded());
|
ASSERT(lookup->IsLoaded());
|
||||||
@ -393,55 +383,52 @@ void CallIC::UpdateCaches(LookupResult* lookup,
|
|||||||
|
|
||||||
// Compute the number of arguments.
|
// Compute the number of arguments.
|
||||||
int argc = target()->arguments_count();
|
int argc = target()->arguments_count();
|
||||||
|
Object* code = NULL;
|
||||||
|
|
||||||
Object* code = Heap::undefined_value();
|
if (state == UNINITIALIZED) {
|
||||||
State state = ComputeCacheState(target(), *object, *name, &code);
|
// This is the first time we execute this inline cache.
|
||||||
|
// Set the target to the pre monomorphic stub to delay
|
||||||
switch (state) {
|
// setting the monomorphic state.
|
||||||
case UNINITIALIZED:
|
code = StubCache::ComputeCallPreMonomorphic(argc);
|
||||||
code = StubCache::ComputeCallPreMonomorphic(argc);
|
} else if (state == MONOMORPHIC) {
|
||||||
break;
|
code = StubCache::ComputeCallMegamorphic(argc);
|
||||||
case MONOMORPHIC:
|
} else {
|
||||||
if (code->IsUndefined()) code = StubCache::ComputeCallMegamorphic(argc);
|
// Compute monomorphic stub.
|
||||||
break;
|
switch (lookup->type()) {
|
||||||
default:
|
case FIELD: {
|
||||||
// Compute monomorphic stub.
|
int index = lookup->GetFieldIndex();
|
||||||
switch (lookup->type()) {
|
code = StubCache::ComputeCallField(argc, *name, *object,
|
||||||
case FIELD: {
|
lookup->holder(), index);
|
||||||
int index = lookup->GetFieldIndex();
|
break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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
|
// If we're unable to compute the stub (not enough memory left), we
|
||||||
@ -460,7 +447,7 @@ void CallIC::UpdateCaches(LookupResult* lookup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
// If the object is undefined or null it's illegal to try to get any
|
||||||
// of its properties; throw a TypeError in that case.
|
// of its properties; throw a TypeError in that case.
|
||||||
if (object->IsUndefined() || object->IsNull()) {
|
if (object->IsUndefined() || object->IsNull()) {
|
||||||
@ -533,7 +520,7 @@ Object* LoadIC::Load(Handle<Object> object, Handle<String> name) {
|
|||||||
|
|
||||||
// Update inline cache and stub cache.
|
// Update inline cache and stub cache.
|
||||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||||
UpdateCaches(&lookup, object, name);
|
UpdateCaches(&lookup, state, object, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyAttributes attr;
|
PropertyAttributes attr;
|
||||||
@ -555,6 +542,7 @@ Object* LoadIC::Load(Handle<Object> object, Handle<String> name) {
|
|||||||
|
|
||||||
|
|
||||||
void LoadIC::UpdateCaches(LookupResult* lookup,
|
void LoadIC::UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object,
|
||||||
Handle<String> name) {
|
Handle<String> name) {
|
||||||
ASSERT(lookup->IsLoaded());
|
ASSERT(lookup->IsLoaded());
|
||||||
@ -567,15 +555,13 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
||||||
|
|
||||||
// Compute the code stub for this load.
|
// Compute the code stub for this load.
|
||||||
Object* code = Heap::undefined_value();
|
Object* code = NULL;
|
||||||
State state = ComputeCacheState(target(), *object, *name, &code);
|
|
||||||
|
|
||||||
if (state == UNINITIALIZED) {
|
if (state == UNINITIALIZED) {
|
||||||
// This is the first time we execute this inline cache.
|
// This is the first time we execute this inline cache.
|
||||||
// Set the target to the pre monomorphic stub to delay
|
// Set the target to the pre monomorphic stub to delay
|
||||||
// setting the monomorphic state.
|
// setting the monomorphic state.
|
||||||
code = pre_monomorphic_stub();
|
code = pre_monomorphic_stub();
|
||||||
} else if (state != MONOMORPHIC) {
|
} else {
|
||||||
// Compute monomorphic stub.
|
// Compute monomorphic stub.
|
||||||
switch (lookup->type()) {
|
switch (lookup->type()) {
|
||||||
case FIELD: {
|
case FIELD: {
|
||||||
@ -616,20 +602,18 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
default:
|
default:
|
||||||
return;
|
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.
|
// Patch the call site depending on the state of the cache.
|
||||||
if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
|
if (state == UNINITIALIZED || state == PREMONOMORPHIC ||
|
||||||
state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
||||||
set_target(Code::cast(code));
|
set_target(Code::cast(code));
|
||||||
} else if (state == MONOMORPHIC && code->IsUndefined()) {
|
|
||||||
set_target(megamorphic_stub());
|
|
||||||
} else if (state == MONOMORPHIC) {
|
} else if (state == MONOMORPHIC) {
|
||||||
set_target(Code::cast(code));
|
set_target(megamorphic_stub());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
@ -638,7 +622,8 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* KeyedLoadIC::Load(Handle<Object> object,
|
Object* KeyedLoadIC::Load(State state,
|
||||||
|
Handle<Object> object,
|
||||||
Handle<Object> key) {
|
Handle<Object> key) {
|
||||||
if (key->IsSymbol()) {
|
if (key->IsSymbol()) {
|
||||||
Handle<String> name = Handle<String>::cast(key);
|
Handle<String> name = Handle<String>::cast(key);
|
||||||
@ -666,7 +651,7 @@ Object* KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
if (code->IsFailure()) return code;
|
if (code->IsFailure()) return code;
|
||||||
set_target(Code::cast(code));
|
set_target(Code::cast(code));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /string]\n");
|
TraceIC("KeyedLoadIC", name, state, target());
|
||||||
#endif
|
#endif
|
||||||
return Smi::FromInt(string->length());
|
return Smi::FromInt(string->length());
|
||||||
}
|
}
|
||||||
@ -678,7 +663,7 @@ Object* KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
if (code->IsFailure()) return code;
|
if (code->IsFailure()) return code;
|
||||||
set_target(Code::cast(code));
|
set_target(Code::cast(code));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#length /array]\n");
|
TraceIC("KeyedLoadIC", name, state, target());
|
||||||
#endif
|
#endif
|
||||||
return JSArray::cast(*object)->length();
|
return JSArray::cast(*object)->length();
|
||||||
}
|
}
|
||||||
@ -691,7 +676,7 @@ Object* KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
if (code->IsFailure()) return code;
|
if (code->IsFailure()) return code;
|
||||||
set_target(Code::cast(code));
|
set_target(Code::cast(code));
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (FLAG_trace_ic) PrintF("[KeyedLoadIC : +#prototype /function]\n");
|
TraceIC("KeyedLoadIC", name, state, target());
|
||||||
#endif
|
#endif
|
||||||
return Accessors::FunctionGetPrototype(*object, 0);
|
return Accessors::FunctionGetPrototype(*object, 0);
|
||||||
}
|
}
|
||||||
@ -720,7 +705,7 @@ Object* KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
|
|
||||||
// Update the inline cache.
|
// Update the inline cache.
|
||||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||||
UpdateCaches(&lookup, object, name);
|
UpdateCaches(&lookup, state, object, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
PropertyAttributes attr;
|
PropertyAttributes attr;
|
||||||
@ -750,9 +735,8 @@ Object* KeyedLoadIC::Load(Handle<Object> object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
|
void KeyedLoadIC::UpdateCaches(LookupResult* lookup, State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object, Handle<String> name) {
|
||||||
Handle<String> name) {
|
|
||||||
ASSERT(lookup->IsLoaded());
|
ASSERT(lookup->IsLoaded());
|
||||||
// Bail out if we didn't find a result.
|
// Bail out if we didn't find a result.
|
||||||
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
|
if (!lookup->IsValid() || !lookup->IsCacheable()) return;
|
||||||
@ -760,11 +744,9 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
if (!object->IsJSObject()) return;
|
if (!object->IsJSObject()) return;
|
||||||
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
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.
|
// Compute the code stub for this load.
|
||||||
|
Object* code = NULL;
|
||||||
|
|
||||||
if (state == UNINITIALIZED) {
|
if (state == UNINITIALIZED) {
|
||||||
// This is the first time we execute this inline cache.
|
// This is the first time we execute this inline cache.
|
||||||
// Set the target to the pre monomorphic stub to delay
|
// Set the target to the pre monomorphic stub to delay
|
||||||
@ -827,7 +809,8 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* StoreIC::Store(Handle<Object> object,
|
Object* StoreIC::Store(State state,
|
||||||
|
Handle<Object> object,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Object> value) {
|
Handle<Object> value) {
|
||||||
// If the object is undefined or null it's illegal to try to set any
|
// If the object is undefined or null it's illegal to try to set any
|
||||||
@ -855,7 +838,7 @@ Object* StoreIC::Store(Handle<Object> object,
|
|||||||
|
|
||||||
// Update inline cache and stub cache.
|
// Update inline cache and stub cache.
|
||||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||||
UpdateCaches(&lookup, receiver, name, value);
|
UpdateCaches(&lookup, state, receiver, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the property.
|
// Set the property.
|
||||||
@ -864,6 +847,7 @@ Object* StoreIC::Store(Handle<Object> object,
|
|||||||
|
|
||||||
|
|
||||||
void StoreIC::UpdateCaches(LookupResult* lookup,
|
void StoreIC::UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<JSObject> receiver,
|
Handle<JSObject> receiver,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Object> value) {
|
Handle<Object> value) {
|
||||||
@ -880,13 +864,10 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
|||||||
// current state.
|
// current state.
|
||||||
PropertyType type = lookup->type();
|
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
|
// Compute the code stub for this store; used for rewriting to
|
||||||
// monomorphic state and making sure that the code stub is in the
|
// monomorphic state and making sure that the code stub is in the
|
||||||
// stub cache.
|
// stub cache.
|
||||||
|
Object* code = NULL;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FIELD: {
|
case FIELD: {
|
||||||
code = StubCache::ComputeStoreField(*name, *receiver,
|
code = StubCache::ComputeStoreField(*name, *receiver,
|
||||||
@ -936,7 +917,8 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* KeyedStoreIC::Store(Handle<Object> object,
|
Object* KeyedStoreIC::Store(State state,
|
||||||
|
Handle<Object> object,
|
||||||
Handle<Object> key,
|
Handle<Object> key,
|
||||||
Handle<Object> value) {
|
Handle<Object> value) {
|
||||||
if (key->IsSymbol()) {
|
if (key->IsSymbol()) {
|
||||||
@ -967,7 +949,7 @@ Object* KeyedStoreIC::Store(Handle<Object> object,
|
|||||||
|
|
||||||
// Update inline cache and stub cache.
|
// Update inline cache and stub cache.
|
||||||
if (FLAG_use_ic && lookup.IsLoaded()) {
|
if (FLAG_use_ic && lookup.IsLoaded()) {
|
||||||
UpdateCaches(&lookup, receiver, name, value);
|
UpdateCaches(&lookup, state, receiver, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the property.
|
// Set the property.
|
||||||
@ -986,6 +968,7 @@ Object* KeyedStoreIC::Store(Handle<Object> object,
|
|||||||
|
|
||||||
|
|
||||||
void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<JSObject> receiver,
|
Handle<JSObject> receiver,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Object> value) {
|
Handle<Object> value) {
|
||||||
@ -1005,8 +988,7 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
|||||||
// Compute the code stub for this store; used for rewriting to
|
// Compute the code stub for this store; used for rewriting to
|
||||||
// monomorphic state and making sure that the code stub is in the
|
// monomorphic state and making sure that the code stub is in the
|
||||||
// stub cache.
|
// stub cache.
|
||||||
Object* code = Heap::undefined_value();
|
Object* code = NULL;
|
||||||
State state = ComputeCacheState(target(), *receiver, *name, &code);
|
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FIELD: {
|
case FIELD: {
|
||||||
@ -1064,7 +1046,8 @@ Object* CallIC_Miss(Arguments args) {
|
|||||||
NoHandleAllocation na;
|
NoHandleAllocation na;
|
||||||
ASSERT(args.length() == 2);
|
ASSERT(args.length() == 2);
|
||||||
CallIC ic;
|
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 @@ Object* LoadIC_Miss(Arguments args) {
|
|||||||
NoHandleAllocation na;
|
NoHandleAllocation na;
|
||||||
ASSERT(args.length() == 2);
|
ASSERT(args.length() == 2);
|
||||||
LoadIC ic;
|
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 @@ Object* KeyedLoadIC_Miss(Arguments args) {
|
|||||||
NoHandleAllocation na;
|
NoHandleAllocation na;
|
||||||
ASSERT(args.length() == 2);
|
ASSERT(args.length() == 2);
|
||||||
KeyedLoadIC ic;
|
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 @@ Object* StoreIC_Miss(Arguments args) {
|
|||||||
NoHandleAllocation na;
|
NoHandleAllocation na;
|
||||||
ASSERT(args.length() == 3);
|
ASSERT(args.length() == 3);
|
||||||
StoreIC ic;
|
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 @@ Object* KeyedStoreIC_Miss(Arguments args) {
|
|||||||
NoHandleAllocation na;
|
NoHandleAllocation na;
|
||||||
ASSERT(args.length() == 3);
|
ASSERT(args.length() == 3);
|
||||||
KeyedStoreIC ic;
|
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
26
src/ic.h
26
src/ic.h
@ -81,12 +81,8 @@ class IC {
|
|||||||
Code* target() { return GetTargetAtAddress(address()); }
|
Code* target() { return GetTargetAtAddress(address()); }
|
||||||
inline Address address();
|
inline Address address();
|
||||||
|
|
||||||
// Compute the state of the current inline cache. If the current
|
// Compute the current IC state based on the target stub and the receiver.
|
||||||
// inline cache is monomorphic, this might change the code cache in
|
static State StateFrom(Code* target, Object* receiver);
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Clear the inline cache to initial state.
|
// Clear the inline cache to initial state.
|
||||||
static void Clear(Address address);
|
static void Clear(Address address);
|
||||||
@ -165,7 +161,7 @@ class CallIC: public IC {
|
|||||||
public:
|
public:
|
||||||
CallIC() : IC(EXTRA_CALL_FRAME) { ASSERT(target()->is_call_stub()); }
|
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.
|
// Code generator routines.
|
||||||
@ -183,6 +179,7 @@ class CallIC: public IC {
|
|||||||
// Update the inline cache and the global stub cache based on the
|
// Update the inline cache and the global stub cache based on the
|
||||||
// lookup result.
|
// lookup result.
|
||||||
void UpdateCaches(LookupResult* lookup,
|
void UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object,
|
||||||
Handle<String> name);
|
Handle<String> name);
|
||||||
|
|
||||||
@ -200,7 +197,7 @@ class LoadIC: public IC {
|
|||||||
public:
|
public:
|
||||||
LoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_load_stub()); }
|
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.
|
// Code generator routines.
|
||||||
static void GenerateInitialize(MacroAssembler* masm);
|
static void GenerateInitialize(MacroAssembler* masm);
|
||||||
@ -222,6 +219,7 @@ class LoadIC: public IC {
|
|||||||
// Update the inline cache and the global stub cache based on the
|
// Update the inline cache and the global stub cache based on the
|
||||||
// lookup result.
|
// lookup result.
|
||||||
void UpdateCaches(LookupResult* lookup,
|
void UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object,
|
||||||
Handle<String> name);
|
Handle<String> name);
|
||||||
|
|
||||||
@ -245,7 +243,7 @@ class KeyedLoadIC: public IC {
|
|||||||
public:
|
public:
|
||||||
KeyedLoadIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_keyed_load_stub()); }
|
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.
|
// Code generator routines.
|
||||||
static void GenerateMiss(MacroAssembler* masm);
|
static void GenerateMiss(MacroAssembler* masm);
|
||||||
@ -258,6 +256,7 @@ class KeyedLoadIC: public IC {
|
|||||||
|
|
||||||
// Update the inline cache.
|
// Update the inline cache.
|
||||||
void UpdateCaches(LookupResult* lookup,
|
void UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<Object> object,
|
Handle<Object> object,
|
||||||
Handle<String> name);
|
Handle<String> name);
|
||||||
|
|
||||||
@ -284,7 +283,8 @@ class StoreIC: public IC {
|
|||||||
public:
|
public:
|
||||||
StoreIC() : IC(NO_EXTRA_FRAME) { ASSERT(target()->is_store_stub()); }
|
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<String> name,
|
||||||
Handle<Object> value);
|
Handle<Object> value);
|
||||||
|
|
||||||
@ -299,7 +299,7 @@ class StoreIC: public IC {
|
|||||||
// Update the inline cache and the global stub cache based on the
|
// Update the inline cache and the global stub cache based on the
|
||||||
// lookup result.
|
// lookup result.
|
||||||
void UpdateCaches(LookupResult* lookup,
|
void UpdateCaches(LookupResult* lookup,
|
||||||
Handle<JSObject> receiver,
|
State state, Handle<JSObject> receiver,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Object> value);
|
Handle<Object> value);
|
||||||
|
|
||||||
@ -320,7 +320,8 @@ class KeyedStoreIC: public IC {
|
|||||||
public:
|
public:
|
||||||
KeyedStoreIC() : IC(NO_EXTRA_FRAME) { }
|
KeyedStoreIC() : IC(NO_EXTRA_FRAME) { }
|
||||||
|
|
||||||
Object* Store(Handle<Object> object,
|
Object* Store(State state,
|
||||||
|
Handle<Object> object,
|
||||||
Handle<Object> name,
|
Handle<Object> name,
|
||||||
Handle<Object> value);
|
Handle<Object> value);
|
||||||
|
|
||||||
@ -334,6 +335,7 @@ class KeyedStoreIC: public IC {
|
|||||||
|
|
||||||
// Update the inline cache.
|
// Update the inline cache.
|
||||||
void UpdateCaches(LookupResult* lookup,
|
void UpdateCaches(LookupResult* lookup,
|
||||||
|
State state,
|
||||||
Handle<JSObject> receiver,
|
Handle<JSObject> receiver,
|
||||||
Handle<String> name,
|
Handle<String> name,
|
||||||
Handle<Object> value);
|
Handle<Object> value);
|
||||||
|
@ -2109,20 +2109,6 @@ void Map::ClearCodeCache() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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 CAST_ACCESSOR
|
||||||
#undef INT_ACCESSORS
|
#undef INT_ACCESSORS
|
||||||
#undef SMI_ACCESSORS
|
#undef SMI_ACCESSORS
|
||||||
|
@ -2410,27 +2410,41 @@ Object* Map::UpdateCodeCache(String* name, Code* code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Object* Map::FindIndexInCodeCache(String* name, Code::Flags flags, int* index) {
|
Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
|
||||||
FixedArray* cache = code_cache();
|
FixedArray* cache = code_cache();
|
||||||
int length = cache->length();
|
int length = cache->length();
|
||||||
for (int i = 0; i < length; i += 2) {
|
for (int i = 0; i < length; i += 2) {
|
||||||
Object* key = cache->get(i);
|
Object* key = cache->get(i);
|
||||||
if (key->IsUndefined()) {
|
if (key->IsUndefined()) {
|
||||||
continue;
|
return key;
|
||||||
}
|
}
|
||||||
if (name->Equals(String::cast(key))) {
|
if (name->Equals(String::cast(key))) {
|
||||||
Code* code = Code::cast(cache->get(i + 1));
|
Code* code = Code::cast(cache->get(i + 1));
|
||||||
if (code->flags() == flags) {
|
if (code->flags() == flags) return code;
|
||||||
*index = i + 1;
|
|
||||||
return code;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*index = -1;
|
|
||||||
return Heap::undefined_value();
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
|
void FixedArray::FixedArrayIterateBody(ObjectVisitor* v) {
|
||||||
IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
|
IteratePointers(v, kHeaderSize, kHeaderSize + length() * kPointerSize);
|
||||||
}
|
}
|
||||||
|
@ -2342,14 +2342,14 @@ class Map: public HeapObject {
|
|||||||
Object* UpdateCodeCache(String* name, Code* code);
|
Object* UpdateCodeCache(String* name, Code* code);
|
||||||
|
|
||||||
// Returns the found code or undefined if absent.
|
// 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
|
// Returns the non-negative index of the code object if it is in the
|
||||||
// index at which the code was found or -1 if absent.
|
// cache and -1 otherwise.
|
||||||
Object* FindIndexInCodeCache(String* name, Code::Flags flags, int* index);
|
int IndexInCodeCache(Code* code);
|
||||||
|
|
||||||
// Removes a code object from the code cache at the given index.
|
// Removes a code object from the code cache at the given index.
|
||||||
inline void RemoveFromCodeCache(int index);
|
void RemoveFromCodeCache(int index);
|
||||||
|
|
||||||
// Dispatched behavior.
|
// Dispatched behavior.
|
||||||
void MapIterateBody(ObjectVisitor* v);
|
void MapIterateBody(ObjectVisitor* v);
|
||||||
|
Loading…
Reference in New Issue
Block a user