Index: src/ic.cc |
=================================================================== |
--- src/ic.cc (revision 2034) |
+++ src/ic.cc (working copy) |
@@ -38,10 +38,9 @@ |
namespace v8 { namespace internal { |
#ifdef DEBUG |
-static char TransitionMarkFromState(IC::State state) { |
+static const char TransitionMarkFromState(IC::State state) { |
switch (state) { |
case UNINITIALIZED: return '0'; |
- case UNINITIALIZED_IN_LOOP: return 'L'; |
case PREMONOMORPHIC: return 'P'; |
case MONOMORPHIC: return '1'; |
case MONOMORPHIC_PROTOTYPE_FAILURE: return '^'; |
@@ -60,12 +59,14 @@ |
void IC::TraceIC(const char* type, |
Handle<String> name, |
State old_state, |
- Code* new_target) { |
+ Code* new_target, |
+ const char* extra_info) { |
if (FLAG_trace_ic) { |
State new_state = StateFrom(new_target, Heap::undefined_value()); |
- PrintF("[%s (%c->%c) ", type, |
+ PrintF("[%s (%c->%c)%s", type, |
TransitionMarkFromState(old_state), |
- TransitionMarkFromState(new_state)); |
+ TransitionMarkFromState(new_state), |
+ extra_info); |
name->Print(); |
PrintF("]\n"); |
} |
@@ -226,8 +227,10 @@ |
void CallIC::Clear(Address address, Code* target) { |
State state = target->ic_state(); |
- if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP) return; |
- Code* code = StubCache::FindCallInitialize(target->arguments_count()); |
+ InlineCacheInLoop in_loop = target->ic_in_loop(); |
+ if (state == UNINITIALIZED) return; |
+ Code* code = |
+ StubCache::FindCallInitialize(target->arguments_count(), in_loop); |
SetTargetAtAddress(address, code); |
} |
@@ -390,21 +393,22 @@ |
// Compute the number of arguments. |
int argc = target()->arguments_count(); |
+ InlineCacheInLoop in_loop = target()->ic_in_loop(); |
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 = StubCache::ComputeCallPreMonomorphic(argc); |
+ code = StubCache::ComputeCallPreMonomorphic(argc, in_loop); |
} else if (state == MONOMORPHIC) { |
- code = StubCache::ComputeCallMegamorphic(argc); |
+ code = StubCache::ComputeCallMegamorphic(argc, in_loop); |
} else { |
// Compute monomorphic stub. |
switch (lookup->type()) { |
case FIELD: { |
int index = lookup->GetFieldIndex(); |
- code = StubCache::ComputeCallField(argc, *name, *object, |
+ code = StubCache::ComputeCallField(argc, in_loop, *name, *object, |
lookup->holder(), index); |
break; |
} |
@@ -413,7 +417,7 @@ |
// 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, |
+ code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object, |
lookup->holder(), function); |
break; |
} |
@@ -425,7 +429,7 @@ |
if (!object->IsJSObject()) return; |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
if (lookup->holder() != *receiver) return; |
- code = StubCache::ComputeCallNormal(argc, *name, *receiver); |
+ code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); |
break; |
} |
case INTERCEPTOR: { |
@@ -443,14 +447,14 @@ |
if (code->IsFailure()) return; |
// Patch the call site depending on the state of the cache. |
- if (state == UNINITIALIZED || state == UNINITIALIZED_IN_LOOP || |
+ if (state == UNINITIALIZED || |
state == PREMONOMORPHIC || state == MONOMORPHIC || |
Kevin Millikin (Chromium)
2009/05/25 11:00:42
One disjunct per line?
|
state == MONOMORPHIC_PROTOTYPE_FAILURE) { |
set_target(Code::cast(code)); |
} |
#ifdef DEBUG |
- TraceIC("CallIC", name, state, target()); |
+ TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : ""); |
#endif |
} |
@@ -1088,14 +1092,27 @@ |
IC::State state = IC::StateFrom(ic.target(), args[0]); |
Object* result = |
ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); |
- if (state != UNINITIALIZED_IN_LOOP || !result->IsJSFunction()) |
+ |
+ // 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 |
+ // then the first call will trigger a compilation. We check for this case |
+ // and we do the compilation immediately, instead of waiting for the stub |
+ // currently attached to the JSFunction object to trigger compilation. We |
+ // do this in the case where we know that the inline cache is inside a loop, |
+ // because then we know that we want to optimize the function. |
+ if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
return result; |
+ } |
- // Compile the function with the knowledge that it's called from |
- // within a loop. This enables further optimization of the function. |
+ // Compile now with optimization. |
HandleScope scope; |
Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); |
- if (!function->is_compiled()) CompileLazyInLoop(function, CLEAR_EXCEPTION); |
+ InlineCacheInLoop in_loop = ic.target()->ic_in_loop(); |
+ if (in_loop) { |
Kevin Millikin (Chromium)
2009/05/25 11:00:42
if (in_loop == IN_LOOP) ....
|
+ CompileLazyInLoop(function, CLEAR_EXCEPTION); |
+ } else { |
+ CompileLazy(function, CLEAR_EXCEPTION); |
+ } |
return *function; |
} |