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

Unified Diff: src/ic.cc

Issue 12390031: Unify grow mode and stub kind (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review feedback Created 7 years, 9 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
« no previous file with comments | « src/ic.h ('k') | src/mips/stub-cache-mips.cc » ('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 7fdf6be31fbe5f36f53a22182371963d5e212be1..33cd3cb53b7055dbb4808e94d1576cc371ff5275 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -59,6 +59,17 @@ char IC::TransitionMarkFromState(IC::State state) {
return 0;
}
+
+const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
+ if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
+ if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
+ return ".IGNORE_OOB";
+ }
+ if (IsGrowStoreMode(mode)) return ".GROW";
+ return "";
+}
+
+
void IC::TraceIC(const char* type,
Handle<Object> name,
State old_state,
@@ -81,13 +92,13 @@ void IC::TraceIC(const char* type,
}
}
JavaScriptFrame::PrintTop(isolate, stdout, false, true);
- bool new_can_grow =
- Code::GetKeyedAccessGrowMode(new_target->extra_ic_state()) ==
- ALLOW_JSARRAY_GROWTH;
+ Code::ExtraICState state = new_target->extra_ic_state();
+ const char* modifier =
+ GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(state));
PrintF(" (%c->%c%s)",
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state),
- new_can_grow ? ".GROW" : "");
+ modifier);
name->Print();
PrintF("]\n");
}
@@ -1602,13 +1613,8 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
- StubKind stub_kind,
+ KeyedAccessStoreMode store_mode,
StrictModeFlag strict_mode) {
- State ic_state = target()->ic_state();
- KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind)
- ? ALLOW_JSARRAY_GROWTH
- : DO_NOT_ALLOW_JSARRAY_GROWTH;
-
// Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
// via megamorphic stubs, since they don't have a map in their relocation info
// and so the stubs can't be harvested for the object needed for a map check.
@@ -1617,42 +1623,76 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
}
+ if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW ||
+ store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS)) {
+ // TODO(danno): We'll soon handle MONOMORPHIC ICs that also support
+ // copying COW arrays and silently ignoring some OOB stores into external
+ // arrays, but for now use the generic.
+ TRACE_GENERIC_IC(isolate(), "KeyedIC", "COW/OOB external array");
+ return strict_mode == kStrictMode
+ ? generic_stub_strict()
+ : generic_stub();
+ }
+
+ State ic_state = target()->ic_state();
Handle<Map> receiver_map(receiver->map());
- MapHandleList target_receiver_maps;
if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
// Optimistically assume that ICs that haven't reached the MONOMORPHIC state
// yet will do so and stay there.
- Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
- stub_kind = GetNoTransitionStubKind(stub_kind);
+ Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
+ store_mode = GetNonTransitioningStoreMode(store_mode);
return isolate()->stub_cache()->ComputeKeyedStoreElement(
- monomorphic_map, stub_kind, strict_mode, grow_mode);
+ monomorphic_map, strict_mode, store_mode);
}
- GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+ MapHandleList target_receiver_maps;
+ target()->FindAllMaps(&target_receiver_maps);
if (target_receiver_maps.length() == 0) {
- // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
- // yet will do so and stay there.
- stub_kind = GetNoTransitionStubKind(stub_kind);
- return isolate()->stub_cache()->ComputeKeyedStoreElement(
- receiver_map, stub_kind, strict_mode, grow_mode);
+ // In the case that there is a non-map-specific IC is installed (e.g. keyed
+ // stores into properties in dictionary mode), then there will be not
+ // receiver maps in the target.
+ return strict_mode == kStrictMode
+ ? generic_stub_strict()
+ : generic_stub();
}
- // The first time a receiver is seen that is a transitioned version of the
- // previous monomorphic receiver type, assume the new ElementsKind is the
- // monomorphic type. This benefits global arrays that only transition
- // once, and all call sites accessing them are faster if they remain
- // monomorphic. If this optimistic assumption is not true, the IC will
- // miss again and it will become polymorphic and support both the
- // untransitioned and transitioned maps.
- if (ic_state == MONOMORPHIC &&
- IsTransitionStubKind(stub_kind) &&
- IsMoreGeneralElementsKindTransition(
- target_receiver_maps.at(0)->elements_kind(),
- receiver->GetElementsKind())) {
- Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
- ASSERT(*monomorphic_map != *receiver_map);
- stub_kind = GetNoTransitionStubKind(stub_kind);
- return isolate()->stub_cache()->ComputeKeyedStoreElement(
- monomorphic_map, stub_kind, strict_mode, grow_mode);
+
+ // There are several special cases where an IC that is MONOMORPHIC can still
+ // transition to a different GetNonTransitioningStoreMode IC that handles a
+ // superset of the original IC. Handle those here if the receiver map hasn't
+ // changed or it has transitioned to a more general kind.
+ KeyedAccessStoreMode old_store_mode =
+ Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
+ Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
+ if (ic_state == MONOMORPHIC && old_store_mode == STANDARD_STORE) {
+ // If the "old" and "new" maps are in the same elements map family, stay
+ // MONOMORPHIC and use the map for the most generic ElementsKind.
+ Handle<Map> transitioned_receiver_map = receiver_map;
+ if (IsTransitionStoreMode(store_mode)) {
+ transitioned_receiver_map =
+ ComputeTransitionedMap(receiver, store_mode);
+ }
+ ElementsKind transitioned_kind =
+ transitioned_receiver_map->elements_kind();
+ bool more_general_transition =
+ IsMoreGeneralElementsKindTransition(
+ previous_receiver_map->elements_kind(),
+ transitioned_kind);
+ Map* transitioned_previous_map = more_general_transition
+ ? previous_receiver_map->LookupElementsTransitionMap(transitioned_kind)
+ : NULL;
+ if (transitioned_previous_map == *transitioned_receiver_map) {
+ // Element family is the same, use the "worst" case map.
+ store_mode = GetNonTransitioningStoreMode(store_mode);
+ return isolate()->stub_cache()->ComputeKeyedStoreElement(
+ transitioned_receiver_map, strict_mode, store_mode);
+ } else if (*previous_receiver_map == receiver->map()) {
+ if (IsGrowStoreMode(store_mode)) {
+ // A "normal" IC that handles stores can switch to a version that can
+ // grow at the end of the array and still stay MONOMORPHIC.
+ return isolate()->stub_cache()->ComputeKeyedStoreElement(
+ receiver_map, strict_mode, store_mode);
+ }
+ }
}
ASSERT(ic_state != GENERIC);
@@ -1660,9 +1700,11 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
bool map_added =
AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
- if (IsTransitionStubKind(stub_kind)) {
- Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind);
- map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map);
+ if (IsTransitionStoreMode(store_mode)) {
+ Handle<Map> transitioned_receiver_map =
+ ComputeTransitionedMap(receiver, store_mode);
+ map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
+ transitioned_receiver_map);
}
if (!map_added) {
@@ -1679,19 +1721,29 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
}
- if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) ==
- ALLOW_JSARRAY_GROWTH)) {
- grow_mode = ALLOW_JSARRAY_GROWTH;
+ // Make sure all polymorphic handlers have the same store mode, otherwise the
+ // generic stub must be used.
+ store_mode = GetNonTransitioningStoreMode(store_mode);
+ if (old_store_mode != STANDARD_STORE) {
+ if (store_mode == STANDARD_STORE) {
+ store_mode = old_store_mode;
+ } else if (store_mode != old_store_mode) {
+ TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
+ return strict_mode == kStrictMode
+ ? generic_stub_strict()
+ : generic_stub();
+ }
}
return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
- &target_receiver_maps, grow_mode, strict_mode);
+ &target_receiver_maps, store_mode, strict_mode);
}
-Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
- StubKind stub_kind) {
- switch (stub_kind) {
+Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
+ Handle<JSObject> receiver,
+ KeyedAccessStoreMode store_mode) {
+ switch (store_mode) {
case STORE_TRANSITION_SMI_TO_OBJECT:
case STORE_TRANSITION_DOUBLE_TO_OBJECT:
case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
@@ -1710,7 +1762,11 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
return JSObject::GetElementsTransitionMap(receiver,
FAST_HOLEY_DOUBLE_ELEMENTS);
- case STORE_NO_TRANSITION:
+ case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
+ ASSERT(receiver->map()->has_external_array_elements());
+ // Fall through
+ case STORE_NO_TRANSITION_HANDLE_COW:
+ case STANDARD_STORE:
case STORE_AND_GROW_NO_TRANSITION:
return Handle<Map>(receiver->map());
}
@@ -1718,15 +1774,23 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
}
-KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
- Handle<Object> key,
- Handle<Object> value) {
+bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
+ int index) {
+ if (receiver->IsJSArray()) {
+ return JSArray::cast(*receiver)->length()->IsSmi() &&
+ index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
+ }
+ return index >= receiver->elements()->length();
+}
+
+
+KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
+ Handle<Object> key,
+ Handle<Object> value) {
ASSERT(key->IsSmi());
int index = Smi::cast(*key)->value();
- bool allow_growth = receiver->IsJSArray() &&
- JSArray::cast(*receiver)->length()->IsSmi() &&
- index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
-
+ bool oob_access = IsOutOfBoundsAccess(receiver, index);
+ bool allow_growth = receiver->IsJSArray() && oob_access;
if (allow_growth) {
// Handle growing array in stub if necessary.
if (receiver->HasFastSmiElements()) {
@@ -1779,7 +1843,12 @@ KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
}
}
}
- return STORE_NO_TRANSITION;
+ if (!FLAG_trace_external_array_abuse &&
+ receiver->map()->has_external_array_elements() && oob_access) {
+ return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
+ } else {
+ return STANDARD_STORE;
+ }
}
}
@@ -1819,8 +1888,8 @@ MaybeObject* KeyedStoreIC::Store(State state,
isolate()->heap()->non_strict_arguments_elements_map()) {
stub = non_strict_arguments_stub();
} else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
- StubKind stub_kind = GetStubKind(receiver, key, value);
- stub = StoreElementStub(receiver, stub_kind, strict_mode);
+ KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
+ stub = StoreElementStub(receiver, store_mode, strict_mode);
}
}
} else {
« no previous file with comments | « src/ic.h ('k') | src/mips/stub-cache-mips.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698