| Index: src/code-stub-assembler.cc
|
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
|
| index 912f17118b8e9f1633388bbf393af1304a823ea4..4479086ed78030baf6af758c894299997090650d 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-configuration.h"
|
| #include "src/ic/stub-cache.h"
|
|
|
| namespace v8 {
|
| @@ -3428,31 +3429,286 @@ void CodeStubAssembler::TryProbeStubCache(
|
| }
|
| }
|
|
|
| -void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p,
|
| - Node* handler, Label* miss) {
|
| +Node* CodeStubAssembler::TryToIntptr(Node* key, Label* miss) {
|
| + Variable var_intptr_key(this, MachineType::PointerRepresentation());
|
| + Label done(this, &var_intptr_key), key_is_smi(this);
|
| + GotoIf(WordIsSmi(key), &key_is_smi);
|
| + // Try to convert a heap number to a Smi.
|
| + GotoUnless(WordEqual(LoadMap(key), HeapNumberMapConstant()), miss);
|
| + {
|
| + Node* value = LoadHeapNumberValue(key);
|
| + Node* int_value = RoundFloat64ToInt32(value);
|
| + GotoUnless(Float64Equal(value, ChangeInt32ToFloat64(int_value)), miss);
|
| + var_intptr_key.Bind(ChangeInt32ToIntPtr(int_value));
|
| + Goto(&done);
|
| + }
|
| +
|
| + Bind(&key_is_smi);
|
| + {
|
| + var_intptr_key.Bind(SmiUntag(key));
|
| + Goto(&done);
|
| + }
|
| +
|
| + Bind(&done);
|
| + return var_intptr_key.value();
|
| +}
|
| +
|
| +// |is_jsarray| should be non-zero for JSArrays.
|
| +void CodeStubAssembler::EmitBoundsCheck(Node* object, Node* elements,
|
| + Node* intptr_key, Node* is_jsarray,
|
| + Label* miss) {
|
| + Variable var_length(this, MachineRepresentation::kTagged);
|
| + Label if_array(this), length_loaded(this, &var_length);
|
| + GotoUnless(WordEqual(is_jsarray, IntPtrConstant(0)), &if_array);
|
| + {
|
| + var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
|
| + Goto(&length_loaded);
|
| + }
|
| + Bind(&if_array);
|
| + {
|
| + var_length.Bind(SmiUntag(LoadObjectField(object, JSArray::kLengthOffset)));
|
| + Goto(&length_loaded);
|
| + }
|
| + Bind(&length_loaded);
|
| + GotoUnless(UintPtrLessThan(intptr_key, var_length.value()), miss);
|
| +}
|
| +
|
| +// |key| should be untagged (int32).
|
| +void CodeStubAssembler::EmitElementLoad(Node* object, Node* elements,
|
| + Node* elements_kind, Node* key,
|
| + Label* if_hole, Label* rebox_double,
|
| + Variable* var_double_value,
|
| + Label* miss) {
|
| + Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
|
| + if_fast_double(this), if_fast_holey_double(this),
|
| + unimplemented_elements_kind(this);
|
| + STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
|
| + GotoIf(
|
| + IntPtrGreaterThanOrEqual(
|
| + elements_kind, IntPtrConstant(FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND)),
|
| + &if_typed_array);
|
| +
|
| + int32_t kinds[] = {// Handled by if_fast_packed.
|
| + FAST_SMI_ELEMENTS, FAST_ELEMENTS,
|
| + // Handled by if_fast_holey.
|
| + FAST_HOLEY_SMI_ELEMENTS, FAST_HOLEY_ELEMENTS,
|
| + // Handled by if_fast_double.
|
| + FAST_DOUBLE_ELEMENTS,
|
| + // Handled by if_fast_holey_double.
|
| + FAST_HOLEY_DOUBLE_ELEMENTS};
|
| + Label* labels[] = {// FAST_{SMI,}_ELEMENTS
|
| + &if_fast_packed, &if_fast_packed,
|
| + // FAST_HOLEY_{SMI,}_ELEMENTS
|
| + &if_fast_holey, &if_fast_holey,
|
| + // FAST_DOUBLE_ELEMENTS
|
| + &if_fast_double,
|
| + // FAST_HOLEY_DOUBLE_ELEMENTS
|
| + &if_fast_holey_double};
|
| + Switch(elements_kind, &unimplemented_elements_kind, kinds, labels,
|
| + arraysize(kinds));
|
| + Bind(&unimplemented_elements_kind);
|
| + {
|
| + // Crash if we get here.
|
| + DebugBreak();
|
| + Goto(miss);
|
| + }
|
| +
|
| + Bind(&if_fast_packed);
|
| + {
|
| + Comment("fast packed elements");
|
| + // 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.
|
| + Return(LoadFixedArrayElement(elements, key));
|
| + }
|
| +
|
| + Bind(&if_fast_holey);
|
| + {
|
| + Comment("fast holey elements");
|
| + Node* element = LoadFixedArrayElement(elements, key);
|
| + GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
|
| + Return(element);
|
| + }
|
| +
|
| + Bind(&if_fast_double);
|
| + {
|
| + Comment("packed double elements");
|
| + var_double_value->Bind(
|
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Float64()));
|
| + Goto(rebox_double);
|
| + }
|
| +
|
| + Bind(&if_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), if_hole);
|
| + } else {
|
| + Node* element_upper = LoadFixedDoubleArrayElement(
|
| + elements, key, MachineType::Uint32(), kIeeeDoubleExponentWordOffset);
|
| + GotoIf(Word32Equal(element_upper, Int32Constant(kHoleNanUpper32)),
|
| + if_hole);
|
| + }
|
| + var_double_value->Bind(
|
| + LoadFixedDoubleArrayElement(elements, key, MachineType::Float64()));
|
| + Goto(rebox_double);
|
| + }
|
| +
|
| + Bind(&if_typed_array);
|
| + {
|
| + Comment("typed elements");
|
| + // Check if buffer has been neutered.
|
| + Node* buffer = LoadObjectField(object, JSArrayBufferView::kBufferOffset);
|
| + Node* bitfield = LoadObjectField(buffer, JSArrayBuffer::kBitFieldOffset,
|
| + MachineType::Uint32());
|
| + Node* neutered_bit =
|
| + Word32And(bitfield, Int32Constant(JSArrayBuffer::WasNeutered::kMask));
|
| + 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];
|
| + }
|
| + }
|
| +}
|
| +
|
| +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. See handler-configuration.h
|
| + // for the encoding format.
|
| {
|
| Variable var_double_value(this, MachineRepresentation::kFloat64);
|
| Label rebox_double(this, &var_double_value);
|
|
|
| Node* handler_word = SmiUntag(handler);
|
| + if (support_elements == kSupportElements) {
|
| + Label property(this);
|
| + Node* handler_type =
|
| + WordAnd(handler_word, IntPtrConstant(LoadHandlerTypeBit::kMask));
|
| + GotoUnless(
|
| + WordEqual(handler_type, IntPtrConstant(kLoadICHandlerForElements)),
|
| + &property);
|
| +
|
| + Comment("element_load");
|
| + Node* key = TryToIntptr(p->name, miss);
|
| + Node* elements = LoadElements(p->receiver);
|
| + Node* is_jsarray =
|
| + WordAnd(handler_word, IntPtrConstant(KeyedLoadIsJsArray::kMask));
|
| + EmitBoundsCheck(p->receiver, elements, key, is_jsarray, miss);
|
| + Label if_hole(this);
|
| +
|
| + Node* elements_kind = BitFieldDecode<KeyedLoadElementsKind>(handler_word);
|
| +
|
| + EmitElementLoad(p->receiver, elements, elements_kind, key, &if_hole,
|
| + &rebox_double, &var_double_value, miss);
|
| +
|
| + Bind(&if_hole);
|
| + {
|
| + Comment("convert hole");
|
| + Node* convert_hole =
|
| + WordAnd(handler_word, IntPtrConstant(KeyedLoadConvertHole::kMask));
|
| + GotoIf(WordEqual(convert_hole, IntPtrConstant(0)), miss);
|
| + Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
|
| + DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
|
| + GotoUnless(
|
| + WordEqual(
|
| + LoadObjectField(protector_cell, PropertyCell::kValueOffset),
|
| + SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))),
|
| + miss);
|
| + Return(UndefinedConstant());
|
| + }
|
| +
|
| + Bind(&property);
|
| + Comment("property_load");
|
| + }
|
| +
|
| // |handler_word| is a field index as obtained by
|
| // FieldIndex.GetLoadByFieldOffset():
|
| Label inobject_double(this), out_of_object(this),
|
| out_of_object_double(this);
|
| - Node* inobject_bit = WordAnd(
|
| - handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsInobject::kMask));
|
| - Node* double_bit = WordAnd(
|
| - handler_word, IntPtrConstant(FieldIndex::FieldOffsetIsDouble::kMask));
|
| - Node* offset = WordSar(
|
| - handler_word, IntPtrConstant(FieldIndex::FieldOffsetOffset::kShift));
|
| + Node* inobject_bit =
|
| + WordAnd(handler_word, IntPtrConstant(FieldOffsetIsInobject::kMask));
|
| + Node* double_bit =
|
| + WordAnd(handler_word, IntPtrConstant(FieldOffsetIsDouble::kMask));
|
| + Node* offset =
|
| + WordSar(handler_word, IntPtrConstant(FieldOffsetOffset::kShift));
|
|
|
| GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object);
|
|
|
| @@ -3553,7 +3809,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);
|
|
|