| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 50b1cde888d769b675d6eee89d5a27819d77c1c0..92c2681a2ffbbb938669155852d993df8359e054 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -1243,7 +1243,7 @@ MaybeObject* KeyedLoadIC::Load(State state,
|
| stub = indexed_interceptor_stub();
|
| } else if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| MaybeObject* maybe_stub = ComputeStub(receiver,
|
| - false,
|
| + LOAD,
|
| kNonStrictMode,
|
| stub);
|
| stub = maybe_stub->IsFailure() ?
|
| @@ -1593,14 +1593,15 @@ void KeyedIC::GetReceiverMapsForStub(Code* stub, MapList* result) {
|
|
|
|
|
| MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
|
| - bool is_store,
|
| + StubKind stub_kind,
|
| StrictModeFlag strict_mode,
|
| Code* generic_stub) {
|
| State ic_state = target()->ic_state();
|
| - if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
|
| + if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) &&
|
| + !IsTransitionStubKind(stub_kind)) {
|
| Code* monomorphic_stub;
|
| MaybeObject* maybe_stub = ComputeMonomorphicStub(receiver,
|
| - is_store,
|
| + stub_kind,
|
| strict_mode,
|
| generic_stub);
|
| if (!maybe_stub->To(&monomorphic_stub)) return maybe_stub;
|
| @@ -1619,8 +1620,17 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
|
| // Determine the list of receiver maps that this call site has seen,
|
| // adding the map that was just encountered.
|
| MapList target_receiver_maps;
|
| - GetReceiverMapsForStub(target(), &target_receiver_maps);
|
| - if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map())) {
|
| + if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
|
| + target_receiver_maps.Add(receiver->map());
|
| + } else {
|
| + GetReceiverMapsForStub(target(), &target_receiver_maps);
|
| + }
|
| + Map* new_map = receiver->map();
|
| + if (IsTransitionStubKind(stub_kind)) {
|
| + MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind);
|
| + if (!maybe_map->To(&new_map)) return maybe_map;
|
| + }
|
| + if (!AddOneReceiverMapIfMissing(&target_receiver_maps, new_map)) {
|
| // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub
|
| // won't help, use the generic stub.
|
| return generic_stub;
|
| @@ -1642,21 +1652,14 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver,
|
| ASSERT(maybe_cached_stub->IsCode());
|
| return Code::cast(maybe_cached_stub);
|
| }
|
| - // Collect MONOMORPHIC stubs for all target_receiver_maps.
|
| - CodeList handler_ics(target_receiver_maps.length());
|
| - for (int i = 0; i < target_receiver_maps.length(); ++i) {
|
| - Map* receiver_map(target_receiver_maps.at(i));
|
| - MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
|
| - receiver_map, strict_mode);
|
| - Code* cached_stub;
|
| - if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
|
| - handler_ics.Add(cached_stub);
|
| + MaybeObject* maybe_stub = NULL;
|
| + if (IsTransitionStubKind(stub_kind)) {
|
| + maybe_stub = ComputePolymorphicStubWithTransition(
|
| + receiver, &target_receiver_maps, new_map, strict_mode);
|
| + } else {
|
| + maybe_stub = ComputePolymorphicStub(&target_receiver_maps, strict_mode);
|
| }
|
| - // Build the MEGAMORPHIC stub.
|
| Code* stub;
|
| - MaybeObject* maybe_stub = ConstructMegamorphicStub(&target_receiver_maps,
|
| - &handler_ics,
|
| - strict_mode);
|
| if (!maybe_stub->To(&stub)) return maybe_stub;
|
| MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub);
|
| if (maybe_update->IsFailure()) return maybe_update;
|
| @@ -1684,7 +1687,7 @@ MaybeObject* KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
|
|
|
|
|
| MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
|
| - bool is_store,
|
| + StubKind stub_kind,
|
| StrictModeFlag strict_mode,
|
| Code* generic_stub) {
|
| Code* result = NULL;
|
| @@ -1695,7 +1698,7 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
|
| receiver->HasDictionaryElements()) {
|
| MaybeObject* maybe_stub =
|
| isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
|
| - receiver, is_store, strict_mode);
|
| + receiver, stub_kind, strict_mode);
|
| if (!maybe_stub->To(&result)) return maybe_stub;
|
| } else {
|
| result = generic_stub;
|
| @@ -1704,6 +1707,60 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver,
|
| }
|
|
|
|
|
| +MaybeObject* KeyedIC::ComputePolymorphicStubWithTransition(
|
| + JSObject* receiver,
|
| + MapList* receiver_maps,
|
| + Map* new_map,
|
| + StrictModeFlag strict_mode) {
|
| + Map* existing_transitionable_map = NULL;
|
| + for (int i = 0; i < receiver_maps->length(); ++i) {
|
| + Map* map = receiver_maps->at(i);
|
| + if (map != receiver->map() && map != new_map) {
|
| + existing_transitionable_map = map;
|
| + break;
|
| + }
|
| + }
|
| + KeyedStoreStubCompiler compiler(strict_mode);
|
| + return compiler.CompileStoreElementWithTransition(
|
| + new_map,
|
| + receiver->map(),
|
| + existing_transitionable_map);
|
| +}
|
| +
|
| +
|
| +MaybeObject* KeyedIC::ComputePolymorphicStub(
|
| + MapList* receiver_maps,
|
| + StrictModeFlag strict_mode) {
|
| + // Collect MONOMORPHIC stubs for all target_receiver_maps.
|
| + CodeList handler_ics(receiver_maps->length());
|
| + for (int i = 0; i < receiver_maps->length(); ++i) {
|
| + Map* receiver_map(receiver_maps->at(i));
|
| + MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck(
|
| + receiver_map, strict_mode);
|
| + Code* cached_stub;
|
| + if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub;
|
| + handler_ics.Add(cached_stub);
|
| + }
|
| + // Build the MEGAMORPHIC stub.
|
| + return ConstructMegamorphicStub(receiver_maps, &handler_ics, strict_mode);
|
| +}
|
| +
|
| +
|
| +MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver,
|
| + StubKind stub_kind) {
|
| + switch (stub_kind) {
|
| + case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT:
|
| + case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT:
|
| + return receiver->GetElementsTransitionMap(FAST_ELEMENTS);
|
| + case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
|
| + return receiver->GetElementsTransitionMap(FAST_DOUBLE_ELEMENTS);
|
| + default:
|
| + UNREACHABLE();
|
| + return NULL;
|
| + }
|
| +}
|
| +
|
| +
|
| MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck(
|
| bool is_js_array,
|
| ElementsKind elements_kind) {
|
| @@ -1786,9 +1843,21 @@ MaybeObject* KeyedStoreIC::Store(State state,
|
| stub = non_strict_arguments_stub();
|
| } else if (!force_generic) {
|
| if (key->IsSmi() && (target() != non_strict_arguments_stub())) {
|
| + StubKind stub_kind = STORE_NO_TRANSITION;
|
| + if (receiver->GetElementsKind() == FAST_SMI_ONLY_ELEMENTS) {
|
| + if (value->IsHeapNumber()) {
|
| + stub_kind = STORE_TRANSITION_SMI_TO_DOUBLE;
|
| + } else if (value->IsHeapObject()) {
|
| + stub_kind = STORE_TRANSITION_SMI_TO_OBJECT;
|
| + }
|
| + } else if (receiver->GetElementsKind() == FAST_DOUBLE_ELEMENTS) {
|
| + if (!value->IsSmi() && !value->IsHeapNumber()) {
|
| + stub_kind = STORE_TRANSITION_DOUBLE_TO_OBJECT;
|
| + }
|
| + }
|
| HandleScope scope(isolate());
|
| MaybeObject* maybe_stub = ComputeStub(receiver,
|
| - true,
|
| + stub_kind,
|
| strict_mode,
|
| stub);
|
| stub = maybe_stub->IsFailure() ?
|
|
|