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

Unified Diff: src/ic.cc

Issue 6344005: Introduce extra IC state to record additional feedback from IC-s. (Closed)
Patch Set: Moved the logic to runtime Created 9 years, 11 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
« src/ia32/stub-cache-ia32.cc ('K') | « src/ic.h ('k') | src/objects.h » ('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 645c6fdcf6542304d6b67901e1c649ede62a566e..67af1243dff0350a981a8911b3d97cd930d4394e 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -154,24 +154,20 @@ static bool HasNormalObjectsInPrototypeChain(LookupResult* lookup,
}
-IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
- IC::State state = target->ic_state();
-
- if (state != MONOMORPHIC || !name->IsString()) return state;
- if (receiver->IsUndefined() || receiver->IsNull()) return state;
-
+static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
+ Object* receiver,
+ Object* name) {
InlineCacheHolderFlag cache_holder =
Code::ExtractCacheHolderFromFlags(target->flags());
-
if (cache_holder == OWN_MAP && !receiver->IsJSObject()) {
// The stub was generated for JSObject but called for non-JSObject.
// IC::GetCodeCacheHolder is not applicable.
- return MONOMORPHIC;
+ return false;
} else if (cache_holder == PROTOTYPE_MAP &&
receiver->GetPrototype()->IsNull()) {
// IC::GetCodeCacheHolder is not applicable.
- return MONOMORPHIC;
+ return false;
}
Map* map = IC::GetCodeCacheHolder(receiver, cache_holder)->map();
@@ -185,20 +181,37 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
// to prototype check failure.
int index = map->IndexInCodeCache(name, target);
if (index >= 0) {
- // For keyed load/store/call, 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.
- Code::Kind kind = target->kind();
- if (kind == Code::KEYED_LOAD_IC ||
- kind == Code::KEYED_STORE_IC ||
- kind == Code::KEYED_CALL_IC) {
- return MONOMORPHIC;
- }
-
- // Remove the target from the code cache to avoid hitting the same
- // invalid stub again.
map->RemoveFromCodeCache(String::cast(name), target, index);
+ return true;
+ }
+
+ return false;
+}
+
+
+IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
+ IC::State state = target->ic_state();
+
+ if (state != MONOMORPHIC || !name->IsString()) return state;
+ if (receiver->IsUndefined() || receiver->IsNull()) return state;
+
+ // For keyed load/store/call, 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.
+ Code::Kind kind = target->kind();
+ if (kind == Code::KEYED_LOAD_IC ||
+ kind == Code::KEYED_STORE_IC ||
+ kind == Code::KEYED_CALL_IC) {
+ return MONOMORPHIC;
+ }
+ // Remove the target from the code cache if it became invalid
+ // because of changes in the prototype chain to avoid hitting it
+ // again.
+ // Call stubs handle this later to allow extra IC state
+ // transitions.
+ if (kind != Code::CALL_IC &&
+ TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
return MONOMORPHIC_PROTOTYPE_FAILURE;
}
@@ -482,6 +495,7 @@ void CallICBase::ReceiverToObject(Handle<Object> object) {
MaybeObject* CallICBase::LoadFunction(State state,
+ Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name) {
// If the object is undefined or null it's illegal to try to get any
@@ -527,7 +541,7 @@ MaybeObject* CallICBase::LoadFunction(State state,
// Lookup is valid: Update inline cache and stub cache.
if (FLAG_use_ic) {
- UpdateCaches(&lookup, state, object, name);
+ UpdateCaches(&lookup, state, extra_ic_state, object, name);
}
// Get the property.
@@ -576,8 +590,57 @@ MaybeObject* CallICBase::LoadFunction(State state,
}
+bool CallICBase::TryUpdateExtraICState(LookupResult* lookup,
+ Handle<Object> object,
+ Code::ExtraICState* extra_ic_state) {
+ ASSERT(kind_ == Code::CALL_IC);
+ if (lookup->type() != CONSTANT_FUNCTION) return false;
+ JSFunction* function = lookup->GetConstantFunction();
+ if (!function->shared()->HasBuiltinFunctionId()) return false;
+
+ // Fetch the arguments passed to the called function.
+ const int argc = target()->arguments_count();
+ Address entry = Top::c_entry_fp(Top::GetCurrentThread());
+ Address fp = Memory::Address_at(entry + ExitFrameConstants::kCallerFPOffset);
+ Arguments args(argc + 1,
+ &Memory::Object_at(fp +
+ StandardFrameConstants::kCallerSPOffset +
+ argc * kPointerSize));
+ switch (function->shared()->builtin_function_id()) {
+ case kStringCharCodeAt:
+ case kStringCharAt:
+ if (object->IsString()) {
+ String* string = String::cast(*object);
+ // Check that there's the right wrapper in the receiver slot.
+ ASSERT(string == JSValue::cast(args[0])->value());
+ // If we're in the default (fastest) state and the index is
+ // out of bounds, update the state to record this fact.
+ if (*extra_ic_state == DEFAULT_STRING_STUB &&
+ argc >= 1 && args[1]->IsNumber()) {
+ double index;
+ if (args[1]->IsSmi()) {
+ index = Smi::cast(args[1])->value();
+ } else {
+ ASSERT(args[1]->IsHeapNumber());
+ index = DoubleToInteger(HeapNumber::cast(args[1])->value());
+ }
+ if (index < 0 || index >= string->length()) {
+ *extra_ic_state = STRING_INDEX_OUT_OF_BOUNDS;
+ return true;
+ }
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+ return false;
+}
+
+
void CallICBase::UpdateCaches(LookupResult* lookup,
State state,
+ Code::ExtraICState extra_ic_state,
Handle<Object> object,
Handle<String> name) {
// Bail out if we didn't find a result.
@@ -590,6 +653,17 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
return;
}
+
+ if (kind_ == Code::CALL_IC && state == MONOMORPHIC) {
Mads Ager (chromium) 2011/01/18 11:28:57 Why isn't this just part of the normal MONOMORPHIC
Vitaly Repeshko 2011/01/18 12:13:46 Because we change the state to PREMONORPHIC to gen
+ if (TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
+ state = PREMONOMORPHIC;
+ } else if (TryRemoveInvalidPrototypeDependentStub(target(),
+ *object,
+ *name)) {
+ state = MONOMORPHIC_PROTOTYPE_FAILURE;
+ }
+ }
+
// Compute the number of arguments.
int argc = target()->arguments_count();
InLoopFlag in_loop = target()->ic_in_loop();
@@ -624,6 +698,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
maybe_code = StubCache::ComputeCallConstant(argc,
in_loop,
kind_,
+ extra_ic_state,
*name,
*object,
lookup->holder(),
@@ -707,7 +782,10 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
Handle<Object> object,
Handle<Object> key) {
if (key->IsSymbol()) {
- return CallICBase::LoadFunction(state, object, Handle<String>::cast(key));
+ return CallICBase::LoadFunction(state,
+ Code::kNoExtraICState,
+ object,
+ Handle<String>::cast(key));
}
if (object->IsUndefined() || object->IsNull()) {
@@ -1638,14 +1716,28 @@ static JSFunction* CompileFunction(JSFunction* function,
// Used from ic-<arch>.cc.
MUST_USE_RESULT MaybeObject* CallIC_Miss(Arguments args) {
NoHandleAllocation na;
- ASSERT(args.length() == 2);
+ ASSERT(args.length() == 2 || args.length() == 3);
Mads Ager (chromium) 2011/01/18 11:28:57 Why do you need to pass the extra state to the mis
CallIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
+ IC::State state;
+ Code::ExtraICState extra_ic_state;
+ if (args.length() == 2) {
+ state = IC::StateFrom(ic.target(), args[0], args[1]);
+ extra_ic_state = Code::kNoExtraICState;
+ } else {
+ ASSERT(args.length() == 3);
+ ASSERT(ic.target()->ic_state() == MONOMORPHIC);
+ // Extra IC state change is requested. Use PREMONOMORPHIC to
+ // trigger generating a new stub.
+ state = PREMONOMORPHIC;
+ extra_ic_state = static_cast<Code::ExtraICState>(
+ Smi::cast(args[2])->value());
+ }
+ MaybeObject* maybe_result = ic.LoadFunction(state,
+ extra_ic_state,
+ args.at<Object>(0),
+ args.at<String>(1));
Object* result;
- { MaybeObject* maybe_result =
- ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
- if (!maybe_result->ToObject(&result)) return maybe_result;
- }
+ if (!maybe_result->ToObject(&result)) return maybe_result;
// The first time the inline cache is updated may be the first time the
// function it references gets called. If the function was lazily compiled
« src/ia32/stub-cache-ia32.cc ('K') | « src/ic.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698