Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Unified Diff: src/code-stub-assembler.cc

Issue 2227703003: Reland "[KeyedLoadIC] Support Smi "handlers" for element loads" (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: add DCHECK Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « src/code-stub-assembler.h ('k') | src/field-index.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698