Unify grow mode and stub kind
In the process, ensure that transition-causing element stores handle all cases of the transitioned receiver map. Review URL: https://codereview.chromium.org/12390031 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13850 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
935e7f7ba5
commit
bbc599f334
@ -3064,7 +3064,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
|
||||
Handle<Code> stub =
|
||||
KeyedStoreElementStub(is_js_array,
|
||||
elements_kind,
|
||||
grow_mode_).GetCode(isolate());
|
||||
store_mode_).GetCode(isolate());
|
||||
|
||||
__ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK);
|
||||
|
||||
@ -3722,7 +3722,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : key
|
||||
@ -3762,7 +3762,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
}
|
||||
// Compare smis.
|
||||
__ cmp(key_reg, scratch);
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
__ b(hs, &grow);
|
||||
} else {
|
||||
__ b(hs, &miss_force_generic);
|
||||
@ -3815,7 +3815,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ Jump(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Grow the array by a single element if possible.
|
||||
__ bind(&grow);
|
||||
|
||||
@ -3887,7 +3887,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- r0 : value
|
||||
// -- r1 : key
|
||||
@ -3933,7 +3933,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
// Compare smis, unsigned compare catches both negative and out-of-bound
|
||||
// indexes.
|
||||
__ cmp(key_reg, scratch1);
|
||||
if (grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
__ b(hs, &grow);
|
||||
} else {
|
||||
__ b(hs, &miss_force_generic);
|
||||
@ -3961,7 +3961,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ Jump(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Grow the array by a single element if possible.
|
||||
__ bind(&grow);
|
||||
|
||||
|
@ -442,14 +442,14 @@ void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
|
||||
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
|
||||
is_js_array_,
|
||||
elements_kind_,
|
||||
grow_mode_);
|
||||
store_mode_);
|
||||
}
|
||||
break;
|
||||
case FAST_DOUBLE_ELEMENTS:
|
||||
case FAST_HOLEY_DOUBLE_ELEMENTS:
|
||||
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
|
||||
is_js_array_,
|
||||
grow_mode_);
|
||||
store_mode_);
|
||||
break;
|
||||
case EXTERNAL_BYTE_ELEMENTS:
|
||||
case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
|
||||
@ -593,13 +593,13 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
|
||||
KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
|
||||
is_jsarray_,
|
||||
to_,
|
||||
grow_mode_);
|
||||
store_mode_);
|
||||
} else if (IsFastSmiElementsKind(from_) &&
|
||||
IsFastDoubleElementsKind(to_)) {
|
||||
ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
|
||||
KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
|
||||
is_jsarray_,
|
||||
grow_mode_);
|
||||
store_mode_);
|
||||
} else if (IsFastDoubleElementsKind(from_)) {
|
||||
ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
|
||||
ElementsTransitionGenerator::
|
||||
|
@ -1400,31 +1400,31 @@ class KeyedStoreElementStub : public PlatformCodeStub {
|
||||
public:
|
||||
KeyedStoreElementStub(bool is_js_array,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessGrowMode grow_mode)
|
||||
KeyedAccessStoreMode store_mode)
|
||||
: is_js_array_(is_js_array),
|
||||
elements_kind_(elements_kind),
|
||||
grow_mode_(grow_mode),
|
||||
store_mode_(store_mode),
|
||||
fp_registers_(CanUseFPRegisters()) { }
|
||||
|
||||
Major MajorKey() { return KeyedStoreElement; }
|
||||
int MinorKey() {
|
||||
return ElementsKindBits::encode(elements_kind_) |
|
||||
IsJSArrayBits::encode(is_js_array_) |
|
||||
GrowModeBits::encode(grow_mode_) |
|
||||
StoreModeBits::encode(store_mode_) |
|
||||
FPRegisters::encode(fp_registers_);
|
||||
}
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
|
||||
private:
|
||||
class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
|
||||
class GrowModeBits: public BitField<KeyedAccessGrowMode, 8, 1> {};
|
||||
class IsJSArrayBits: public BitField<bool, 9, 1> {};
|
||||
class FPRegisters: public BitField<bool, 10, 1> {};
|
||||
class ElementsKindBits: public BitField<ElementsKind, 0, 8> {};
|
||||
class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {};
|
||||
class IsJSArrayBits: public BitField<bool, 12, 1> {};
|
||||
class FPRegisters: public BitField<bool, 13, 1> {};
|
||||
|
||||
bool is_js_array_;
|
||||
ElementsKind elements_kind_;
|
||||
KeyedAccessGrowMode grow_mode_;
|
||||
KeyedAccessStoreMode store_mode_;
|
||||
bool fp_registers_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub);
|
||||
@ -1507,19 +1507,19 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
|
||||
ElementsKind to,
|
||||
bool is_jsarray,
|
||||
StrictModeFlag strict_mode,
|
||||
KeyedAccessGrowMode grow_mode)
|
||||
KeyedAccessStoreMode store_mode)
|
||||
: from_(from),
|
||||
to_(to),
|
||||
is_jsarray_(is_jsarray),
|
||||
strict_mode_(strict_mode),
|
||||
grow_mode_(grow_mode) {}
|
||||
store_mode_(store_mode) {}
|
||||
|
||||
private:
|
||||
class FromBits: public BitField<ElementsKind, 0, 8> {};
|
||||
class ToBits: public BitField<ElementsKind, 8, 8> {};
|
||||
class IsJSArrayBits: public BitField<bool, 16, 1> {};
|
||||
class StrictModeBits: public BitField<StrictModeFlag, 17, 1> {};
|
||||
class GrowModeBits: public BitField<KeyedAccessGrowMode, 18, 1> {};
|
||||
class FromBits: public BitField<ElementsKind, 0, 8> {};
|
||||
class ToBits: public BitField<ElementsKind, 8, 8> {};
|
||||
class IsJSArrayBits: public BitField<bool, 16, 1> {};
|
||||
class StrictModeBits: public BitField<StrictModeFlag, 17, 1> {};
|
||||
class StoreModeBits: public BitField<KeyedAccessStoreMode, 18, 4> {};
|
||||
|
||||
Major MajorKey() { return ElementsTransitionAndStore; }
|
||||
int MinorKey() {
|
||||
@ -1527,7 +1527,7 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
|
||||
ToBits::encode(to_) |
|
||||
IsJSArrayBits::encode(is_jsarray_) |
|
||||
StrictModeBits::encode(strict_mode_) |
|
||||
GrowModeBits::encode(grow_mode_);
|
||||
StoreModeBits::encode(store_mode_);
|
||||
}
|
||||
|
||||
void Generate(MacroAssembler* masm);
|
||||
@ -1536,7 +1536,7 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
|
||||
ElementsKind to_;
|
||||
bool is_jsarray_;
|
||||
StrictModeFlag strict_mode_;
|
||||
KeyedAccessGrowMode grow_mode_;
|
||||
KeyedAccessStoreMode store_mode_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub);
|
||||
};
|
||||
|
@ -226,8 +226,6 @@ namespace internal {
|
||||
"KeyedLoadElementMonomorphic") \
|
||||
V(KeyedStoreElementMonomorphic_string, \
|
||||
"KeyedStoreElementMonomorphic") \
|
||||
V(KeyedStoreAndGrowElementMonomorphic_string, \
|
||||
"KeyedStoreAndGrowElementMonomorphic") \
|
||||
V(stack_overflow_string, "kStackOverflowBoilerplate") \
|
||||
V(illegal_access_string, "illegal access") \
|
||||
V(out_of_memory_string, "out-of-memory") \
|
||||
@ -266,7 +264,7 @@ namespace internal {
|
||||
V(infinity_string, "Infinity") \
|
||||
V(minus_infinity_string, "-Infinity") \
|
||||
V(hidden_stack_trace_string, "v8::hidden_stack_trace") \
|
||||
V(query_colon_string, "(?:)") \
|
||||
V(query_colon_string, "(?:)")
|
||||
|
||||
// Forward declarations.
|
||||
class GCTracer;
|
||||
|
@ -2883,7 +2883,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
|
||||
Handle<Code> stub =
|
||||
KeyedStoreElementStub(is_jsarray,
|
||||
elements_kind,
|
||||
grow_mode_).GetCode(isolate());
|
||||
store_mode_).GetCode(isolate());
|
||||
|
||||
__ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
|
||||
|
||||
@ -3538,7 +3538,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : key
|
||||
@ -3563,7 +3563,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
if (is_js_array) {
|
||||
// Check that the key is within bounds.
|
||||
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
|
||||
if (grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
__ j(above_equal, &grow);
|
||||
} else {
|
||||
__ j(above_equal, &miss_force_generic);
|
||||
@ -3615,7 +3615,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ jmp(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Handle transition requiring the array to grow.
|
||||
__ bind(&grow);
|
||||
|
||||
@ -3693,7 +3693,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- eax : value
|
||||
// -- ecx : key
|
||||
@ -3716,7 +3716,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
if (is_js_array) {
|
||||
// Check that the key is within bounds.
|
||||
__ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis.
|
||||
if (grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
__ j(above_equal, &grow);
|
||||
} else {
|
||||
__ j(above_equal, &miss_force_generic);
|
||||
@ -3743,7 +3743,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ jmp(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Handle transition requiring the array to grow.
|
||||
__ bind(&grow);
|
||||
|
||||
|
185
src/ic.cc
185
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");
|
||||
}
|
||||
@ -1634,13 +1645,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.
|
||||
@ -1649,42 +1655,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);
|
||||
@ -1692,9 +1732,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) {
|
||||
@ -1711,19 +1753,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:
|
||||
@ -1742,7 +1794,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());
|
||||
}
|
||||
@ -1750,15 +1806,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()) {
|
||||
@ -1811,7 +1875,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1851,8 +1920,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 {
|
||||
|
63
src/ic.h
63
src/ic.h
@ -584,43 +584,6 @@ enum KeyedStoreIncrementLength {
|
||||
|
||||
class KeyedStoreIC: public StoreIC {
|
||||
public:
|
||||
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());
|
||||
}
|
||||
@ -662,7 +625,7 @@ class KeyedStoreIC: public StoreIC {
|
||||
}
|
||||
|
||||
Handle<Code> StoreElementStub(Handle<JSObject> receiver,
|
||||
StubKind stub_kind,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
private:
|
||||
@ -692,27 +655,12 @@ class KeyedStoreIC: public StoreIC {
|
||||
|
||||
static void Clear(Address address, Code* target);
|
||||
|
||||
StubKind GetStubKind(Handle<JSObject> receiver,
|
||||
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;
|
||||
}
|
||||
KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
|
||||
Handle<Object> key,
|
||||
Handle<Object> value);
|
||||
|
||||
Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
|
||||
StubKind stub_kind);
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
friend class IC;
|
||||
};
|
||||
@ -836,7 +784,6 @@ class ToBooleanIC: public IC {
|
||||
enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
|
||||
void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
|
||||
|
||||
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss);
|
||||
DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -3788,7 +3788,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : value
|
||||
// -- a1 : key
|
||||
@ -3950,7 +3950,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- a0 : value
|
||||
// -- a1 : key
|
||||
|
@ -152,11 +152,75 @@ enum CompareMapMode {
|
||||
ALLOW_ELEMENT_TRANSITION_MAPS
|
||||
};
|
||||
|
||||
enum KeyedAccessGrowMode {
|
||||
DO_NOT_ALLOW_JSARRAY_GROWTH,
|
||||
ALLOW_JSARRAY_GROWTH
|
||||
enum KeyedAccessStoreMode {
|
||||
STANDARD_STORE,
|
||||
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,
|
||||
STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS,
|
||||
STORE_NO_TRANSITION_HANDLE_COW
|
||||
};
|
||||
|
||||
|
||||
static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
|
||||
STANDARD_STORE;
|
||||
STATIC_ASSERT(STANDARD_STORE == 0);
|
||||
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 KeyedAccessStoreMode GetGrowStoreMode(
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
if (store_mode < STORE_AND_GROW_NO_TRANSITION) {
|
||||
store_mode = static_cast<KeyedAccessStoreMode>(
|
||||
static_cast<int>(store_mode) + kGrowICDelta);
|
||||
}
|
||||
return store_mode;
|
||||
}
|
||||
|
||||
|
||||
static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) {
|
||||
return store_mode > STANDARD_STORE &&
|
||||
store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT &&
|
||||
store_mode != STORE_AND_GROW_NO_TRANSITION;
|
||||
}
|
||||
|
||||
|
||||
static inline KeyedAccessStoreMode GetNonTransitioningStoreMode(
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
if (store_mode >= STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
|
||||
return store_mode;
|
||||
}
|
||||
if (store_mode >= STORE_AND_GROW_NO_TRANSITION) {
|
||||
return STORE_AND_GROW_NO_TRANSITION;
|
||||
}
|
||||
return STANDARD_STORE;
|
||||
}
|
||||
|
||||
|
||||
static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
|
||||
return store_mode >= STORE_AND_GROW_NO_TRANSITION &&
|
||||
store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
|
||||
}
|
||||
|
||||
|
||||
// Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
|
||||
enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
|
||||
|
||||
@ -4469,24 +4533,22 @@ class Code: public HeapObject {
|
||||
void FindAllCode(CodeHandleList* code_list, int length);
|
||||
|
||||
class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
|
||||
class ExtraICStateKeyedAccessGrowMode:
|
||||
public BitField<KeyedAccessGrowMode, 1, 1> {}; // NOLINT
|
||||
|
||||
static const int kExtraICStateGrowModeShift = 1;
|
||||
class ExtraICStateKeyedAccessStoreMode:
|
||||
public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT
|
||||
|
||||
static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) {
|
||||
return ExtraICStateStrictMode::decode(extra_ic_state);
|
||||
}
|
||||
|
||||
static inline KeyedAccessGrowMode GetKeyedAccessGrowMode(
|
||||
static inline KeyedAccessStoreMode GetKeyedAccessStoreMode(
|
||||
ExtraICState extra_ic_state) {
|
||||
return ExtraICStateKeyedAccessGrowMode::decode(extra_ic_state);
|
||||
return ExtraICStateKeyedAccessStoreMode::decode(extra_ic_state);
|
||||
}
|
||||
|
||||
static inline ExtraICState ComputeExtraICState(
|
||||
KeyedAccessGrowMode grow_mode,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
StrictModeFlag strict_mode) {
|
||||
return ExtraICStateKeyedAccessGrowMode::encode(grow_mode) |
|
||||
return ExtraICStateKeyedAccessStoreMode::encode(store_mode) |
|
||||
ExtraICStateStrictMode::encode(strict_mode);
|
||||
}
|
||||
|
||||
@ -4650,8 +4712,8 @@ class Code: public HeapObject {
|
||||
class TypeField: public BitField<StubType, 3, 3> {};
|
||||
class CacheHolderField: public BitField<InlineCacheHolderFlag, 6, 1> {};
|
||||
class KindField: public BitField<Kind, 7, 4> {};
|
||||
class ExtraICStateField: public BitField<ExtraICState, 11, 2> {};
|
||||
class IsPregeneratedField: public BitField<bool, 13, 1> {};
|
||||
class ExtraICStateField: public BitField<ExtraICState, 11, 5> {};
|
||||
class IsPregeneratedField: public BitField<bool, 16, 1> {};
|
||||
|
||||
// KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
|
||||
static const int kStackSlotsFirstBit = 0;
|
||||
@ -4708,7 +4770,7 @@ class Code: public HeapObject {
|
||||
class StackCheckTableOffsetField: public BitField<int, 0, 31> {};
|
||||
|
||||
// Signed field cannot be encoded using the BitField class.
|
||||
static const int kArgumentsCountShift = 14;
|
||||
static const int kArgumentsCountShift = 17;
|
||||
static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
|
||||
|
||||
// This constant should be encodable in an ARM instruction.
|
||||
|
@ -438,28 +438,26 @@ Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
|
||||
|
||||
Handle<Code> StubCache::ComputeKeyedStoreElement(
|
||||
Handle<Map> receiver_map,
|
||||
KeyedStoreIC::StubKind stub_kind,
|
||||
StrictModeFlag strict_mode,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
Code::ExtraICState extra_state =
|
||||
Code::ComputeExtraICState(grow_mode, strict_mode);
|
||||
Code::ComputeExtraICState(store_mode, strict_mode);
|
||||
Code::Flags flags = Code::ComputeMonomorphicFlags(
|
||||
Code::KEYED_STORE_IC, extra_state);
|
||||
|
||||
ASSERT(stub_kind == KeyedStoreIC::STORE_NO_TRANSITION ||
|
||||
stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
|
||||
|
||||
Handle<Name> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
|
||||
? isolate()->factory()->KeyedStoreElementMonomorphic_string()
|
||||
: isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_string();
|
||||
ASSERT(store_mode == STANDARD_STORE ||
|
||||
store_mode == STORE_AND_GROW_NO_TRANSITION);
|
||||
|
||||
Handle<String> name =
|
||||
isolate()->factory()->KeyedStoreElementMonomorphic_string();
|
||||
Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
|
||||
if (probe->IsCode()) return Handle<Code>::cast(probe);
|
||||
|
||||
KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
|
||||
KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode);
|
||||
Handle<Code> code = compiler.CompileStoreElement(receiver_map);
|
||||
|
||||
Map::UpdateCodeCache(receiver_map, name, code);
|
||||
ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode);
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -556,8 +554,7 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
|
||||
isolate_);
|
||||
if (probe->IsCode()) return Handle<Code>::cast(probe);
|
||||
|
||||
KeyedStoreStubCompiler compiler(isolate(), strict_mode,
|
||||
DO_NOT_ALLOW_JSARRAY_GROWTH);
|
||||
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
|
||||
Handle<Code> code =
|
||||
compiler.CompileStoreField(receiver, field_index, transition, name);
|
||||
JSObject::UpdateMapCodeCache(receiver, name, code);
|
||||
@ -914,18 +911,20 @@ Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
|
||||
|
||||
Handle<Code> StubCache::ComputeStoreElementPolymorphic(
|
||||
MapHandleList* receiver_maps,
|
||||
KeyedAccessGrowMode grow_mode,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
StrictModeFlag strict_mode) {
|
||||
ASSERT(store_mode == STANDARD_STORE ||
|
||||
store_mode == STORE_AND_GROW_NO_TRANSITION);
|
||||
Handle<PolymorphicCodeCache> cache =
|
||||
isolate_->factory()->polymorphic_code_cache();
|
||||
Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
|
||||
Code::ExtraICState extra_state = Code::ComputeExtraICState(store_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);
|
||||
KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode);
|
||||
Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
|
||||
PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
|
||||
return code;
|
||||
@ -1664,7 +1663,7 @@ Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
|
||||
Handle<Name> name,
|
||||
InlineCacheState state) {
|
||||
Code::ExtraICState extra_state =
|
||||
Code::ComputeExtraICState(grow_mode_, strict_mode_);
|
||||
Code::ComputeExtraICState(store_mode_, strict_mode_);
|
||||
Code::Flags flags =
|
||||
Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
|
||||
Handle<Code> code = GetCodeWithFlags(flags, name);
|
||||
@ -1698,12 +1697,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
|
||||
transitioned_map->elements_kind(),
|
||||
is_js_array,
|
||||
strict_mode_,
|
||||
grow_mode_).GetCode(isolate());
|
||||
store_mode_).GetCode(isolate());
|
||||
} else {
|
||||
cached_stub = KeyedStoreElementStub(
|
||||
is_js_array,
|
||||
elements_kind,
|
||||
grow_mode_).GetCode(isolate());
|
||||
store_mode_).GetCode(isolate());
|
||||
}
|
||||
ASSERT(!cached_stub.is_null());
|
||||
handlers.Add(cached_stub);
|
||||
|
@ -196,9 +196,8 @@ class StubCache {
|
||||
Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
|
||||
|
||||
Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
|
||||
KeyedStoreIC::StubKind stub_kind,
|
||||
StrictModeFlag strict_mode,
|
||||
KeyedAccessGrowMode grow_mode);
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
// ---
|
||||
|
||||
@ -262,7 +261,7 @@ class StubCache {
|
||||
|
||||
Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
|
||||
Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
|
||||
KeyedAccessGrowMode grow_mode,
|
||||
KeyedAccessStoreMode store_mode,
|
||||
StrictModeFlag strict_mode);
|
||||
|
||||
Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
|
||||
@ -803,10 +802,10 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
public:
|
||||
KeyedStoreStubCompiler(Isolate* isolate,
|
||||
StrictModeFlag strict_mode,
|
||||
KeyedAccessGrowMode grow_mode)
|
||||
KeyedAccessStoreMode store_mode)
|
||||
: StubCompiler(isolate),
|
||||
strict_mode_(strict_mode),
|
||||
grow_mode_(grow_mode) { }
|
||||
store_mode_(store_mode) { }
|
||||
|
||||
Handle<Code> CompileStoreField(Handle<JSObject> object,
|
||||
int index,
|
||||
@ -824,11 +823,11 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
static void GenerateStoreFastElement(MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
ElementsKind element_kind,
|
||||
KeyedAccessGrowMode grow_mode);
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
KeyedAccessGrowMode grow_mode);
|
||||
KeyedAccessStoreMode store_mode);
|
||||
|
||||
static void GenerateStoreExternalArray(MacroAssembler* masm,
|
||||
ElementsKind elements_kind);
|
||||
@ -841,7 +840,7 @@ class KeyedStoreStubCompiler: public StubCompiler {
|
||||
InlineCacheState state = MONOMORPHIC);
|
||||
|
||||
StrictModeFlag strict_mode_;
|
||||
KeyedAccessGrowMode grow_mode_;
|
||||
KeyedAccessStoreMode store_mode_;
|
||||
};
|
||||
|
||||
|
||||
|
@ -126,12 +126,12 @@ bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) {
|
||||
if (map_or_code->IsMap()) return true;
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
bool allow_growth =
|
||||
Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
|
||||
ALLOW_JSARRAY_GROWTH;
|
||||
bool standard_store =
|
||||
Code::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
|
||||
STANDARD_STORE;
|
||||
bool preliminary_checks =
|
||||
code->is_keyed_store_stub() &&
|
||||
!allow_growth &&
|
||||
standard_store &&
|
||||
code->ic_state() == MONOMORPHIC &&
|
||||
Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
|
||||
if (!preliminary_checks) return false;
|
||||
@ -146,10 +146,10 @@ bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
bool allow_growth =
|
||||
Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
|
||||
ALLOW_JSARRAY_GROWTH;
|
||||
return code->is_keyed_store_stub() && !allow_growth &&
|
||||
bool standard_store =
|
||||
Code::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
|
||||
STANDARD_STORE;
|
||||
return code->is_keyed_store_stub() && standard_store &&
|
||||
code->ic_state() == POLYMORPHIC;
|
||||
}
|
||||
return false;
|
||||
@ -218,6 +218,19 @@ Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
|
||||
}
|
||||
|
||||
|
||||
KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
|
||||
TypeFeedbackId ast_id) {
|
||||
Handle<Object> map_or_code = GetInfo(ast_id);
|
||||
if (map_or_code->IsCode()) {
|
||||
Handle<Code> code = Handle<Code>::cast(map_or_code);
|
||||
if (code->kind() == Code::KEYED_STORE_IC) {
|
||||
return Code::GetKeyedAccessStoreMode(code->extra_ic_state());
|
||||
}
|
||||
}
|
||||
return STANDARD_STORE;
|
||||
}
|
||||
|
||||
|
||||
void TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
|
||||
Handle<String> name,
|
||||
SmallMapList* types) {
|
||||
|
@ -255,6 +255,8 @@ class TypeFeedbackOracle: public ZoneObject {
|
||||
Handle<Map> LoadMonomorphicReceiverType(Property* expr);
|
||||
Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId ast_id);
|
||||
|
||||
KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id);
|
||||
|
||||
void LoadReceiverTypes(Property* expr,
|
||||
Handle<String> name,
|
||||
SmallMapList* types);
|
||||
|
@ -2705,7 +2705,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
|
||||
Handle<Code> stub =
|
||||
KeyedStoreElementStub(is_js_array,
|
||||
elements_kind,
|
||||
grow_mode_).GetCode(isolate());
|
||||
store_mode_).GetCode(isolate());
|
||||
|
||||
__ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
|
||||
|
||||
@ -3335,7 +3335,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
ElementsKind elements_kind,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : key
|
||||
@ -3360,7 +3360,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
// Check that the key is within bounds.
|
||||
if (is_js_array) {
|
||||
__ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
|
||||
if (grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
__ j(above_equal, &grow);
|
||||
} else {
|
||||
__ j(above_equal, &miss_force_generic);
|
||||
@ -3404,7 +3404,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ jmp(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Grow the array by a single element if possible.
|
||||
__ bind(&grow);
|
||||
|
||||
@ -3477,7 +3477,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
|
||||
void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
MacroAssembler* masm,
|
||||
bool is_js_array,
|
||||
KeyedAccessGrowMode grow_mode) {
|
||||
KeyedAccessStoreMode store_mode) {
|
||||
// ----------- S t a t e -------------
|
||||
// -- rax : value
|
||||
// -- rcx : key
|
||||
@ -3500,7 +3500,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
// Check that the key is within bounds.
|
||||
if (is_js_array) {
|
||||
__ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
|
||||
if (grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (IsGrowStoreMode(store_mode)) {
|
||||
__ j(above_equal, &grow);
|
||||
} else {
|
||||
__ j(above_equal, &miss_force_generic);
|
||||
@ -3530,7 +3530,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
|
||||
Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
|
||||
__ jmp(ic_miss, RelocInfo::CODE_TARGET);
|
||||
|
||||
if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
|
||||
if (is_js_array && IsGrowStoreMode(store_mode)) {
|
||||
// Grow the array by a single element if possible.
|
||||
__ bind(&grow);
|
||||
|
||||
|
@ -28,6 +28,10 @@
|
||||
// Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
|
||||
// Flags: --notrack_allocation_sites
|
||||
|
||||
// Limit the number of stress runs to reduce polymorphism it defeats some of
|
||||
// they assumptions made about how elements transitions work because transition
|
||||
// stubs end up going generic. Flags: --stress-runs=2
|
||||
|
||||
// Test element kind of objects.
|
||||
// Since --smi-only-arrays affects builtins, its default setting at compile
|
||||
// time sticks if built with snapshot. If --smi-only-arrays is deactivated
|
||||
|
Loading…
Reference in New Issue
Block a user