| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 8b3b4723fe215f6ad68566d6a7c3ed70067c3e14..8c7acc7e29069c36602fa101b31fb9c720a6122f 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -712,7 +712,6 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
|
|
|
| // Compute the number of arguments.
|
| int argc = target()->arguments_count();
|
| - bool had_proto_failure = false;
|
| Handle<Code> code;
|
| if (state == UNINITIALIZED) {
|
| // This is the first time we execute this inline cache.
|
| @@ -729,7 +728,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
|
| TryRemoveInvalidPrototypeDependentStub(target(),
|
| *object,
|
| *name)) {
|
| - had_proto_failure = true;
|
| + state = MONOMORPHIC_PROTOTYPE_FAILURE;
|
| code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
|
| object, name);
|
| } else {
|
| @@ -745,22 +744,36 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
|
| if (code.is_null()) return;
|
|
|
| // Patch the call site depending on the state of the cache.
|
| - if (state == UNINITIALIZED ||
|
| - state == PREMONOMORPHIC ||
|
| - state == MONOMORPHIC ||
|
| - state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
| - set_target(*code);
|
| - } else if (state == MEGAMORPHIC) {
|
| - // Cache code holding map should be consistent with
|
| - // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
|
| - Handle<JSObject> cache_object = object->IsJSObject()
|
| - ? Handle<JSObject>::cast(object)
|
| - : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
|
| - // Update the stub cache.
|
| - isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
|
| - }
|
| -
|
| - if (had_proto_failure) state = MONOMORPHIC_PROTOTYPE_FAILURE;
|
| + switch (state) {
|
| + case UNINITIALIZED:
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + case PREMONOMORPHIC:
|
| + set_target(*code);
|
| + break;
|
| + case MONOMORPHIC:
|
| + if (code->ic_state() != MONOMORPHIC) {
|
| + Map* map = target()->FindFirstMap();
|
| + if (map != NULL) {
|
| + isolate()->stub_cache()->Set(*name, map, target());
|
| + }
|
| + }
|
| + set_target(*code);
|
| + break;
|
| + case MEGAMORPHIC: {
|
| + // Cache code holding map should be consistent with
|
| + // GenerateMonomorphicCacheProbe. It is not the map which holds the stub.
|
| + Handle<JSObject> cache_object = object->IsJSObject()
|
| + ? Handle<JSObject>::cast(object)
|
| + : Handle<JSObject>(JSObject::cast(object->GetPrototype()));
|
| + // Update the stub cache.
|
| + isolate()->stub_cache()->Set(*name, cache_object->map(), *code);
|
| + break;
|
| + }
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + break;
|
| + }
|
| +
|
| TRACE_IC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC",
|
| name, state, target());
|
| }
|
| @@ -1024,25 +1037,34 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
|
| }
|
|
|
| // Patch the call site depending on the state of the cache.
|
| - if (state == UNINITIALIZED ||
|
| - state == PREMONOMORPHIC ||
|
| - state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
| - set_target(*code);
|
| - } else if (state == MONOMORPHIC) {
|
| - // We are transitioning from monomorphic to megamorphic case.
|
| - // Place the current monomorphic stub and stub compiled for
|
| - // the receiver into stub cache.
|
| - Map* map = target()->FindFirstMap();
|
| - if (map != NULL) {
|
| - isolate()->stub_cache()->Set(*name, map, target());
|
| - }
|
| - isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + switch (state) {
|
| + case UNINITIALIZED:
|
| + case PREMONOMORPHIC:
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + set_target(*code);
|
| + break;
|
| + case MONOMORPHIC:
|
| + if (target() != *code) {
|
| + // We are transitioning from monomorphic to megamorphic case.
|
| + // Place the current monomorphic stub and stub compiled for
|
| + // the receiver into stub cache.
|
| + Map* map = target()->FindFirstMap();
|
| + if (map != NULL) {
|
| + isolate()->stub_cache()->Set(*name, map, target());
|
| + }
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
|
|
| - set_target(*megamorphic_stub());
|
| - } else if (state == MEGAMORPHIC) {
|
| - // Cache code holding map should be consistent with
|
| - // GenerateMonomorphicCacheProbe.
|
| - isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + set_target(*megamorphic_stub());
|
| + }
|
| + break;
|
| + case MEGAMORPHIC:
|
| + // Cache code holding map should be consistent with
|
| + // GenerateMonomorphicCacheProbe.
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + break;
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + break;
|
| }
|
|
|
| TRACE_IC("LoadIC", name, state, target());
|
| @@ -1296,13 +1318,25 @@ void KeyedLoadIC::UpdateCaches(LookupResult* lookup,
|
| }
|
| }
|
|
|
| - // Patch the call site depending on the state of the cache. Make
|
| - // sure to always rewrite from monomorphic to megamorphic.
|
| - ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
|
| - if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
|
| - set_target(*code);
|
| - } else if (state == MONOMORPHIC) {
|
| - set_target(*megamorphic_stub());
|
| + // Patch the call site depending on the state of the cache.
|
| + switch (state) {
|
| + case UNINITIALIZED:
|
| + case PREMONOMORPHIC:
|
| + set_target(*code);
|
| + break;
|
| + case MONOMORPHIC:
|
| + // Only move to megamorphic if the target changes.
|
| + if (target() != *code) {
|
| + set_target(*megamorphic_stub());
|
| + }
|
| + break;
|
| + case MEGAMORPHIC:
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + break;
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| TRACE_IC("KeyedLoadIC", name, state, target());
|
| @@ -1547,18 +1581,35 @@ void StoreIC::UpdateCaches(LookupResult* lookup,
|
| }
|
|
|
| // Patch the call site depending on the state of the cache.
|
| - if (state == UNINITIALIZED || state == MONOMORPHIC_PROTOTYPE_FAILURE) {
|
| - set_target(*code);
|
| - } else if (state == MONOMORPHIC) {
|
| - // Only move to megamorphic if the target changes.
|
| - if (target() != *code) {
|
| - set_target((strict_mode == kStrictMode)
|
| - ? megamorphic_stub_strict()
|
| - : megamorphic_stub());
|
| - }
|
| - } else if (state == MEGAMORPHIC) {
|
| - // Update the stub cache.
|
| - isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + switch (state) {
|
| + case UNINITIALIZED:
|
| + case PREMONOMORPHIC:
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + set_target(*code);
|
| + break;
|
| + case MONOMORPHIC:
|
| + // Only move to megamorphic if the target changes.
|
| + if (target() != *code) {
|
| + // We are transitioning from monomorphic to megamorphic case.
|
| + // Place the current monomorphic stub and stub compiled for
|
| + // the receiver into stub cache.
|
| + Map* map = target()->FindFirstMap();
|
| + if (map != NULL) {
|
| + isolate()->stub_cache()->Set(*name, map, target());
|
| + }
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + set_target((strict_mode == kStrictMode)
|
| + ? megamorphic_stub_strict()
|
| + : megamorphic_stub());
|
| + }
|
| + break;
|
| + case MEGAMORPHIC:
|
| + // Update the stub cache.
|
| + isolate()->stub_cache()->Set(*name, receiver->map(), *code);
|
| + break;
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + break;
|
| }
|
|
|
| TRACE_IC("StoreIC", name, state, target());
|
| @@ -1585,18 +1636,28 @@ void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub,
|
| if (!string_stub().is_null() && stub.is_identical_to(string_stub())) {
|
| return result->Add(isolate()->factory()->string_map());
|
| } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
|
| - if (stub->ic_state() == MONOMORPHIC) {
|
| - result->Add(Handle<Map>(stub->FindFirstMap()));
|
| - } else {
|
| - ASSERT(stub->ic_state() == MEGAMORPHIC);
|
| - AssertNoAllocation no_allocation;
|
| - int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
| - for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
|
| - RelocInfo* info = it.rinfo();
|
| - Handle<Object> object(info->target_object());
|
| - ASSERT(object->IsMap());
|
| - AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
|
| + switch (stub->ic_state()) {
|
| + case MONOMORPHIC:
|
| + result->Add(Handle<Map>(stub->FindFirstMap()));
|
| + break;
|
| + case MEGAMORPHIC: {
|
| + AssertNoAllocation no_allocation;
|
| + int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
|
| + for (RelocIterator it(*stub, mask); !it.done(); it.next()) {
|
| + RelocInfo* info = it.rinfo();
|
| + Handle<Object> object(info->target_object());
|
| + ASSERT(object->IsMap());
|
| + AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
|
| + }
|
| + break;
|
| }
|
| + case UNINITIALIZED:
|
| + case PREMONOMORPHIC:
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
| }
|
| }
|
| @@ -2024,15 +2085,27 @@ void KeyedStoreIC::UpdateCaches(LookupResult* lookup,
|
|
|
| ASSERT(!code.is_null());
|
|
|
| - // Patch the call site depending on the state of the cache. Make
|
| - // sure to always rewrite from monomorphic to megamorphic.
|
| - ASSERT(state != MONOMORPHIC_PROTOTYPE_FAILURE);
|
| - if (state == UNINITIALIZED || state == PREMONOMORPHIC) {
|
| - set_target(*code);
|
| - } else if (state == MONOMORPHIC) {
|
| - set_target((strict_mode == kStrictMode)
|
| - ? *megamorphic_stub_strict()
|
| - : *megamorphic_stub());
|
| + // Patch the call site depending on the state of the cache.
|
| + switch (state) {
|
| + case UNINITIALIZED:
|
| + case PREMONOMORPHIC:
|
| + set_target(*code);
|
| + break;
|
| + case MONOMORPHIC:
|
| + // Only move to megamorphic if the target changes.
|
| + if (target() != *code) {
|
| + set_target((strict_mode == kStrictMode)
|
| + ? *megamorphic_stub_strict()
|
| + : *megamorphic_stub());
|
| + }
|
| + break;
|
| + case MEGAMORPHIC:
|
| + case DEBUG_BREAK:
|
| + case DEBUG_PREPARE_STEP_IN:
|
| + break;
|
| + case MONOMORPHIC_PROTOTYPE_FAILURE:
|
| + UNREACHABLE();
|
| + break;
|
| }
|
|
|
| TRACE_IC("KeyedStoreIC", name, state, target());
|
| @@ -2057,13 +2130,12 @@ RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
|
| extra_ic_state,
|
| args.at<Object>(0),
|
| args.at<String>(1));
|
| - // Result could be a function or a failure.
|
| - JSFunction* raw_function = NULL;
|
| + JSFunction* raw_function;
|
| if (!maybe_result->To(&raw_function)) 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 is lazily compiled
|
| - // then the first call will trigger a compilation. We check for this case
|
| + // function it references gets called. If the function is 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.
|
| if (raw_function->is_compiled()) return raw_function;
|
|
|