Index: src/code-stub-assembler.cc |
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
index 803403ec05a0b4a9acbce30dcce93a93c043ded4..6e3cd99dd5b2083f68d5dc37ab10aed543e705ed 100644 |
--- a/src/code-stub-assembler.cc |
+++ b/src/code-stub-assembler.cc |
@@ -2416,7 +2416,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, |
Node* elements = LoadElements(object); |
Node* length = LoadFixedArrayBaseLength(elements); |
- GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); |
+ GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found); |
Node* element = LoadFixedArrayElement(elements, index); |
Node* the_hole = TheHoleConstant(); |
@@ -2427,7 +2427,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, |
Node* elements = LoadElements(object); |
Node* length = LoadFixedArrayBaseLength(elements); |
- GotoIf(Int32GreaterThanOrEqual(index, SmiToWord32(length)), if_not_found); |
+ GotoUnless(Uint32LessThan(index, SmiToWord32(length)), if_not_found); |
if (kPointerSize == kDoubleSize) { |
Node* element = |
@@ -2456,7 +2456,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, |
Assert(Int32LessThan(LoadInstanceType(string), |
Int32Constant(FIRST_NONSTRING_TYPE))); |
Node* length = LoadStringLength(string); |
- GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); |
+ GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found); |
Goto(&if_isobjectorsmi); |
} |
Bind(&if_isslowstringwrapper); |
@@ -2466,7 +2466,7 @@ void CodeStubAssembler::TryLookupElement(Node* object, Node* map, |
Assert(Int32LessThan(LoadInstanceType(string), |
Int32Constant(FIRST_NONSTRING_TYPE))); |
Node* length = LoadStringLength(string); |
- GotoIf(Int32LessThan(index, SmiToWord32(length)), if_found); |
+ GotoIf(Uint32LessThan(index, SmiToWord32(length)), if_found); |
Goto(&if_isdictionary); |
} |
} |
@@ -2977,6 +2977,71 @@ void CodeStubAssembler::TryProbeStubCache( |
} |
} |
+void CodeStubAssembler::HandleLoadICHandlerCase(const LoadICParameters* p, |
+ Node* handler, Label* miss) { |
+ 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. |
+ { |
+ Variable var_double_value(this, MachineRepresentation::kFloat64); |
+ Label rebox_double(this, &var_double_value); |
+ |
+ Node* handler_word = SmiUntag(handler); |
+ // |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)); |
+ |
+ GotoIf(WordEqual(inobject_bit, IntPtrConstant(0)), &out_of_object); |
+ |
+ GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &inobject_double); |
+ Return(LoadObjectField(p->receiver, offset)); |
+ |
+ Bind(&inobject_double); |
+ if (FLAG_unbox_double_fields) { |
+ var_double_value.Bind( |
+ LoadObjectField(p->receiver, offset, MachineType::Float64())); |
+ } else { |
+ Node* mutable_heap_number = LoadObjectField(p->receiver, offset); |
+ var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); |
+ } |
+ Goto(&rebox_double); |
+ |
+ Bind(&out_of_object); |
+ Node* properties = LoadProperties(p->receiver); |
+ Node* value = LoadObjectField(properties, offset); |
+ GotoUnless(WordEqual(double_bit, IntPtrConstant(0)), &out_of_object_double); |
+ Return(value); |
+ |
+ Bind(&out_of_object_double); |
+ var_double_value.Bind(LoadHeapNumberValue(value)); |
+ Goto(&rebox_double); |
+ |
+ Bind(&rebox_double); |
+ Return(AllocateHeapNumberWithValue(var_double_value.value())); |
+ } |
+ |
+ // |handler| is a heap object. Must be code, call it. |
+ Bind(&call_handler); |
+ typedef LoadWithVectorDescriptor Descriptor; |
+ TailCallStub(Descriptor(isolate()), handler, p->context, |
+ Arg(Descriptor::kReceiver, p->receiver), |
+ Arg(Descriptor::kName, p->name), |
+ Arg(Descriptor::kSlot, p->slot), |
+ Arg(Descriptor::kVector, p->vector)); |
+} |
+ |
void CodeStubAssembler::LoadIC(const LoadICParameters* p) { |
Variable var_handler(this, MachineRepresentation::kTagged); |
// TODO(ishell): defer blocks when it works. |
@@ -2991,66 +3056,7 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) { |
&var_handler, &try_polymorphic); |
Bind(&if_handler); |
{ |
- Comment("LoadIC_if_handler"); |
- Label call_handler(this); |
- Node* handler = var_handler.value(); |
- GotoUnless(WordIsSmi(handler), &call_handler); |
- |
- // |handler| is a Smi. It encodes a field index as obtained by |
- // FieldIndex.GetLoadByFieldOffset(). |
- { |
- Label inobject_double(this), out_of_object(this), |
- out_of_object_double(this); |
- Variable var_double_value(this, MachineRepresentation::kFloat64); |
- Label rebox_double(this, &var_double_value); |
- |
- Node* handler_word = SmiToWord32(handler); |
- // handler == (offset << 1) | is_double. |
- Node* double_bit = Word32And(handler_word, Int32Constant(1)); |
- Node* offset = Word32Sar(handler_word, Int32Constant(1)); |
- |
- // Negative index -> out of object. |
- GotoIf(Int32LessThan(offset, Int32Constant(0)), &out_of_object); |
- |
- Node* offset_ptr = ChangeInt32ToIntPtr(offset); |
- GotoUnless(Word32Equal(double_bit, Int32Constant(0)), &inobject_double); |
- Return(LoadObjectField(p->receiver, offset_ptr)); |
- |
- Bind(&inobject_double); |
- if (FLAG_unbox_double_fields) { |
- var_double_value.Bind( |
- LoadObjectField(p->receiver, offset_ptr, MachineType::Float64())); |
- } else { |
- Node* mutable_heap_number = LoadObjectField(p->receiver, offset_ptr); |
- var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); |
- } |
- Goto(&rebox_double); |
- |
- Bind(&out_of_object); |
- // |offset| == -actual_offset |
- offset_ptr = ChangeInt32ToIntPtr(Int32Sub(Int32Constant(0), offset)); |
- Node* properties = LoadProperties(p->receiver); |
- Node* value = LoadObjectField(properties, offset_ptr); |
- GotoUnless(Word32Equal(double_bit, Int32Constant(0)), |
- &out_of_object_double); |
- Return(value); |
- |
- Bind(&out_of_object_double); |
- var_double_value.Bind(LoadHeapNumberValue(value)); |
- Goto(&rebox_double); |
- |
- Bind(&rebox_double); |
- Return(AllocateHeapNumberWithValue(var_double_value.value())); |
- } |
- |
- // |handler| is a heap object. Must be code, call it. |
- Bind(&call_handler); |
- typedef LoadWithVectorDescriptor Descriptor; |
- TailCallStub(Descriptor(isolate()), var_handler.value(), p->context, |
- Arg(Descriptor::kReceiver, p->receiver), |
- Arg(Descriptor::kName, p->name), |
- Arg(Descriptor::kSlot, p->slot), |
- Arg(Descriptor::kVector, p->vector)); |
+ HandleLoadICHandlerCase(p, var_handler.value(), &miss); |
} |
Bind(&try_polymorphic); |
@@ -3081,6 +3087,68 @@ void CodeStubAssembler::LoadIC(const LoadICParameters* p) { |
} |
} |
+void CodeStubAssembler::KeyedLoadIC(const LoadICParameters* p) { |
+ Variable var_handler(this, MachineRepresentation::kTagged); |
+ // TODO(ishell): defer blocks when it works. |
+ Label if_handler(this, &var_handler), try_polymorphic(this), |
+ try_megamorphic(this /*, Label::kDeferred*/), |
+ try_polymorphic_name(this /*, Label::kDeferred*/), |
+ miss(this /*, Label::kDeferred*/); |
+ |
+ Node* receiver_map = LoadReceiverMap(p->receiver); |
+ |
+ // Check monomorphic case. |
+ Node* feedback = TryMonomorphicCase(p, receiver_map, &if_handler, |
+ &var_handler, &try_polymorphic); |
+ Bind(&if_handler); |
+ { |
+ HandleLoadICHandlerCase(p, var_handler.value(), &miss); |
+ } |
+ |
+ Bind(&try_polymorphic); |
+ { |
+ // Check polymorphic case. |
+ Comment("KeyedLoadIC_try_polymorphic"); |
+ GotoUnless( |
+ WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)), |
+ &try_megamorphic); |
+ HandlePolymorphicCase(p, receiver_map, feedback, &if_handler, &var_handler, |
+ &miss, 2); |
+ } |
+ |
+ Bind(&try_megamorphic); |
+ { |
+ // Check megamorphic case. |
+ Comment("KeyedLoadIC_try_megamorphic"); |
+ GotoUnless( |
+ WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)), |
+ &try_polymorphic_name); |
+ // TODO(jkummerow): Inline this? Or some of it? |
+ TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context, |
+ p->receiver, p->name, p->slot, p->vector); |
+ } |
+ Bind(&try_polymorphic_name); |
+ { |
+ // We might have a name in feedback, and a fixed array in the next slot. |
+ Comment("KeyedLoadIC_try_polymorphic_name"); |
+ GotoUnless(WordEqual(feedback, p->name), &miss); |
+ // If the name comparison succeeded, we know we have a fixed array with |
+ // at least one map/handler pair. |
+ Node* offset = ElementOffsetFromIndex( |
+ p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS, |
+ FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag); |
+ Node* array = Load(MachineType::AnyTagged(), p->vector, offset); |
+ HandlePolymorphicCase(p, receiver_map, array, &if_handler, &var_handler, |
+ &miss, 1); |
+ } |
+ Bind(&miss); |
+ { |
+ Comment("KeyedLoadIC_miss"); |
+ TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver, |
+ p->name, p->slot, p->vector); |
+ } |
+} |
+ |
void CodeStubAssembler::LoadGlobalIC(const LoadICParameters* p) { |
Label try_handler(this), miss(this); |
Node* weak_cell = |