Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 9846984dd383c4488e3bb20e0db4685751926e4f..248f4fc891d16430d602c613c81deb21badbaf86 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -81,9 +81,13 @@ void IC::TraceIC(const char* type, |
} |
} |
JavaScriptFrame::PrintTop(stdout, false, true); |
- PrintF(" (%c->%c)", |
+ bool new_can_grow = |
+ Code::GetKeyedAccessGrowMode(new_target->extra_ic_state()) == |
+ ALLOW_JSARRAY_GROWTH; |
+ PrintF(" (%c->%c%s)", |
TransitionMarkFromState(old_state), |
- TransitionMarkFromState(new_state)); |
+ TransitionMarkFromState(new_state), |
+ new_can_grow ? ".GROW" : ""); |
name->Print(); |
PrintF("]\n"); |
} |
@@ -375,7 +379,7 @@ void LoadIC::Clear(Address address, Code* target) { |
void StoreIC::Clear(Address address, Code* target) { |
if (target->ic_state() == UNINITIALIZED) return; |
SetTargetAtAddress(address, |
- (target->extra_ic_state() == kStrictMode) |
+ (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) |
? initialize_stub_strict() |
: initialize_stub()); |
} |
@@ -384,7 +388,7 @@ void StoreIC::Clear(Address address, Code* target) { |
void KeyedStoreIC::Clear(Address address, Code* target) { |
if (target->ic_state() == UNINITIALIZED) return; |
SetTargetAtAddress(address, |
- (target->extra_ic_state() == kStrictMode) |
+ (Code::GetStrictMode(target->extra_ic_state()) == kStrictMode) |
? initialize_stub_strict() |
: initialize_stub()); |
} |
@@ -996,19 +1000,22 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck( |
bool is_js_array, |
- ElementsKind elements_kind) { |
+ ElementsKind elements_kind, |
+ KeyedAccessGrowMode grow_mode) { |
+ ASSERT(grow_mode == DO_NOT_ALLOW_JSARRAY_GROWTH); |
return KeyedLoadElementStub(elements_kind).GetCode(); |
} |
Handle<Code> KeyedLoadIC::ComputePolymorphicStub( |
MapHandleList* receiver_maps, |
- StrictModeFlag strict_mode) { |
+ StrictModeFlag strict_mode, |
+ KeyedAccessGrowMode growth_mode) { |
CodeHandleList handler_ics(receiver_maps->length()); |
for (int i = 0; i < receiver_maps->length(); ++i) { |
Handle<Map> receiver_map = receiver_maps->at(i); |
Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
- receiver_map, strict_mode); |
+ receiver_map, strict_mode, growth_mode); |
handler_ics.Add(cached_stub); |
} |
KeyedLoadStubCompiler compiler(isolate()); |
@@ -1493,6 +1500,9 @@ Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, |
StrictModeFlag strict_mode, |
Handle<Code> generic_stub) { |
State ic_state = target()->ic_state(); |
+ KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind) |
+ ? ALLOW_JSARRAY_GROWTH |
+ : DO_NOT_ALLOW_JSARRAY_GROWTH; |
if ((ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) && |
!IsTransitionStubKind(stub_kind)) { |
return ComputeMonomorphicStub( |
@@ -1537,14 +1547,21 @@ Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, |
return generic_stub; |
} |
+ if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) == |
+ ALLOW_JSARRAY_GROWTH)) { |
+ grow_mode = ALLOW_JSARRAY_GROWTH; |
+ } |
+ |
Handle<PolymorphicCodeCache> cache = |
isolate()->factory()->polymorphic_code_cache(); |
- Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, strict_mode); |
+ Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode, |
+ strict_mode); |
+ Code::Flags flags = Code::ComputeFlags(kind(), MEGAMORPHIC, extra_state); |
Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags); |
if (probe->IsCode()) return Handle<Code>::cast(probe); |
Handle<Code> stub = |
- ComputePolymorphicStub(&target_receiver_maps, strict_mode); |
+ ComputePolymorphicStub(&target_receiver_maps, strict_mode, grow_mode); |
PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub); |
return stub; |
} |
@@ -1552,7 +1569,8 @@ Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver, |
Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck( |
Handle<Map> receiver_map, |
- StrictModeFlag strict_mode) { |
+ StrictModeFlag strict_mode, |
+ KeyedAccessGrowMode grow_mode) { |
if ((receiver_map->instance_type() & kNotStringTag) == 0) { |
ASSERT(!string_stub().is_null()); |
return string_stub(); |
@@ -1564,7 +1582,8 @@ Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck( |
receiver_map->has_external_array_elements()); |
bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
return GetElementStubWithoutMapCheck(is_js_array, |
- receiver_map->elements_kind()); |
+ receiver_map->elements_kind(), |
+ grow_mode); |
} |
} |
@@ -1591,9 +1610,12 @@ Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver, |
switch (stub_kind) { |
case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT: |
case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT: |
+ case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT: |
+ case KeyedIC::STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT: |
return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS); |
break; |
case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE: |
+ case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE: |
return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS); |
break; |
default: |
@@ -1605,13 +1627,16 @@ Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver, |
Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck( |
bool is_js_array, |
- ElementsKind elements_kind) { |
- return KeyedStoreElementStub(is_js_array, elements_kind).GetCode(); |
+ ElementsKind elements_kind, |
+ KeyedAccessGrowMode grow_mode) { |
+ return KeyedStoreElementStub(is_js_array, elements_kind, grow_mode).GetCode(); |
} |
-Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps, |
- StrictModeFlag strict_mode) { |
+Handle<Code> KeyedStoreIC::ComputePolymorphicStub( |
+ MapHandleList* receiver_maps, |
+ StrictModeFlag strict_mode, |
+ KeyedAccessGrowMode grow_mode) { |
// Collect MONOMORPHIC stubs for all target_receiver_maps. |
CodeHandleList handler_ics(receiver_maps->length()); |
MapHandleList transitioned_maps(receiver_maps->length()); |
@@ -1625,16 +1650,17 @@ Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps, |
receiver_map->elements_kind(), // original elements_kind |
transitioned_map->elements_kind(), |
receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array |
- strict_mode).GetCode(); |
+ strict_mode, grow_mode).GetCode(); |
} else { |
cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map, |
- strict_mode); |
+ strict_mode, |
+ grow_mode); |
} |
ASSERT(!cached_stub.is_null()); |
handler_ics.Add(cached_stub); |
transitioned_maps.Add(transitioned_map); |
} |
- KeyedStoreStubCompiler compiler(isolate(), strict_mode); |
+ KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode); |
Handle<Code> code = compiler.CompileStorePolymorphic( |
receiver_maps, &handler_ics, &transitioned_maps); |
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
@@ -1644,6 +1670,48 @@ Handle<Code> KeyedStoreIC::ComputePolymorphicStub(MapHandleList* receiver_maps, |
} |
+KeyedIC::StubKind KeyedStoreIC::GetStubKind(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(); |
+ |
+ if (allow_growth) { |
+ // Handle growing array in stub if necessary. |
+ if (receiver->HasFastSmiOnlyElements()) { |
+ if (value->IsHeapNumber()) { |
+ return STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE; |
+ } |
+ if (value->IsHeapObject()) { |
+ return STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT; |
+ } |
+ } else if (receiver->HasFastDoubleElements()) { |
+ if (!value->IsSmi() && !value->IsHeapNumber()) { |
+ return STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT; |
+ } |
+ } |
+ return STORE_AND_GROW_NO_TRANSITION; |
+ } else { |
+ // Handle only in-bounds elements accesses. |
+ if (receiver->HasFastSmiOnlyElements()) { |
+ if (value->IsHeapNumber()) { |
+ return STORE_TRANSITION_SMI_TO_DOUBLE; |
+ } else if (value->IsHeapObject()) { |
+ return STORE_TRANSITION_SMI_TO_OBJECT; |
+ } |
+ } else if (receiver->HasFastDoubleElements()) { |
+ if (!value->IsSmi() && !value->IsHeapNumber()) { |
+ return STORE_TRANSITION_DOUBLE_TO_OBJECT; |
+ } |
+ } |
+ return STORE_NO_TRANSITION; |
+ } |
+} |
+ |
+ |
MaybeObject* KeyedStoreIC::Store(State state, |
StrictModeFlag strict_mode, |
Handle<Object> object, |
@@ -1706,18 +1774,7 @@ 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; |
- } |
- } |
+ StubKind stub_kind = GetStubKind(receiver, key, value); |
stub = ComputeStub(receiver, stub_kind, strict_mode, stub); |
} |
} else { |
@@ -1900,7 +1957,7 @@ RUNTIME_FUNCTION(MaybeObject*, StoreIC_Miss) { |
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
return ic.Store(state, |
- static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
+ Code::GetStrictMode(extra_ic_state), |
args.at<Object>(0), |
args.at<String>(1), |
args.at<Object>(2)); |
@@ -1976,7 +2033,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Miss) { |
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
return ic.Store(state, |
- static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
+ Code::GetStrictMode(extra_ic_state), |
args.at<Object>(0), |
args.at<Object>(1), |
args.at<Object>(2), |
@@ -1992,8 +2049,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_Slow) { |
Handle<Object> object = args.at<Object>(0); |
Handle<Object> key = args.at<Object>(1); |
Handle<Object> value = args.at<Object>(2); |
- StrictModeFlag strict_mode = |
- static_cast<StrictModeFlag>(extra_ic_state & kStrictMode); |
+ StrictModeFlag strict_mode = Code::GetStrictMode(extra_ic_state); |
return Runtime::SetObjectProperty(isolate, |
object, |
key, |
@@ -2010,7 +2066,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedStoreIC_MissForceGeneric) { |
IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
Code::ExtraICState extra_ic_state = ic.target()->extra_ic_state(); |
return ic.Store(state, |
- static_cast<StrictModeFlag>(extra_ic_state & kStrictMode), |
+ Code::GetStrictMode(extra_ic_state), |
args.at<Object>(0), |
args.at<Object>(1), |
args.at<Object>(2), |