}
-MaybeObject* IC::Load(State state,
- Handle<Object> object,
- Handle<String> name) {
+MaybeObject* 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()) {
}
-Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck(
- bool is_js_array,
- ElementsKind elements_kind,
- KeyedAccessGrowMode grow_mode) {
- ASSERT(grow_mode == DO_NOT_ALLOW_JSARRAY_GROWTH);
- if (IsFastElementsKind(elements_kind) ||
- IsExternalArrayElementsKind(elements_kind)) {
- return KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode();
- } else {
- ASSERT(elements_kind == DICTIONARY_ELEMENTS);
- return KeyedLoadDictionaryElementStub().GetCode();
- }
-}
-
-
-Handle<Code> KeyedLoadIC::ComputePolymorphicStub(
- MapHandleList* receiver_maps,
- 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, growth_mode);
- handler_ics.Add(cached_stub);
- }
- KeyedLoadStubCompiler compiler(isolate());
- Handle<Code> code = compiler.CompileLoadPolymorphic(
- receiver_maps, &handler_ics);
- isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
- return code;
-}
-
-
static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
// This helper implements a few common fast cases for converting
// non-smi keys of keyed loads/stores to a smi or a string.
}
+static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
+ Handle<Map> new_receiver_map) {
+ ASSERT(!new_receiver_map.is_null());
+ for (int current = 0; current < receiver_maps->length(); ++current) {
+ if (!receiver_maps->at(current).is_null() &&
+ receiver_maps->at(current).is_identical_to(new_receiver_map)) {
+ return false;
+ }
+ }
+ receiver_maps->Add(new_receiver_map);
+ return true;
+}
+
+
+static void GetReceiverMapsForStub(Handle<Code> stub,
+ MapHandleList* result) {
+ ASSERT(stub->is_inline_cache_stub());
+ if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
+ switch (stub->ic_state()) {
+ case MONOMORPHIC:
+ result->Add(Handle<Map>(stub->FindFirstMap()));
+ break;
+ case POLYMORPHIC: {
+ 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 MEGAMORPHIC:
+ case GENERIC:
+ break;
+ case UNINITIALIZED:
+ case PREMONOMORPHIC:
+ case MONOMORPHIC_PROTOTYPE_FAILURE:
+ case DEBUG_STUB:
+ UNREACHABLE();
+ break;
+ }
+ }
+}
+
+
+Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
+ State ic_state = target()->ic_state();
+
+ // 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.
+ if (target()->type() != Code::NORMAL) {
+ TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type");
+ return generic_stub();
+ }
+
+ 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.
+ return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
+ }
+
+ if (target() == *string_stub()) {
+ target_receiver_maps.Add(isolate()->factory()->string_map());
+ } else {
+ GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+ }
+
+ // 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 &&
+ IsMoreGeneralElementsKindTransition(
+ target_receiver_maps.at(0)->elements_kind(),
+ receiver->GetElementsKind())) {
+ return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
+ }
+
+ ASSERT(target() != *generic_stub());
+
+ // Determine the list of receiver maps that this call site has seen,
+ // adding the map that was just encountered.
+ if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
+ // If the miss wasn't due to an unseen map, a polymorphic stub
+ // won't help, use the generic stub.
+ TRACE_GENERIC_IC("KeyedIC", "same map added twice");
+ return generic_stub();
+ }
+
+ // If the maximum number of receiver maps has been exceeded, use the generic
+ // version of the IC.
+ if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
+ TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded");
+ return generic_stub();
+ }
+
+ return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
+ &target_receiver_maps);
+}
+
+
MaybeObject* KeyedLoadIC::Load(State state,
Handle<Object> object,
Handle<Object> key,
key = TryConvertKey(key, isolate());
if (key->IsSymbol()) {
- return IC::Load(state, object, Handle<String>::cast(key));
+ return LoadIC::Load(state, object, Handle<String>::cast(key));
}
// Do not use ICs for objects that require access checks (including
} else if (receiver->HasIndexedInterceptor()) {
stub = indexed_interceptor_stub();
} else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
- stub = ComputeStub(receiver, KeyedIC::LOAD, kNonStrictMode, stub);
+ stub = LoadElementStub(receiver);
}
}
} else {
}
-MaybeObject* IC::Store(State state,
- StrictModeFlag strict_mode,
- Handle<Object> object,
- Handle<String> name,
- Handle<Object> value,
- JSReceiver::StoreFromKeyed store_mode) {
+MaybeObject* StoreIC::Store(State state,
+ StrictModeFlag strict_mode,
+ Handle<Object> object,
+ Handle<String> name,
+ Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode) {
// Handle proxies.
if (object->IsJSProxy()) {
return JSProxy::cast(*object)->
}
-static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
- Handle<Map> new_receiver_map) {
- ASSERT(!new_receiver_map.is_null());
- for (int current = 0; current < receiver_maps->length(); ++current) {
- if (!receiver_maps->at(current).is_null() &&
- receiver_maps->at(current).is_identical_to(new_receiver_map)) {
- return false;
- }
- }
- receiver_maps->Add(new_receiver_map);
- return true;
-}
-
-
-void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub,
- MapHandleList* result) {
- ASSERT(stub->is_inline_cache_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()) {
- switch (stub->ic_state()) {
- case MONOMORPHIC:
- result->Add(Handle<Map>(stub->FindFirstMap()));
- break;
- case POLYMORPHIC: {
- 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 MEGAMORPHIC:
- case GENERIC:
- break;
- case UNINITIALIZED:
- case PREMONOMORPHIC:
- case MONOMORPHIC_PROTOTYPE_FAILURE:
- case DEBUG_STUB:
- UNREACHABLE();
- break;
- }
- }
-}
-
-
-Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
- StubKind stub_kind,
- StrictModeFlag strict_mode,
- Handle<Code> generic_stub) {
+Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
+ StubKind stub_kind,
+ StrictModeFlag strict_mode) {
State ic_state = target()->ic_state();
KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind)
? ALLOW_JSARRAY_GROWTH
// and so the stubs can't be harvested for the object needed for a map check.
if (target()->type() != Code::NORMAL) {
TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type");
- return generic_stub;
+ return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
}
- bool monomorphic = false;
- bool is_transition_stub = IsTransitionStubKind(stub_kind);
Handle<Map> receiver_map(receiver->map());
- Handle<Map> monomorphic_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.
- monomorphic = true;
- } else {
- GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
- if (ic_state == MONOMORPHIC && (is_transition_stub || stub_kind == LOAD)) {
- // 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.
- monomorphic = IsMoreGeneralElementsKindTransition(
+ stub_kind = GetNoTransitionStubKind(stub_kind);
+ return isolate()->stub_cache()->ComputeKeyedStoreElement(
+ receiver_map, stub_kind, strict_mode, grow_mode);
+ }
+
+ GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+ // 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());
- }
+ 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);
}
- if (monomorphic) {
- if (is_transition_stub) {
- monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
- ASSERT(*monomorphic_map != *receiver_map);
- stub_kind = GetNoTransitionStubKind(stub_kind);
- }
- return ComputeMonomorphicStub(
- monomorphic_map, stub_kind, strict_mode, generic_stub);
- }
- ASSERT(target() != *generic_stub);
+ ASSERT(target() != *generic_stub() && target() != *generic_stub_strict());
- // Determine the list of receiver maps that this call site has seen,
- // adding the map that was just encountered.
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 (!map_added) {
// If the miss wasn't due to an unseen map, a polymorphic stub
// won't help, use the generic stub.
TRACE_GENERIC_IC("KeyedIC", "same map added twice");
- return generic_stub;
+ return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
}
// If the maximum number of receiver maps has been exceeded, use the generic
// version of the IC.
if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded");
- return generic_stub;
+ return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
}
if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) ==
grow_mode = ALLOW_JSARRAY_GROWTH;
}
- Handle<PolymorphicCodeCache> cache =
- isolate()->factory()->polymorphic_code_cache();
- Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
- strict_mode);
- Code::Flags flags = Code::ComputeFlags(kind(), POLYMORPHIC, 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, grow_mode);
- PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub);
- return stub;
-}
-
-
-Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
- Handle<Map> receiver_map,
- StrictModeFlag strict_mode,
- KeyedAccessGrowMode grow_mode) {
- if ((receiver_map->instance_type() & kNotStringTag) == 0) {
- ASSERT(!string_stub().is_null());
- return string_stub();
- } else {
- ASSERT(receiver_map->has_dictionary_elements() ||
- receiver_map->has_fast_smi_or_object_elements() ||
- receiver_map->has_fast_double_elements() ||
- 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(),
- grow_mode);
- }
-}
-
-
-Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<Map> receiver_map,
- StubKind stub_kind,
- StrictModeFlag strict_mode,
- Handle<Code> generic_stub) {
- ElementsKind elements_kind = receiver_map->elements_kind();
- if (IsFastElementsKind(elements_kind) ||
- IsExternalArrayElementsKind(elements_kind) ||
- IsDictionaryElementsKind(elements_kind)) {
- return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
- receiver_map, stub_kind, strict_mode);
- } else {
- return generic_stub;
- }
+ return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
+ &target_receiver_maps, grow_mode, strict_mode);
}
-Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver,
- StubKind stub_kind) {
+Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
+ StubKind stub_kind) {
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:
+ case STORE_TRANSITION_SMI_TO_OBJECT:
+ case STORE_TRANSITION_DOUBLE_TO_OBJECT:
+ case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
+ case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
- case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
- case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
+ case STORE_TRANSITION_SMI_TO_DOUBLE:
+ case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
- case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
- case KeyedIC::STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
- case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
- case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+ case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
+ case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+ case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
+ case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
return JSObject::GetElementsTransitionMap(receiver,
FAST_HOLEY_ELEMENTS);
- case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
- case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+ case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+ case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
return JSObject::GetElementsTransitionMap(receiver,
FAST_HOLEY_DOUBLE_ELEMENTS);
- case KeyedIC::LOAD:
- case KeyedIC::STORE_NO_TRANSITION:
- case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
+ case STORE_NO_TRANSITION:
+ case STORE_AND_GROW_NO_TRANSITION:
UNREACHABLE();
break;
}
}
-Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck(
- bool is_js_array,
- 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,
- KeyedAccessGrowMode grow_mode) {
- // Collect MONOMORPHIC stubs for all target_receiver_maps.
- CodeHandleList handler_ics(receiver_maps->length());
- MapHandleList transitioned_maps(receiver_maps->length());
- for (int i = 0; i < receiver_maps->length(); ++i) {
- Handle<Map> receiver_map(receiver_maps->at(i));
- Handle<Code> cached_stub;
- Handle<Map> transitioned_map =
- receiver_map->FindTransitionedMap(receiver_maps);
-
- // TODO(mvstanton): The code below is doing pessimistic elements
- // transitions. I would like to stop doing that and rely on Allocation Site
- // Tracking to do a better job of ensuring the data types are what they need
- // to be. Not all the elements are in place yet, pessimistic elements
- // transitions are still important for performance.
- if (!transitioned_map.is_null()) {
- cached_stub = ElementsTransitionAndStoreStub(
- receiver_map->elements_kind(), // original elements_kind
- transitioned_map->elements_kind(),
- receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array
- strict_mode, grow_mode).GetCode();
- } else {
- cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map,
- strict_mode,
- grow_mode);
- }
- ASSERT(!cached_stub.is_null());
- handler_ics.Add(cached_stub);
- transitioned_maps.Add(transitioned_map);
- }
- 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();
- PROFILE(isolate(),
- CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
- return code;
-}
-
-
-KeyedIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
- Handle<Object> key,
- Handle<Object> value) {
+KeyedStoreIC::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() &&
if (key->IsSymbol()) {
Handle<String> name = Handle<String>::cast(key);
- return IC::Store(state,
- strict_mode,
- object,
- name,
- value,
- JSReceiver::MAY_BE_STORE_FROM_KEYED);
+ return StoreIC::Store(state,
+ strict_mode,
+ object,
+ name,
+ value,
+ JSReceiver::MAY_BE_STORE_FROM_KEYED);
}
// Do not use ICs for objects that require access checks (including
} else if (miss_mode != MISS_FORCE_GENERIC) {
if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
StubKind stub_kind = GetStubKind(receiver, key, value);
- stub = ComputeStub(receiver, stub_kind, strict_mode, stub);
+ stub = StoreElementStub(receiver, stub_kind, strict_mode);
}
} else {
TRACE_GENERIC_IC("KeyedStoreIC", "force generic");
static inline JSObject* GetCodeCacheHolder(Object* object,
InlineCacheHolderFlag holder);
- MUST_USE_RESULT MaybeObject* Load(State state,
- Handle<Object> object,
- Handle<String> name);
-
- MUST_USE_RESULT MaybeObject* Store(
- State state,
- StrictModeFlag strict_mode,
- Handle<Object> object,
- Handle<String> name,
- Handle<Object> value,
- JSReceiver::StoreFromKeyed store_mode =
- JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
-
protected:
- virtual Handle<Code> pre_monomorphic_stub() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
- virtual Handle<Code> megamorphic_stub() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
- virtual Handle<Code> megamorphic_stub_strict() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
- virtual Handle<Code> generic_stub() const {
- UNREACHABLE();
- return Handle<Code>::null();
- }
- virtual Code::Kind kind() const {
- UNREACHABLE();
- return Code::STUB;
- }
- virtual Handle<Code> global_proxy_stub() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
- virtual Handle<Code> global_proxy_stub_strict() {
- UNREACHABLE();
- return Handle<Code>::null();
- }
-
- virtual void UpdateLoadCaches(LookupResult* lookup,
- State state,
- Handle<Object> object,
- Handle<String> name) {
- UNREACHABLE();
- }
- virtual void UpdateStoreCaches(LookupResult* lookup,
- State state,
- StrictModeFlag strict_mode,
- Handle<JSObject> receiver,
- Handle<String> name,
- Handle<Object> value) {
- UNREACHABLE();
- }
Address fp() const { return fp_; }
Address pc() const { return *pc_address_; }
Isolate* isolate() const { return isolate_; }
class LoadIC: public IC {
public:
explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
- ASSERT(target()->is_load_stub());
+ ASSERT(target()->is_load_stub() || target()->is_keyed_load_stub());
}
// Code generator routines.
static void GenerateArrayLength(MacroAssembler* masm);
static void GenerateFunctionPrototype(MacroAssembler* masm);
+ MUST_USE_RESULT MaybeObject* Load(State state,
+ Handle<Object> object,
+ Handle<String> name);
+
protected:
virtual Code::Kind kind() const { return Code::LOAD_IC; }
+ virtual Handle<Code> generic_stub() const {
+ UNREACHABLE();
+ return Handle<Code>::null();
+ }
+
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->LoadIC_Megamorphic();
}
};
-class KeyedIC: public IC {
- public:
- enum StubKind {
- LOAD,
- STORE_NO_TRANSITION,
- STORE_TRANSITION_SMI_TO_OBJECT,
- STORE_TRANSITION_SMI_TO_DOUBLE,
- STORE_TRANSITION_DOUBLE_TO_OBJECT,
- STORE_TRANSITION_HOLEY_SMI_TO_OBJECT,
- STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE,
- STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT,
- STORE_AND_GROW_NO_TRANSITION,
- STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
- STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
- STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT,
- STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT,
- STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE,
- STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT
- };
-
- static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
- STORE_NO_TRANSITION;
- STATIC_ASSERT(kGrowICDelta ==
- STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
- STORE_TRANSITION_SMI_TO_OBJECT);
- STATIC_ASSERT(kGrowICDelta ==
- STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
- STORE_TRANSITION_SMI_TO_DOUBLE);
- STATIC_ASSERT(kGrowICDelta ==
- STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
- STORE_TRANSITION_DOUBLE_TO_OBJECT);
-
- explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
- virtual ~KeyedIC() {}
-
- static inline KeyedAccessGrowMode GetGrowModeFromStubKind(
- StubKind stub_kind) {
- return (stub_kind >= STORE_AND_GROW_NO_TRANSITION)
- ? ALLOW_JSARRAY_GROWTH
- : DO_NOT_ALLOW_JSARRAY_GROWTH;
- }
-
- static inline StubKind GetGrowStubKind(StubKind stub_kind) {
- ASSERT(stub_kind != LOAD);
- if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
- stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
- kGrowICDelta);
- }
- return stub_kind;
- }
-
- virtual Handle<Code> GetElementStubWithoutMapCheck(
- bool is_js_array,
- ElementsKind elements_kind,
- KeyedAccessGrowMode grow_mode) = 0;
-
- protected:
- virtual Handle<Code> string_stub() {
- return Handle<Code>::null();
- }
-
- Handle<Code> ComputeStub(Handle<JSObject> receiver,
- StubKind stub_kind,
- StrictModeFlag strict_mode,
- Handle<Code> default_stub);
-
- virtual Handle<Code> ComputePolymorphicStub(
- MapHandleList* receiver_maps,
- StrictModeFlag strict_mode,
- KeyedAccessGrowMode grow_mode) = 0;
-
- Handle<Code> ComputeMonomorphicStubWithoutMapCheck(
- Handle<Map> receiver_map,
- StrictModeFlag strict_mode,
- KeyedAccessGrowMode grow_mode);
-
- private:
- void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result);
-
- Handle<Code> ComputeMonomorphicStub(Handle<Map> receiver_map,
- StubKind stub_kind,
- StrictModeFlag strict_mode,
- Handle<Code> default_stub);
-
- Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
- StubKind stub_kind);
-
- static bool IsTransitionStubKind(StubKind stub_kind) {
- return stub_kind > STORE_NO_TRANSITION &&
- stub_kind != STORE_AND_GROW_NO_TRANSITION;
- }
-
- static bool IsGrowStubKind(StubKind stub_kind) {
- return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
- }
-
- static StubKind GetNoTransitionStubKind(StubKind stub_kind) {
- if (!IsTransitionStubKind(stub_kind)) return stub_kind;
- if (IsGrowStubKind(stub_kind)) return STORE_AND_GROW_NO_TRANSITION;
- return STORE_NO_TRANSITION;
- }
-};
-
-
enum ICMissMode {
MISS_FORCE_GENERIC,
MISS
};
-class KeyedLoadIC: public KeyedIC {
+class KeyedLoadIC: public LoadIC {
public:
- explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
+ explicit KeyedLoadIC(Isolate* isolate) : LoadIC(isolate) {
ASSERT(target()->is_keyed_load_stub());
}
static const int kSlowCaseBitFieldMask =
(1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
- virtual Handle<Code> GetElementStubWithoutMapCheck(
- bool is_js_array,
- ElementsKind elements_kind,
- KeyedAccessGrowMode grow_mode);
-
protected:
virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
+ Handle<Code> LoadElementStub(Handle<JSObject> receiver);
+
virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedLoadIC_Generic();
}
return isolate()->builtins()->KeyedLoadIC_Generic();
}
- virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
- StrictModeFlag strict_mode,
- KeyedAccessGrowMode grow_mode);
-
- virtual Handle<Code> string_stub() {
- return isolate()->builtins()->KeyedLoadIC_String();
- }
-
// Update the inline cache.
virtual void UpdateLoadCaches(LookupResult* lookup,
State state,
Handle<Code> non_strict_arguments_stub() {
return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
}
+ Handle<Code> string_stub() {
+ return isolate()->builtins()->KeyedLoadIC_String();
+ }
static void Clear(Address address, Code* target);
class StoreIC: public IC {
public:
explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
- ASSERT(target()->is_store_stub());
+ ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub());
}
// Code generators for stub routines. Only called once at startup.
static void GenerateGlobalProxy(MacroAssembler* masm,
StrictModeFlag strict_mode);
+ MUST_USE_RESULT MaybeObject* Store(
+ State state,
+ StrictModeFlag strict_mode,
+ Handle<Object> object,
+ Handle<String> name,
+ Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode =
+ JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
+
protected:
virtual Code::Kind kind() const { return Code::STORE_IC; }
virtual Handle<Code> megamorphic_stub() {
};
-class KeyedStoreIC: public KeyedIC {
+class KeyedStoreIC: public StoreIC {
public:
- explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
+ enum StubKind {
+ STORE_NO_TRANSITION,
+ STORE_TRANSITION_SMI_TO_OBJECT,
+ STORE_TRANSITION_SMI_TO_DOUBLE,
+ STORE_TRANSITION_DOUBLE_TO_OBJECT,
+ STORE_TRANSITION_HOLEY_SMI_TO_OBJECT,
+ STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+ STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT,
+ STORE_AND_GROW_NO_TRANSITION,
+ STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
+ STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
+ STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT,
+ STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT,
+ STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+ STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT
+ };
+
+ static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
+ STORE_NO_TRANSITION;
+ STATIC_ASSERT(kGrowICDelta ==
+ STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
+ STORE_TRANSITION_SMI_TO_OBJECT);
+ STATIC_ASSERT(kGrowICDelta ==
+ STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
+ STORE_TRANSITION_SMI_TO_DOUBLE);
+ STATIC_ASSERT(kGrowICDelta ==
+ STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
+ STORE_TRANSITION_DOUBLE_TO_OBJECT);
+
+ static inline StubKind GetGrowStubKind(StubKind stub_kind) {
+ if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
+ stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
+ kGrowICDelta);
+ }
+ return stub_kind;
+ }
+
+ explicit KeyedStoreIC(Isolate* isolate) : StoreIC(isolate) {
ASSERT(target()->is_keyed_store_stub());
}
static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
- virtual Handle<Code> GetElementStubWithoutMapCheck(
- bool is_js_array,
- ElementsKind elements_kind,
- KeyedAccessGrowMode grow_mode);
-
protected:
virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
- virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
- StrictModeFlag strict_mode,
- KeyedAccessGrowMode grow_mode);
-
// Update the inline cache.
virtual void UpdateStoreCaches(LookupResult* lookup,
State state,
return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
}
+ Handle<Code> StoreElementStub(Handle<JSObject> receiver,
+ StubKind stub_kind,
+ StrictModeFlag strict_mode);
+
private:
void set_target(Code* code) {
// Strict mode must be preserved across IC patching.
Handle<Object> key,
Handle<Object> value);
+ static bool IsTransitionStubKind(StubKind stub_kind) {
+ return stub_kind > STORE_NO_TRANSITION &&
+ stub_kind != STORE_AND_GROW_NO_TRANSITION;
+ }
+
+ static bool IsGrowStubKind(StubKind stub_kind) {
+ return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
+ }
+
+ static StubKind GetNoTransitionStubKind(StubKind stub_kind) {
+ if (!IsTransitionStubKind(stub_kind)) return stub_kind;
+ if (IsGrowStubKind(stub_kind)) return STORE_AND_GROW_NO_TRANSITION;
+ return STORE_NO_TRANSITION;
+ }
+
+ Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
+ StubKind stub_kind);
+
friend class IC;
};
}
-Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
+Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
+ Code::Flags flags =
+ Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::NORMAL);
+ Handle<String> name =
+ isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
+
+ Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate());
+ Handle<Code> code = compiler.CompileLoadElement(receiver_map);
+
+ PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
+ Map::UpdateCodeCache(receiver_map, name, code);
+ return code;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedStoreElement(
Handle<Map> receiver_map,
- KeyedIC::StubKind stub_kind,
- StrictModeFlag strict_mode) {
- KeyedAccessGrowMode grow_mode =
- KeyedIC::GetGrowModeFromStubKind(stub_kind);
+ KeyedStoreIC::StubKind stub_kind,
+ StrictModeFlag strict_mode,
+ KeyedAccessGrowMode grow_mode) {
Code::ExtraICState extra_state =
Code::ComputeExtraICState(grow_mode, strict_mode);
- Code::Flags flags =
- Code::ComputeMonomorphicFlags(
- stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
- : Code::KEYED_STORE_IC,
- Code::NORMAL,
- extra_state);
- Handle<String> name;
- switch (stub_kind) {
- case KeyedIC::LOAD:
- name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
- break;
- case KeyedIC::STORE_NO_TRANSITION:
- name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
- break;
- case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
- name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
- break;
- default:
- UNREACHABLE();
- break;
- }
+ Code::Flags flags = Code::ComputeMonomorphicFlags(
+ Code::KEYED_STORE_IC, Code::NORMAL, extra_state);
+
+ ASSERT(stub_kind == KeyedStoreIC::STORE_NO_TRANSITION ||
+ stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
+
+ Handle<String> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
+ ? isolate()->factory()->KeyedStoreElementMonomorphic_symbol()
+ : isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
+
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
- Handle<Code> code;
- switch (stub_kind) {
- case KeyedIC::LOAD: {
- KeyedLoadStubCompiler compiler(isolate_);
- code = compiler.CompileLoadElement(receiver_map);
- break;
- }
- case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
- KeyedStoreStubCompiler compiler(isolate_, strict_mode,
- ALLOW_JSARRAY_GROWTH);
- code = compiler.CompileStoreElement(receiver_map);
- break;
- }
- case KeyedIC::STORE_NO_TRANSITION: {
- KeyedStoreStubCompiler compiler(isolate_, strict_mode,
- DO_NOT_ALLOW_JSARRAY_GROWTH);
- code = compiler.CompileStoreElement(receiver_map);
- break;
- }
- default:
- UNREACHABLE();
- break;
- }
-
- ASSERT(!code.is_null());
+ KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
+ Handle<Code> code = compiler.CompileStoreElement(receiver_map);
- if (stub_kind == KeyedIC::LOAD) {
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
- } else {
- PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
- }
+ PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
Map::UpdateCodeCache(receiver_map, name, code);
return code;
}
}
+Handle<Code> StubCache::ComputeLoadElementPolymorphic(
+ MapHandleList* receiver_maps) {
+ Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
+ Handle<PolymorphicCodeCache> cache =
+ isolate_->factory()->polymorphic_code_cache();
+ Handle<Object> probe = cache->Lookup(receiver_maps, flags);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedLoadStubCompiler compiler(isolate_);
+ Handle<Code> code = compiler.CompileLoadElementPolymorphic(receiver_maps);
+ PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
+ return code;
+}
+
+
+Handle<Code> StubCache::ComputeStoreElementPolymorphic(
+ MapHandleList* receiver_maps,
+ KeyedAccessGrowMode grow_mode,
+ StrictModeFlag strict_mode) {
+ Handle<PolymorphicCodeCache> cache =
+ isolate_->factory()->polymorphic_code_cache();
+ Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
+ strict_mode);
+ Code::Flags flags =
+ Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
+ Handle<Object> probe = cache->Lookup(receiver_maps, flags);
+ if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+ KeyedStoreStubCompiler compiler(isolate_, strict_mode, grow_mode);
+ Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
+ PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
+ return code;
+}
+
+
#ifdef ENABLE_DEBUGGER_SUPPORT
Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
Code::Kind kind) {
}
+Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
+ MapHandleList* receiver_maps) {
+ 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;
+
+ if ((receiver_map->instance_type() & kNotStringTag) == 0) {
+ cached_stub = isolate()->builtins()->KeyedLoadIC_String();
+ } else {
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ ElementsKind elements_kind = receiver_map->elements_kind();
+
+ if (IsFastElementsKind(elements_kind) ||
+ IsExternalArrayElementsKind(elements_kind)) {
+ cached_stub =
+ KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode();
+ } else {
+ ASSERT(elements_kind == DICTIONARY_ELEMENTS);
+ cached_stub = KeyedLoadDictionaryElementStub().GetCode();
+ }
+ }
+
+ handler_ics.Add(cached_stub);
+ }
+ Handle<Code> code = CompileLoadPolymorphic(receiver_maps, &handler_ics);
+ isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
+ return code;
+}
+
+
+
Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
Handle<String> name) {
Code::Flags flags =
}
+Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
+ MapHandleList* receiver_maps) {
+ // Collect MONOMORPHIC stubs for all |receiver_maps|.
+ CodeHandleList handler_ics(receiver_maps->length());
+ MapHandleList transitioned_maps(receiver_maps->length());
+ for (int i = 0; i < receiver_maps->length(); ++i) {
+ Handle<Map> receiver_map(receiver_maps->at(i));
+ Handle<Code> cached_stub;
+ Handle<Map> transitioned_map =
+ receiver_map->FindTransitionedMap(receiver_maps);
+
+ // TODO(mvstanton): The code below is doing pessimistic elements
+ // transitions. I would like to stop doing that and rely on Allocation Site
+ // Tracking to do a better job of ensuring the data types are what they need
+ // to be. Not all the elements are in place yet, pessimistic elements
+ // transitions are still important for performance.
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ if (!transitioned_map.is_null()) {
+ cached_stub = ElementsTransitionAndStoreStub(
+ elements_kind,
+ transitioned_map->elements_kind(),
+ is_js_array,
+ strict_mode_,
+ grow_mode_).GetCode();
+ } else {
+ cached_stub = KeyedStoreElementStub(
+ is_js_array,
+ elements_kind,
+ grow_mode_).GetCode();
+ }
+ ASSERT(!cached_stub.is_null());
+ handler_ics.Add(cached_stub);
+ transitioned_maps.Add(transitioned_map);
+ }
+ Handle<Code> code =
+ CompileStorePolymorphic(receiver_maps, &handler_ics, &transitioned_maps);
+ isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
+ PROFILE(isolate(),
+ CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
+ return code;
+}
+
+
void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
MacroAssembler* masm) {
KeyedStoreIC::GenerateSlow(masm);
Handle<Map> transition,
StrictModeFlag strict_mode);
- Handle<Code> ComputeKeyedLoadOrStoreElement(Handle<Map> receiver_map,
- KeyedIC::StubKind stub_kind,
- StrictModeFlag strict_mode);
+ Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
+
+ Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
+ KeyedStoreIC::StubKind stub_kind,
+ StrictModeFlag strict_mode,
+ KeyedAccessGrowMode grow_mode);
// ---
Code::Kind kind,
Code::ExtraICState state);
+ // ---
+
+ Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
+ Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
+ KeyedAccessGrowMode grow_mode,
+ StrictModeFlag strict_mode);
+
// Finds the Code object stored in the Heap::non_monomorphic_cache().
Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
CodeHandleList* handler_ics);
+ Handle<Code> CompileLoadElementPolymorphic(MapHandleList* receiver_maps);
+
static void GenerateLoadDictionaryElement(MacroAssembler* masm);
private:
CodeHandleList* handler_stubs,
MapHandleList* transitioned_maps);
+ Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
+
static void GenerateStoreFastElement(MacroAssembler* masm,
bool is_js_array,
ElementsKind element_kind,