| 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));
|
| }
|
|
|
|
|
|
|