Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 6e3cd99dd5b2083f68d5dc37ab10aed543e705ed..fa927c21cc7337e7bd25e015f10104457b1eb990 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -6,6 +6,7 @@ |
| #include "src/code-factory.h" |
| #include "src/frames-inl.h" |
| #include "src/frames.h" |
| +#include "src/ic/handler-compiler.h" |
| #include "src/ic/stub-cache.h" |
| namespace v8 { |
| @@ -2977,21 +2978,214 @@ void CodeStubAssembler::TryProbeStubCache( |
| } |
| } |
| -void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p, |
| - Node* handler, Label* miss) { |
| +void CodeStubAssembler::HandleLoadICHandlerCase( |
| + const LoadICParameters* p, Node* handler, Label* miss, |
| + ElementSupport support_elements) { |
| Comment("have_handler"); |
| Label call_handler(this); |
| GotoUnless(WordIsSmi(handler), &call_handler); |
| - // |handler| is a Smi. It encodes a field index as obtained by |
| - // FieldIndex.GetLoadByFieldOffset(). |
| - // TODO(jkummerow): For KeyedLoadICs, extend this scheme to encode |
| - // fast *element* loads. |
| + // |handler| is a Smi, encoding what to do. The last bit distinguishes |
| + // element and property loads. |
| { |
| Variable var_double_value(this, MachineRepresentation::kFloat64); |
| Label rebox_double(this, &var_double_value); |
| Node* handler_word = SmiUntag(handler); |
| + if (support_elements == kSupportElements) { |
|
Igor Sheludko
2016/07/28 10:01:11
I think this new code (and maybe the property case
Jakob Kummerow
2016/08/03 11:44:11
Done (did some splitting, though not exactly here)
|
| + Variable var_length(this, MachineRepresentation::kTagged); |
| + Label property(this), is_array(this), length_loaded(this, &var_length); |
| + Node* is_element_bit = WordAnd(handler_word, IntPtrConstant(1)); |
|
Igor Sheludko
2016/07/28 10:01:11
It would be nice to have such a SmiHandlerIsProper
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + GotoUnless(WordEqual(is_element_bit, IntPtrConstant(0)), &property); |
| + |
| + Comment("element_load"); |
| + GotoUnless(WordIsSmi(p->name), miss); |
|
Igor Sheludko
2016/07/28 10:01:11
Future improvement: support "123"-like unique stri
Jakob Kummerow
2016/08/03 11:44:09
Possibly, yes. That change would have to be made i
|
| + Node* key = SmiUntag(p->name); |
| + Node* elements = LoadElements(p->receiver); |
| + Node* is_jsarray = WordAnd( |
| + handler_word, |
| + IntPtrConstant(ElementHandlerCompiler::KeyedLoadIsJsarray::kMask)); |
| + GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &is_array); |
| + var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements))); |
| + Goto(&length_loaded); |
| + Bind(&is_array); |
|
Igor Sheludko
2016/07/28 10:01:11
Consider wrapping blocks in {} for readability.
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + var_length.Bind( |
| + SmiUntag(LoadObjectField(p->receiver, JSArray::kLengthOffset))); |
| + Goto(&length_loaded); |
| + |
| + Bind(&length_loaded); |
|
Igor Sheludko
2016/07/28 10:01:11
Same here.
Jakob Kummerow
2016/08/03 11:44:12
Done.
|
| + // Bounds check. |
| + GotoUnless(UintPtrLessThan(key, var_length.value()), miss); |
| + Node* convert_hole = WordAnd( |
|
Igor Sheludko
2016/07/28 10:01:11
You can probably move this to if_hole block althou
Jakob Kummerow
2016/08/03 11:44:11
Done.
|
| + handler_word, |
| + IntPtrConstant(ElementHandlerCompiler::KeyedLoadConvertHole::kMask)); |
| + Node* elements_kind = |
| + WordShr(handler_word, |
| + IntPtrConstant( |
| + ElementHandlerCompiler::KeyedLoadElementsKind::kShift)); |
| + |
| + Label typed_array(this), fast_packed(this), fast_holey(this), |
|
Igor Sheludko
2016/07/28 10:01:10
As far as I understand we have a kind of naming co
Jakob Kummerow
2016/08/03 11:44:11
Done.
|
| + fast_double(this), fast_holey_double(this), hole(this); |
|
Igor Sheludko
2016/07/28 10:01:11
STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYP
Jakob Kummerow
2016/08/03 11:44:11
Done.
|
| + GotoIf(IntPtrGreaterThanOrEqual( |
| + elements_kind, |
| + IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)), |
| + &typed_array); |
| +#define JUMP_IF_KIND(kind, label) \ |
| + GotoIf(WordEqual(elements_kind, IntPtrConstant(kind)), label); |
|
Igor Sheludko
2016/07/28 10:01:10
It looks like a switch construct will fit better h
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + |
| + JUMP_IF_KIND(FAST_SMI_ELEMENTS, &fast_packed); |
| + JUMP_IF_KIND(FAST_ELEMENTS, &fast_packed); |
| + JUMP_IF_KIND(FAST_HOLEY_SMI_ELEMENTS, &fast_holey); |
| + JUMP_IF_KIND(FAST_HOLEY_ELEMENTS, &fast_holey); |
| + JUMP_IF_KIND(FAST_DOUBLE_ELEMENTS, &fast_double); |
| + JUMP_IF_KIND(FAST_HOLEY_DOUBLE_ELEMENTS, &fast_holey_double); |
| + // All other kinds are unimplemented. |
| + DebugBreak(); |
|
Igor Sheludko
2016/07/28 10:01:11
?
Jakob Kummerow
2016/08/03 11:44:11
I want to crash if we get here. Think "UNREACHABLE
|
| + Goto(miss); |
| +#undef JUMP_IF_KIND |
| + |
| + Bind(&fast_packed); |
| + Comment("fast packed elements"); |
|
Igor Sheludko
2016/07/28 10:01:11
Consider wrapping blocks in {} for readability.
Jakob Kummerow
2016/08/03 11:44:11
Done.
|
| + // TODO(jkummerow): The Load*Element helpers add movsxlq instructions |
| + // on x64 which we don't need here, because |key| is an IntPtr already. |
| + // Do something about that. |
|
Igor Sheludko
2016/07/28 10:01:10
We just need to introduce INTPTR_PARAMETERS mode.
Jakob Kummerow
2016/08/03 11:44:09
Yes, that's what I was thinking too. Follow-up CL.
|
| + Return(LoadFixedArrayElement(elements, key)); |
| + |
| + Bind(&fast_holey); |
| + { |
| + Comment("fast holey elements"); |
| + Node* element = LoadFixedArrayElement(elements, key); |
| + GotoIf(WordEqual(element, TheHoleConstant()), &hole); |
| + Return(element); |
| + } |
| + |
| + Bind(&fast_double); |
| + Comment("packed double elements"); |
|
Igor Sheludko
2016/07/28 10:01:11
Same here.
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + var_double_value.Bind( |
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); |
| + Goto(&rebox_double); |
| + |
| + Bind(&fast_holey_double); |
| + { |
| + Comment("holey double elements"); |
| + if (kPointerSize == kDoubleSize) { |
| + Node* raw_element = |
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Uint64()); |
| + Node* the_hole = Int64Constant(kHoleNanInt64); |
| + GotoIf(Word64Equal(raw_element, the_hole), &hole); |
| + } else { |
| + Node* element_upper = |
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Uint32(), |
| + kIeeeDoubleExponentWordOffset); |
| + GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)), |
| + &hole); |
| + } |
| + var_double_value.Bind( |
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Float64())); |
| + Goto(&rebox_double); |
| + } |
| + |
| + Bind(&hole); |
| + { |
| + Comment("convert hole"); |
| + GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss); |
| + Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
| + GotoUnless( |
| + WordEqual(LoadObjectField(protector_cell, Cell::kValueOffset), |
| + SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
| + miss); |
| + Return(UndefinedConstant()); |
| + } |
| + |
| + Bind(&typed_array); |
|
Igor Sheludko
2016/07/28 10:01:11
And here.
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + Comment("typed elements"); |
| + // Check if buffer has been neutered. |
| + Node* buffer = |
| + LoadObjectField(p->receiver, JSArrayBufferView::kBufferOffset); |
| + Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset, |
| + MachineType::Uint32()); |
| + Node* neutered_bit = Word32And( |
| + bitfield, Int32Constant(1 << JSArrayBuffer::WasNeutered::kShift)); |
|
Igor Sheludko
2016/07/28 10:01:11
JSArrayBuffer::WasNeutered::kMask?
Jakob Kummerow
2016/08/03 11:44:09
Done.
|
| + GotoUnless(Word32Equal(neutered_bit, Int32Constant(0)), miss); |
| + // Backing store = external_pointer + base_pointer. |
| + Node* external_pointer = |
| + LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| + MachineType::Pointer()); |
| + Node* base_pointer = |
| + LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
| + Node* backing_store = IntPtrAdd(external_pointer, base_pointer); |
| + |
| + const int kTypedElementsKindCount = |
| + LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND - |
| + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1; |
| + Label* elements_kind_labels[kTypedElementsKindCount]; |
| + int32_t elements_kinds[kTypedElementsKindCount]; |
| + for (int i = 0; i < kTypedElementsKindCount; i++) { |
| + elements_kinds[i] = i + FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; |
| + elements_kind_labels[i] = new Label(this); |
| + } |
| + Switch(elements_kind, miss, elements_kinds, elements_kind_labels, |
| + static_cast<size_t>(kTypedElementsKindCount)); |
| + |
| + for (int i = 0; i < kTypedElementsKindCount; i++) { |
| + ElementsKind kind = static_cast<ElementsKind>(elements_kinds[i]); |
| + Bind(elements_kind_labels[i]); |
| + Comment(ElementsKindToString(kind)); |
| + switch (kind) { |
| + case UINT8_ELEMENTS: |
| + case UINT8_CLAMPED_ELEMENTS: |
| + Return(SmiTag(Load(MachineType::Uint8(), backing_store, key))); |
| + break; |
| + case INT8_ELEMENTS: |
| + Return(SmiTag(Load(MachineType::Int8(), backing_store, key))); |
| + break; |
| + case UINT16_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(1)); |
| + Return(SmiTag(Load(MachineType::Uint16(), backing_store, index))); |
| + break; |
| + } |
| + case INT16_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(1)); |
| + Return(SmiTag(Load(MachineType::Int16(), backing_store, index))); |
| + break; |
| + } |
| + case UINT32_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(2)); |
| + Node* element = Load(MachineType::Uint32(), backing_store, index); |
| + Return(ChangeUint32ToTagged(element)); |
| + break; |
| + } |
| + case INT32_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(2)); |
| + Node* element = Load(MachineType::Int32(), backing_store, index); |
| + Return(ChangeInt32ToTagged(element)); |
| + break; |
| + } |
| + case FLOAT32_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(2)); |
| + Node* element = Load(MachineType::Float32(), backing_store, index); |
| + var_double_value.Bind(ChangeFloat32ToFloat64(element)); |
| + Goto(&rebox_double); |
| + break; |
| + } |
| + case FLOAT64_ELEMENTS: { |
| + Node* index = WordShl(key, IntPtrConstant(3)); |
| + Node* element = Load(MachineType::Float64(), backing_store, index); |
| + var_double_value.Bind(element); |
| + Goto(&rebox_double); |
| + break; |
| + } |
| + default: |
| + UNREACHABLE(); |
| + } |
| + // Don't forget to clean up. |
| + delete elements_kind_labels[i]; |
| + } |
| + |
| + Bind(&property); |
| + Comment("property_load"); |
| + } |
| + |
| // |handler_word| is a field index as obtained by |
| // FieldIndex.GetLoadByFieldOffset(): |
| Label inobject_double(this), out_of_object(this), |
| @@ -3102,7 +3296,7 @@ void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) { |
| &var_handler, &try_polymorphic); |
| Bind(&if_handler); |
| { |
| - HandleLoadICHandlerCase(p, var_handler.value(), &miss); |
| + HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); |
| } |
| Bind(&try_polymorphic); |