summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic/accessor-assembler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ic/accessor-assembler.cc')
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc833
1 files changed, 462 insertions, 371 deletions
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index c2b2d17950..d3379ab6d2 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -3,25 +3,27 @@
// found in the LICENSE file.
#include "src/ic/accessor-assembler.h"
-#include "src/ic/accessor-assembler-impl.h"
#include "src/code-factory.h"
#include "src/code-stubs.h"
+#include "src/counters.h"
#include "src/ic/handler-configuration.h"
#include "src/ic/stub-cache.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
using compiler::CodeAssemblerState;
+using compiler::Node;
//////////////////// Private helpers.
-Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector,
- Node* receiver_map,
- Label* if_handler,
- Variable* var_handler,
- Label* if_miss) {
+Node* AccessorAssembler::TryMonomorphicCase(Node* slot, Node* vector,
+ Node* receiver_map,
+ Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
Comment("TryMonomorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@@ -51,9 +53,11 @@ Node* AccessorAssemblerImpl::TryMonomorphicCase(Node* slot, Node* vector,
return feedback;
}
-void AccessorAssemblerImpl::HandlePolymorphicCase(
- Node* receiver_map, Node* feedback, Label* if_handler,
- Variable* var_handler, Label* if_miss, int unroll_count) {
+void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
+ Node* feedback, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss,
+ int unroll_count) {
Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@@ -78,7 +82,7 @@ void AccessorAssemblerImpl::HandlePolymorphicCase(
Node* init = IntPtrConstant(unroll_count * kEntrySize);
Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
BuildFastLoop(
- MachineType::PointerRepresentation(), init, length,
+ init, length,
[this, receiver_map, feedback, if_handler, var_handler](Node* index) {
Node* cached_map =
LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
@@ -93,12 +97,12 @@ void AccessorAssemblerImpl::HandlePolymorphicCase(
Bind(&next_entry);
},
- kEntrySize, IndexAdvanceMode::kPost);
+ kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// The loop falls through if no handler was found.
Goto(if_miss);
}
-void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
+void AccessorAssembler::HandleKeyedStorePolymorphicCase(
Node* receiver_map, Node* feedback, Label* if_handler,
Variable* var_handler, Label* if_transition_handler,
Variable* var_transition_map_cell, Label* if_miss) {
@@ -109,7 +113,7 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
Node* init = IntPtrConstant(0);
Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
- BuildFastLoop(MachineType::PointerRepresentation(), init, length,
+ BuildFastLoop(init, length,
[this, receiver_map, feedback, if_handler, var_handler,
if_transition_handler, var_transition_map_cell](Node* index) {
Node* cached_map =
@@ -130,15 +134,17 @@ void AccessorAssemblerImpl::HandleKeyedStorePolymorphicCase(
Bind(&next_entry);
},
- kEntrySize, IndexAdvanceMode::kPost);
+ kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// The loop falls through if no handler was found.
Goto(if_miss);
}
-void AccessorAssemblerImpl::HandleLoadICHandlerCase(
+void AccessorAssembler::HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
Comment("have_handler");
+ ExitPoint direct_exit(this);
+
Variable var_holder(this, MachineRepresentation::kTagged);
var_holder.Bind(p->receiver);
Variable var_smi_handler(this, MachineRepresentation::kTagged);
@@ -155,14 +161,14 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase(
Bind(&if_smi_handler);
{
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
- miss, support_elements);
+ miss, &direct_exit, support_elements);
}
Bind(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss, false);
+ &if_smi_handler, miss, &direct_exit, false);
}
Bind(&call_handler);
@@ -173,9 +179,9 @@ void AccessorAssemblerImpl::HandleLoadICHandlerCase(
}
}
-void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
+void AccessorAssembler::HandleLoadICSmiHandlerCase(
const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
- ElementSupport support_elements) {
+ ExitPoint* exit_point, ElementSupport support_elements) {
Variable var_double_value(this, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
@@ -183,7 +189,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
if (support_elements == kSupportElements) {
Label property(this);
- GotoUnless(
+ GotoIfNot(
WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
&property);
@@ -199,7 +205,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
EmitElementLoad(holder, elements, elements_kind, intptr_index,
is_jsarray_condition, &if_hole, &rebox_double,
&var_double_value, &unimplemented_elements_kind,
- out_of_bounds, miss);
+ out_of_bounds, miss, exit_point);
Bind(&unimplemented_elements_kind);
{
@@ -212,14 +218,14 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Bind(&if_hole);
{
Comment("convert hole");
- GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
+ GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex);
DCHECK(isolate()->heap()->array_protector()->IsPropertyCell());
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset),
SmiConstant(Smi::FromInt(Isolate::kProtectorValid))),
miss);
- Return(UndefinedConstant());
+ exit_point->Return(UndefinedConstant());
}
Bind(&property);
@@ -243,7 +249,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
{
Label is_double(this);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
- Return(LoadObjectField(holder, offset));
+ exit_point->Return(LoadObjectField(holder, offset));
Bind(&is_double);
if (FLAG_unbox_double_fields) {
@@ -262,7 +268,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Node* properties = LoadProperties(holder);
Node* value = LoadObjectField(properties, offset);
GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
- Return(value);
+ exit_point->Return(value);
Bind(&is_double);
var_double_value.Bind(LoadHeapNumberValue(value));
@@ -270,7 +276,7 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
}
Bind(&rebox_double);
- Return(AllocateHeapNumberWithValue(var_double_value.value()));
+ exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
}
Bind(&constant);
@@ -287,18 +293,19 @@ void AccessorAssemblerImpl::HandleLoadICSmiHandlerCase(
Label if_accessor_info(this);
GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
&if_accessor_info);
- Return(value);
+ exit_point->Return(value);
Bind(&if_accessor_info);
Callable callable = CodeFactory::ApiGetter(isolate());
- TailCallStub(callable, p->context, p->receiver, holder, value);
+ exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
+ value);
}
}
-void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
+void AccessorAssembler::HandleLoadICProtoHandlerCase(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
- bool throw_reference_error_if_nonexistent) {
+ ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
@@ -327,7 +334,7 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
Node* handler_flags = SmiUntag(smi_handler);
Label check_prototypes(this);
- GotoUnless(
+ GotoIfNot(
IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
&check_prototypes);
{
@@ -350,9 +357,10 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
// This is a handler for a load of a non-existent value.
if (throw_reference_error_if_nonexistent) {
- TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name);
+ exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
+ p->name);
} else {
- Return(UndefinedConstant());
+ exit_point->Return(UndefinedConstant());
}
Bind(&load_existent);
@@ -368,15 +376,14 @@ void AccessorAssemblerImpl::HandleLoadICProtoHandlerCase(
Bind(&array_handler);
{
- typedef LoadICProtoArrayDescriptor Descriptor;
- LoadICProtoArrayStub stub(isolate(), throw_reference_error_if_nonexistent);
- Node* target = HeapConstant(stub.GetCode());
- TailCallStub(Descriptor(isolate()), target, p->context, p->receiver,
- p->name, p->slot, p->vector, handler);
+ exit_point->ReturnCallStub(
+ CodeFactory::LoadICProtoArray(isolate(),
+ throw_reference_error_if_nonexistent),
+ p->context, p->receiver, p->name, p->slot, p->vector, handler);
}
}
-Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
+Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
const LoadICParameters* p, Node* handler, Node* handler_length,
Node* handler_flags, Label* miss,
bool throw_reference_error_if_nonexistent) {
@@ -384,8 +391,8 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
Label can_access(this);
- GotoUnless(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
- &can_access);
+ GotoIfNot(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags),
+ &can_access);
{
// Skip this entry of a handler.
start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1));
@@ -399,7 +406,7 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
Node* native_context = LoadNativeContext(p->context);
GotoIf(WordEqual(expected_native_context, native_context), &can_access);
// If the receiver is not a JSGlobalProxy then we miss.
- GotoUnless(IsJSGlobalProxy(p->receiver), miss);
+ GotoIfNot(IsJSGlobalProxy(p->receiver), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
Node* expected_token = LoadContextElement(expected_native_context,
@@ -410,13 +417,13 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
}
Bind(&can_access);
- BuildFastLoop(
- MachineType::PointerRepresentation(), start_index.value(), handler_length,
- [this, p, handler, miss](Node* current) {
- Node* prototype_cell = LoadFixedArrayElement(handler, current);
- CheckPrototype(prototype_cell, p->name, miss);
- },
- 1, IndexAdvanceMode::kPost);
+ BuildFastLoop(start_index.value(), handler_length,
+ [this, p, handler, miss](Node* current) {
+ Node* prototype_cell =
+ LoadFixedArrayElement(handler, current);
+ CheckPrototype(prototype_cell, p->name, miss);
+ },
+ 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
Node* maybe_holder_cell =
LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
@@ -438,9 +445,9 @@ Node* AccessorAssemblerImpl::EmitLoadICProtoArrayCheck(
return holder;
}
-void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase(
+void AccessorAssembler::HandleLoadGlobalICHandlerCase(
const LoadICParameters* pp, Node* handler, Label* miss,
- bool throw_reference_error_if_nonexistent) {
+ ExitPoint* exit_point, bool throw_reference_error_if_nonexistent) {
LoadICParameters p = *pp;
DCHECK_NULL(p.receiver);
Node* native_context = LoadNativeContext(p.context);
@@ -450,14 +457,14 @@ void AccessorAssemblerImpl::HandleLoadGlobalICHandlerCase(
Variable var_smi_handler(this, MachineRepresentation::kTagged);
Label if_smi_handler(this);
HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss,
+ &if_smi_handler, miss, exit_point,
throw_reference_error_if_nonexistent);
Bind(&if_smi_handler);
HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
- miss, kOnlyProperties);
+ miss, exit_point, kOnlyProperties);
}
-void AccessorAssemblerImpl::HandleStoreICHandlerCase(
+void AccessorAssembler::HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
Label if_smi_handler(this), if_nonsmi_handler(this);
@@ -504,7 +511,7 @@ void AccessorAssemblerImpl::HandleStoreICHandlerCase(
}
}
-void AccessorAssemblerImpl::HandleStoreICElementHandlerCase(
+void AccessorAssembler::HandleStoreICElementHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss) {
Comment("HandleStoreICElementHandlerCase");
Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
@@ -521,8 +528,8 @@ void AccessorAssemblerImpl::HandleStoreICElementHandlerCase(
p->value, p->slot, p->vector);
}
-void AccessorAssemblerImpl::HandleStoreICProtoHandler(
- const StoreICParameters* p, Node* handler, Label* miss) {
+void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
+ Node* handler, Label* miss) {
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset ==
StoreHandler::kTransitionCellOffset);
@@ -564,14 +571,13 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler(
Bind(&array_handler);
{
Node* length = SmiUntag(maybe_transition_cell);
- BuildFastLoop(MachineType::PointerRepresentation(),
- IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
+ BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
[this, p, handler, miss](Node* current) {
Node* prototype_cell =
LoadFixedArrayElement(handler, current);
CheckPrototype(prototype_cell, p->name, miss);
},
- 1, IndexAdvanceMode::kPost);
+ 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
Node* maybe_transition_cell =
LoadFixedArrayElement(handler, StoreHandler::kTransitionCellIndex);
@@ -613,11 +619,10 @@ void AccessorAssemblerImpl::HandleStoreICProtoHandler(
}
}
-void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
- Node* holder,
- Node* value,
- Node* transition,
- Label* miss) {
+void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
+ Node* holder, Node* value,
+ Node* transition,
+ Label* miss) {
Comment(transition ? "transitioning field store" : "field store");
#ifdef DEBUG
@@ -631,8 +636,17 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant))));
} else {
- CSA_ASSERT(this, WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kStoreField)));
+ if (FLAG_track_constant_fields) {
+ CSA_ASSERT(
+ this,
+ Word32Or(WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreField)),
+ WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreConstField))));
+ } else {
+ CSA_ASSERT(this, WordEqual(handler_kind,
+ IntPtrConstant(StoreHandler::kStoreField)));
+ }
}
#endif
@@ -683,9 +697,11 @@ void AccessorAssemblerImpl::HandleStoreICSmiHandlerCase(Node* handler_word,
}
}
-void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
- Node* handler_word, Node* holder, Representation representation,
- Node* value, Node* transition, Label* miss) {
+void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
+ Node* holder,
+ Representation representation,
+ Node* value, Node* transition,
+ Label* miss) {
bool transition_to_field = transition != nullptr;
Node* prepared_value = PrepareValueForStore(
handler_word, holder, representation, transition, value, miss);
@@ -697,7 +713,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
Bind(&if_inobject);
{
StoreNamedField(handler_word, holder, true, representation, prepared_value,
- transition_to_field);
+ transition_to_field, miss);
if (transition_to_field) {
StoreMap(holder, transition);
}
@@ -708,8 +724,8 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
{
if (transition_to_field) {
Label storage_extended(this);
- GotoUnless(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
- &storage_extended);
+ GotoIfNot(IsSetWord<StoreHandler::ExtendStorageBits>(handler_word),
+ &storage_extended);
Comment("[ Extend storage");
ExtendPropertiesBackingStore(holder);
Comment("] Extend storage");
@@ -719,7 +735,7 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
}
StoreNamedField(handler_word, holder, false, representation, prepared_value,
- transition_to_field);
+ transition_to_field, miss);
if (transition_to_field) {
StoreMap(holder, transition);
}
@@ -727,16 +743,24 @@ void AccessorAssemblerImpl::HandleStoreFieldAndReturn(
}
}
-Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
- Node* holder,
- Representation representation,
- Node* transition, Node* value,
- Label* bailout) {
+Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
+ Representation representation,
+ Node* transition, Node* value,
+ Label* bailout) {
if (representation.IsDouble()) {
value = TryTaggedToFloat64(value, bailout);
} else if (representation.IsHeapObject()) {
GotoIf(TaggedIsSmi(value), bailout);
+
+ Label done(this);
+ if (FLAG_track_constant_fields && !transition) {
+ // Skip field type check in favor of constant value check when storing
+ // to constant field.
+ GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
+ IntPtrConstant(StoreHandler::kStoreConstField)),
+ &done);
+ }
Node* value_index_in_descriptor =
DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
Node* descriptors =
@@ -744,7 +768,6 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
Node* maybe_field_type =
LoadFixedArrayElement(descriptors, value_index_in_descriptor);
- Label done(this);
GotoIf(TaggedIsSmi(maybe_field_type), &done);
// Check that value type matches the field type.
{
@@ -754,7 +777,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
Bind(&done);
} else if (representation.IsSmi()) {
- GotoUnless(TaggedIsSmi(value), bailout);
+ GotoIfNot(TaggedIsSmi(value), bailout);
} else {
DCHECK(representation.IsTagged());
@@ -762,7 +785,7 @@ Node* AccessorAssemblerImpl::PrepareValueForStore(Node* handler_word,
return value;
}
-void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) {
+void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) {
Node* properties = LoadProperties(object);
Node* length = LoadFixedArrayBaseLength(properties);
@@ -798,11 +821,11 @@ void AccessorAssemblerImpl::ExtendPropertiesBackingStore(Node* object) {
StoreObjectField(object, JSObject::kPropertiesOffset, new_properties);
}
-void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
- bool is_inobject,
- Representation representation,
- Node* value,
- bool transition_to_field) {
+void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
+ bool is_inobject,
+ Representation representation,
+ Node* value, bool transition_to_field,
+ Label* bailout) {
bool store_value_as_double = representation.IsDouble();
Node* property_storage = object;
if (!is_inobject) {
@@ -826,6 +849,27 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
}
}
+ // Do constant value check if necessary.
+ if (FLAG_track_constant_fields && !transition_to_field) {
+ Label done(this);
+ GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
+ IntPtrConstant(StoreHandler::kStoreConstField)),
+ &done);
+ {
+ if (store_value_as_double) {
+ Node* current_value =
+ LoadObjectField(property_storage, offset, MachineType::Float64());
+ GotoIfNot(Float64Equal(current_value, value), bailout);
+ } else {
+ Node* current_value = LoadObjectField(property_storage, offset);
+ GotoIfNot(WordEqual(current_value, value), bailout);
+ }
+ Goto(&done);
+ }
+ Bind(&done);
+ }
+
+ // Do the store.
if (store_value_as_double) {
StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
MachineRepresentation::kFloat64);
@@ -836,9 +880,11 @@ void AccessorAssemblerImpl::StoreNamedField(Node* handler_word, Node* object,
}
}
-void AccessorAssemblerImpl::EmitFastElementsBoundsCheck(
- Node* object, Node* elements, Node* intptr_index,
- Node* is_jsarray_condition, Label* miss) {
+void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
+ Node* elements,
+ Node* intptr_index,
+ Node* is_jsarray_condition,
+ Label* miss) {
Variable var_length(this, MachineType::PointerRepresentation());
Comment("Fast elements bounds check");
Label if_array(this), length_loaded(this, &var_length);
@@ -853,14 +899,14 @@ void AccessorAssemblerImpl::EmitFastElementsBoundsCheck(
Goto(&length_loaded);
}
Bind(&length_loaded);
- GotoUnless(UintPtrLessThan(intptr_index, var_length.value()), miss);
+ GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
}
-void AccessorAssemblerImpl::EmitElementLoad(
+void AccessorAssembler::EmitElementLoad(
Node* object, Node* elements, Node* elements_kind, Node* intptr_index,
Node* is_jsarray_condition, Label* if_hole, Label* rebox_double,
Variable* var_double_value, Label* unimplemented_elements_kind,
- Label* out_of_bounds, Label* miss) {
+ Label* out_of_bounds, Label* miss, ExitPoint* exit_point) {
Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
if_dictionary(this);
@@ -892,7 +938,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
Bind(&if_fast_packed);
{
Comment("fast packed elements");
- Return(LoadFixedArrayElement(elements, intptr_index));
+ exit_point->Return(LoadFixedArrayElement(elements, intptr_index));
}
Bind(&if_fast_holey);
@@ -900,7 +946,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
Comment("fast holey elements");
Node* element = LoadFixedArrayElement(elements, intptr_index);
GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
- Return(element);
+ exit_point->Return(element);
}
Bind(&if_fast_double);
@@ -943,16 +989,15 @@ void AccessorAssemblerImpl::EmitElementLoad(
elements, intptr_index, &if_found, &var_entry, if_hole);
Bind(&if_found);
// Check that the value is a data property.
- Node* details_index = EntryToIndex<SeededNumberDictionary>(
- var_entry.value(), SeededNumberDictionary::kEntryDetailsIndex);
- Node* details = SmiToWord32(LoadFixedArrayElement(elements, details_index));
+ Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value());
+ Node* details =
+ LoadDetailsByKeyIndex<SeededNumberDictionary>(elements, index);
Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
// TODO(jkummerow): Support accessors without missing?
- GotoUnless(Word32Equal(kind, Int32Constant(kData)), miss);
+ GotoIfNot(Word32Equal(kind, Int32Constant(kData)), miss);
// Finally, load the value.
- Node* value_index = EntryToIndex<SeededNumberDictionary>(
- var_entry.value(), SeededNumberDictionary::kEntryValueIndex);
- Return(LoadFixedArrayElement(elements, value_index));
+ exit_point->Return(
+ LoadValueByKeyIndex<SeededNumberDictionary>(elements, index));
}
Bind(&if_typed_array);
@@ -965,7 +1010,7 @@ void AccessorAssemblerImpl::EmitElementLoad(
// Bounds check.
Node* length =
SmiUntag(LoadObjectField(object, JSTypedArray::kLengthOffset));
- GotoUnless(UintPtrLessThan(intptr_index, length), out_of_bounds);
+ GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
// Backing store = external_pointer + base_pointer.
Node* external_pointer =
@@ -998,41 +1043,41 @@ void AccessorAssemblerImpl::EmitElementLoad(
{
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&int8_elements);
{
Comment("INT8_ELEMENTS");
Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&uint16_elements);
{
Comment("UINT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Uint16(), backing_store, index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&int16_elements);
{
Comment("INT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Int16(), backing_store, index);
- Return(SmiFromWord32(element));
+ exit_point->Return(SmiFromWord32(element));
}
Bind(&uint32_elements);
{
Comment("UINT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Uint32(), backing_store, index);
- Return(ChangeUint32ToTagged(element));
+ exit_point->Return(ChangeUint32ToTagged(element));
}
Bind(&int32_elements);
{
Comment("INT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Int32(), backing_store, index);
- Return(ChangeInt32ToTagged(element));
+ exit_point->Return(ChangeInt32ToTagged(element));
}
Bind(&float32_elements);
{
@@ -1053,8 +1098,8 @@ void AccessorAssemblerImpl::EmitElementLoad(
}
}
-void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name,
- Label* miss) {
+void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name,
+ Label* miss) {
Node* maybe_prototype = LoadWeakCellValue(prototype_cell, miss);
Label done(this);
@@ -1083,9 +1128,8 @@ void AccessorAssemblerImpl::CheckPrototype(Node* prototype_cell, Node* name,
Bind(&done);
}
-void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object,
- Node* name,
- Label* miss) {
+void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
+ Label* miss) {
CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
Node* properties = LoadProperties(object);
// Ensure the property does not exist in a dictionary-mode object.
@@ -1096,14 +1140,199 @@ void AccessorAssemblerImpl::NameDictionaryNegativeLookup(Node* object,
Bind(&done);
}
+void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* index,
+ Label* slow) {
+ Comment("integer index");
+
+ ExitPoint direct_exit(this);
+
+ Label if_element_hole(this), if_oob(this);
+ // Receivers requiring non-standard element accesses (interceptors, access
+ // checks, strings and string wrappers, proxies) are handled in the runtime.
+ GotoIf(Int32LessThanOrEqual(instance_type,
+ Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
+ slow);
+ Node* elements = LoadElements(receiver);
+ Node* elements_kind = LoadMapElementsKind(receiver_map);
+ Node* is_jsarray_condition =
+ Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
+ Variable var_double_value(this, MachineRepresentation::kFloat64);
+ Label rebox_double(this, &var_double_value);
+
+ // Unimplemented elements kinds fall back to a runtime call.
+ Label* unimplemented_elements_kind = slow;
+ IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
+ EmitElementLoad(receiver, elements, elements_kind, index,
+ is_jsarray_condition, &if_element_hole, &rebox_double,
+ &var_double_value, unimplemented_elements_kind, &if_oob, slow,
+ &direct_exit);
+
+ Bind(&rebox_double);
+ Return(AllocateHeapNumberWithValue(var_double_value.value()));
+
+ Bind(&if_oob);
+ {
+ Comment("out of bounds");
+ // Negative keys can't take the fast OOB path.
+ GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), slow);
+ // Positive OOB indices are effectively the same as hole loads.
+ Goto(&if_element_hole);
+ }
+
+ Bind(&if_element_hole);
+ {
+ Comment("found the hole");
+ Label return_undefined(this);
+ BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
+
+ Bind(&return_undefined);
+ Return(UndefinedConstant());
+ }
+}
+
+void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
+ Node* instance_type, Node* key,
+ const LoadICParameters* p,
+ Label* slow) {
+ Comment("key is unique name");
+ Label if_found_on_receiver(this), if_property_dictionary(this),
+ lookup_prototype_chain(this);
+ Variable var_details(this, MachineRepresentation::kWord32);
+ Variable var_value(this, MachineRepresentation::kTagged);
+
+ // Receivers requiring non-standard accesses (interceptors, access
+ // checks, strings and string wrappers, proxies) are handled in the runtime.
+ GotoIf(Int32LessThanOrEqual(instance_type,
+ Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
+ slow);
+
+ // Check if the receiver has fast or slow properties.
+ Node* properties = LoadProperties(receiver);
+ Node* properties_map = LoadMap(properties);
+ GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
+ &if_property_dictionary);
+
+ // Try looking up the property on the receiver; if unsuccessful, look
+ // for a handler in the stub cache.
+ Node* bitfield3 = LoadMapBitField3(receiver_map);
+ Node* descriptors = LoadMapDescriptors(receiver_map);
+
+ Label if_descriptor_found(this), stub_cache(this);
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found,
+ &var_name_index, &stub_cache);
+
+ Bind(&if_descriptor_found);
+ {
+ LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
+ var_name_index.value(), &var_details,
+ &var_value);
+ Goto(&if_found_on_receiver);
+ }
+
+ Bind(&stub_cache);
+ {
+ Comment("stub cache probe for fast property load");
+ Variable var_handler(this, MachineRepresentation::kTagged);
+ Label found_handler(this, &var_handler), stub_cache_miss(this);
+ TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
+ &found_handler, &var_handler, &stub_cache_miss);
+ Bind(&found_handler);
+ { HandleLoadICHandlerCase(p, var_handler.value(), slow); }
+
+ Bind(&stub_cache_miss);
+ {
+ // TODO(jkummerow): Check if the property exists on the prototype
+ // chain. If it doesn't, then there's no point in missing.
+ Comment("KeyedLoadGeneric_miss");
+ TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
+ p->name, p->slot, p->vector);
+ }
+ }
+
+ Bind(&if_property_dictionary);
+ {
+ Comment("dictionary property load");
+ // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
+ // seeing global objects here (which would need special handling).
+
+ Variable var_name_index(this, MachineType::PointerRepresentation());
+ Label dictionary_found(this, &var_name_index);
+ NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
+ &var_name_index,
+ &lookup_prototype_chain);
+ Bind(&dictionary_found);
+ {
+ LoadPropertyFromNameDictionary(properties, var_name_index.value(),
+ &var_details, &var_value);
+ Goto(&if_found_on_receiver);
+ }
+ }
+
+ Bind(&if_found_on_receiver);
+ {
+ Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context, receiver, slow);
+ IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
+ Return(value);
+ }
+
+ Bind(&lookup_prototype_chain);
+ {
+ Variable var_holder_map(this, MachineRepresentation::kTagged);
+ Variable var_holder_instance_type(this, MachineRepresentation::kWord32);
+ Label return_undefined(this);
+ Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
+ Label loop(this, arraysize(merged_variables), merged_variables);
+
+ var_holder_map.Bind(receiver_map);
+ var_holder_instance_type.Bind(instance_type);
+ // Private symbols must not be looked up on the prototype chain.
+ GotoIf(IsPrivateSymbol(key), &return_undefined);
+ Goto(&loop);
+ Bind(&loop);
+ {
+ // Bailout if it can be an integer indexed exotic case.
+ GotoIf(Word32Equal(var_holder_instance_type.value(),
+ Int32Constant(JS_TYPED_ARRAY_TYPE)),
+ slow);
+ Node* proto = LoadMapPrototype(var_holder_map.value());
+ GotoIf(WordEqual(proto, NullConstant()), &return_undefined);
+ Node* proto_map = LoadMap(proto);
+ Node* proto_instance_type = LoadMapInstanceType(proto_map);
+ var_holder_map.Bind(proto_map);
+ var_holder_instance_type.Bind(proto_instance_type);
+ Label next_proto(this), return_value(this, &var_value), goto_slow(this);
+ TryGetOwnProperty(p->context, receiver, proto, proto_map,
+ proto_instance_type, key, &return_value, &var_value,
+ &next_proto, &goto_slow);
+
+ // This trampoline and the next are required to appease Turbofan's
+ // variable merging.
+ Bind(&next_proto);
+ Goto(&loop);
+
+ Bind(&goto_slow);
+ Goto(slow);
+
+ Bind(&return_value);
+ Return(var_value.value());
+ }
+
+ Bind(&return_undefined);
+ Return(UndefinedConstant());
+ }
+}
+
//////////////////// Stub cache access helpers.
-enum AccessorAssemblerImpl::StubCacheTable : int {
+enum AccessorAssembler::StubCacheTable : int {
kPrimary = static_cast<int>(StubCache::kPrimary),
kSecondary = static_cast<int>(StubCache::kSecondary)
};
-Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) {
+Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
// See v8::internal::StubCache::PrimaryOffset().
STATIC_ASSERT(StubCache::kCacheIndexShift == Name::kHashShift);
// Compute the hash of the name (use entire hash field).
@@ -1125,7 +1354,7 @@ Node* AccessorAssemblerImpl::StubCachePrimaryOffset(Node* name, Node* map) {
return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
}
-Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) {
+Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
// See v8::internal::StubCache::SecondaryOffset().
// Use the seed from the primary cache in the secondary cache.
@@ -1137,10 +1366,12 @@ Node* AccessorAssemblerImpl::StubCacheSecondaryOffset(Node* name, Node* seed) {
return ChangeUint32ToWord(Word32And(hash, Int32Constant(mask)));
}
-void AccessorAssemblerImpl::TryProbeStubCacheTable(
- StubCache* stub_cache, StubCacheTable table_id, Node* entry_offset,
- Node* name, Node* map, Label* if_handler, Variable* var_handler,
- Label* if_miss) {
+void AccessorAssembler::TryProbeStubCacheTable(StubCache* stub_cache,
+ StubCacheTable table_id,
+ Node* entry_offset, Node* name,
+ Node* map, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
StubCache::Table table = static_cast<StubCache::Table>(table_id);
#ifdef DEBUG
if (FLAG_test_secondary_stub_cache && table == StubCache::kPrimary) {
@@ -1180,11 +1411,10 @@ void AccessorAssemblerImpl::TryProbeStubCacheTable(
Goto(if_handler);
}
-void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache,
- Node* receiver, Node* name,
- Label* if_handler,
- Variable* var_handler,
- Label* if_miss) {
+void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
+ Node* name, Label* if_handler,
+ Variable* var_handler,
+ Label* if_miss) {
Label try_secondary(this), miss(this);
Counters* counters = isolate()->counters();
@@ -1217,7 +1447,7 @@ void AccessorAssemblerImpl::TryProbeStubCache(StubCache* stub_cache,
//////////////////// Entry points into private implementation (one per stub).
-void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
+void AccessorAssembler::LoadIC(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),
@@ -1238,8 +1468,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
{
// Check polymorphic case.
Comment("LoadIC_try_polymorphic");
- GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
- &try_megamorphic);
+ GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@@ -1247,9 +1477,8 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
Bind(&try_megamorphic);
{
// Check megamorphic case.
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
@@ -1261,13 +1490,15 @@ void AccessorAssemblerImpl::LoadIC(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::LoadICProtoArray(
+void AccessorAssembler::LoadICProtoArray(
const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent) {
Label miss(this);
CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
CSA_ASSERT(this, IsFixedArrayMap(LoadMap(handler)));
+ ExitPoint direct_exit(this);
+
Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
Node* handler_flags = SmiUntag(smi_handler);
@@ -1277,7 +1508,8 @@ void AccessorAssemblerImpl::LoadICProtoArray(
EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
&miss, throw_reference_error_if_nonexistent);
- HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, kOnlyProperties);
+ HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
+ kOnlyProperties);
Bind(&miss);
{
@@ -1286,36 +1518,41 @@ void AccessorAssemblerImpl::LoadICProtoArray(
}
}
-void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p,
- TypeofMode typeof_mode) {
- Label try_handler(this), call_handler(this), miss(this);
- Node* weak_cell =
- LoadFixedArrayElement(p->vector, p->slot, 0, SMI_PARAMETERS);
+void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
+ Node* vector, Node* slot, ExitPoint* exit_point, Label* try_handler,
+ Label* miss, ParameterMode slot_mode) {
+ Comment("LoadGlobalIC_TryPropertyCellCase");
+
+ Node* weak_cell = LoadFixedArrayElement(vector, slot, 0, slot_mode);
CSA_ASSERT(this, HasInstanceType(weak_cell, WEAK_CELL_TYPE));
// Load value or try handler case if the {weak_cell} is cleared.
- Node* property_cell = LoadWeakCellValue(weak_cell, &try_handler);
+ Node* property_cell = LoadWeakCellValue(weak_cell, try_handler);
CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
- GotoIf(WordEqual(value, TheHoleConstant()), &miss);
- Return(value);
+ GotoIf(WordEqual(value, TheHoleConstant()), miss);
+ exit_point->Return(value);
+}
- Node* handler;
- Bind(&try_handler);
- {
- handler =
- LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
- CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
- GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
- &miss);
- GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
+ TypeofMode typeof_mode,
+ ExitPoint* exit_point,
+ Label* miss) {
+ Comment("LoadGlobalIC_TryHandlerCase");
- bool throw_reference_error_if_nonexistent =
- typeof_mode == NOT_INSIDE_TYPEOF;
- HandleLoadGlobalICHandlerCase(p, handler, &miss,
- throw_reference_error_if_nonexistent);
- }
+ Label call_handler(this);
+
+ Node* handler =
+ LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
+ CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
+ GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
+ miss);
+ GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+
+ bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF;
+ HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point,
+ throw_reference_error_if_nonexistent);
Bind(&call_handler);
{
@@ -1323,17 +1560,35 @@ void AccessorAssemblerImpl::LoadGlobalIC(const LoadICParameters* p,
Node* native_context = LoadNativeContext(p->context);
Node* receiver =
LoadContextElement(native_context, Context::EXTENSION_INDEX);
- TailCallStub(descriptor, handler, p->context, receiver, p->name, p->slot,
- p->vector);
+ exit_point->ReturnCallStub(descriptor, handler, p->context, receiver,
+ p->name, p->slot, p->vector);
}
+}
+
+void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p,
+ ExitPoint* exit_point) {
+ Comment("LoadGlobalIC_MissCase");
+
+ exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context,
+ p->name, p->slot, p->vector);
+}
+
+void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p,
+ TypeofMode typeof_mode) {
+ ExitPoint direct_exit(this);
+
+ Label try_handler(this), miss(this);
+ LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit,
+ &try_handler, &miss);
+
+ Bind(&try_handler);
+ LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss);
+
Bind(&miss);
- {
- TailCallRuntime(Runtime::kLoadGlobalIC_Miss, p->context, p->name, p->slot,
- p->vector);
- }
+ LoadGlobalIC_MissCase(p, &direct_exit);
}
-void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
+void AccessorAssembler::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),
@@ -1355,8 +1610,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// Check polymorphic case.
Comment("KeyedLoadIC_try_polymorphic");
- GotoUnless(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
- &try_megamorphic);
+ GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
@@ -1365,9 +1620,8 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &try_polymorphic_name);
+ GotoIfNot(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);
@@ -1376,7 +1630,7 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
{
// 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);
+ GotoIfNot(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(
@@ -1394,150 +1648,30 @@ void AccessorAssemblerImpl::KeyedLoadIC(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) {
+void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
Variable var_index(this, MachineType::PointerRepresentation());
- Variable var_details(this, MachineRepresentation::kWord32);
- Variable var_value(this, MachineRepresentation::kTagged);
- Label if_index(this), if_unique_name(this), if_element_hole(this),
- if_oob(this), slow(this), stub_cache_miss(this),
- if_property_dictionary(this), if_found_on_receiver(this);
+ Variable var_unique(this, MachineRepresentation::kTagged);
+ var_unique.Bind(p->name); // Dummy initialization.
+ Label if_index(this), if_unique_name(this), slow(this);
Node* receiver = p->receiver;
GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
- // Receivers requiring non-standard element accesses (interceptors, access
- // checks, strings and string wrappers, proxies) are handled in the runtime.
- GotoIf(Int32LessThanOrEqual(instance_type,
- Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
- &slow);
- Node* key = p->name;
- TryToName(key, &if_index, &var_index, &if_unique_name, &slow);
+ TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
+ &slow);
Bind(&if_index);
{
- Comment("integer index");
- Node* index = var_index.value();
- Node* elements = LoadElements(receiver);
- Node* elements_kind = LoadMapElementsKind(receiver_map);
- Node* is_jsarray_condition =
- Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
- Variable var_double_value(this, MachineRepresentation::kFloat64);
- Label rebox_double(this, &var_double_value);
-
- // Unimplemented elements kinds fall back to a runtime call.
- Label* unimplemented_elements_kind = &slow;
- IncrementCounter(isolate()->counters()->ic_keyed_load_generic_smi(), 1);
- EmitElementLoad(receiver, elements, elements_kind, index,
- is_jsarray_condition, &if_element_hole, &rebox_double,
- &var_double_value, unimplemented_elements_kind, &if_oob,
- &slow);
-
- Bind(&rebox_double);
- Return(AllocateHeapNumberWithValue(var_double_value.value()));
- }
-
- Bind(&if_oob);
- {
- Comment("out of bounds");
- Node* index = var_index.value();
- // Negative keys can't take the fast OOB path.
- GotoIf(IntPtrLessThan(index, IntPtrConstant(0)), &slow);
- // Positive OOB indices are effectively the same as hole loads.
- Goto(&if_element_hole);
- }
-
- Bind(&if_element_hole);
- {
- Comment("found the hole");
- Label return_undefined(this);
- BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, &slow);
-
- Bind(&return_undefined);
- Return(UndefinedConstant());
+ GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
+ &slow);
}
- Node* properties = nullptr;
Bind(&if_unique_name);
{
- Comment("key is unique name");
- // Check if the receiver has fast or slow properties.
- properties = LoadProperties(receiver);
- Node* properties_map = LoadMap(properties);
- GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
- &if_property_dictionary);
-
- // Try looking up the property on the receiver; if unsuccessful, look
- // for a handler in the stub cache.
- Comment("DescriptorArray lookup");
-
- // Skip linear search if there are too many descriptors.
- // TODO(jkummerow): Consider implementing binary search.
- // See also TryLookupProperty() which has the same limitation.
- const int32_t kMaxLinear = 210;
- Label stub_cache(this);
- Node* bitfield3 = LoadMapBitField3(receiver_map);
- Node* nof =
- DecodeWordFromWord32<Map::NumberOfOwnDescriptorsBits>(bitfield3);
- GotoIf(UintPtrLessThan(IntPtrConstant(kMaxLinear), nof), &stub_cache);
- Node* descriptors = LoadMapDescriptors(receiver_map);
- Variable var_name_index(this, MachineType::PointerRepresentation());
- Label if_descriptor_found(this);
- DescriptorLookupLinear(key, descriptors, nof, &if_descriptor_found,
- &var_name_index, &stub_cache);
-
- Bind(&if_descriptor_found);
- {
- LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
- var_name_index.value(), &var_details,
- &var_value);
- Goto(&if_found_on_receiver);
- }
-
- Bind(&stub_cache);
- {
- Comment("stub cache probe for fast property load");
- Variable var_handler(this, MachineRepresentation::kTagged);
- Label found_handler(this, &var_handler), stub_cache_miss(this);
- TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
- &found_handler, &var_handler, &stub_cache_miss);
- Bind(&found_handler);
- { HandleLoadICHandlerCase(p, var_handler.value(), &slow); }
-
- Bind(&stub_cache_miss);
- {
- Comment("KeyedLoadGeneric_miss");
- TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
- p->name, p->slot, p->vector);
- }
- }
- }
-
- Bind(&if_property_dictionary);
- {
- Comment("dictionary property load");
- // We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
- // seeing global objects here (which would need special handling).
-
- Variable var_name_index(this, MachineType::PointerRepresentation());
- Label dictionary_found(this, &var_name_index);
- NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
- &var_name_index, &slow);
- Bind(&dictionary_found);
- {
- LoadPropertyFromNameDictionary(properties, var_name_index.value(),
- &var_details, &var_value);
- Goto(&if_found_on_receiver);
- }
- }
-
- Bind(&if_found_on_receiver);
- {
- Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
- p->context, receiver, &slow);
- IncrementCounter(isolate()->counters()->ic_keyed_load_generic_symbol(), 1);
- Return(value);
+ GenericPropertyLoad(receiver, receiver_map, instance_type,
+ var_unique.value(), p, &slow);
}
Bind(&slow);
@@ -1550,7 +1684,7 @@ void AccessorAssemblerImpl::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
-void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
+void AccessorAssembler::StoreIC(const StoreICParameters* p) {
Variable var_handler(this, MachineRepresentation::kTagged);
// TODO(ishell): defer blocks when it works.
Label if_handler(this, &var_handler), try_polymorphic(this),
@@ -1574,7 +1708,7 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
{
// Check polymorphic case.
Comment("StoreIC_try_polymorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
@@ -1584,9 +1718,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
Bind(&try_megamorphic);
{
// Check megamorphic case.
- GotoUnless(
- WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
+ &miss);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
@@ -1598,8 +1731,8 @@ void AccessorAssemblerImpl::StoreIC(const StoreICParameters* p) {
}
}
-void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
- LanguageMode language_mode) {
+void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
+ LanguageMode language_mode) {
// TODO(ishell): defer blocks when it works.
Label miss(this /*, Label::kDeferred*/);
{
@@ -1627,7 +1760,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// CheckPolymorphic case.
Comment("KeyedStoreIC_try_polymorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
Label if_transition_handler(this);
@@ -1643,7 +1776,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
Label call_handler(this);
Variable var_code_handler(this, MachineRepresentation::kTagged);
var_code_handler.Bind(handler);
- GotoUnless(IsTuple2Map(LoadMap(handler)), &call_handler);
+ GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler);
{
CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
@@ -1677,7 +1810,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// Check megamorphic case.
Comment("KeyedStoreIC_try_megamorphic");
- GotoUnless(
+ GotoIfNot(
WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
&try_polymorphic_name);
TailCallStub(
@@ -1689,7 +1822,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedStoreIC_try_polymorphic_name");
- GotoUnless(WordEqual(feedback, p->name), &miss);
+ GotoIfNot(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a FixedArray with
// at least one map/handler pair.
Node* offset = ElementOffsetFromIndex(
@@ -1710,7 +1843,7 @@ void AccessorAssemblerImpl::KeyedStoreIC(const StoreICParameters* p,
//////////////////// Public methods.
-void AccessorAssemblerImpl::GenerateLoadIC() {
+void AccessorAssembler::GenerateLoadIC() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1723,7 +1856,7 @@ void AccessorAssemblerImpl::GenerateLoadIC() {
LoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateLoadICTrampoline() {
+void AccessorAssembler::GenerateLoadICTrampoline() {
typedef LoadDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1736,9 +1869,9 @@ void AccessorAssemblerImpl::GenerateLoadICTrampoline() {
LoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateLoadICProtoArray(
+void AccessorAssembler::GenerateLoadICProtoArray(
bool throw_reference_error_if_nonexistent) {
- typedef LoadICProtoArrayStub::Descriptor Descriptor;
+ typedef LoadICProtoArrayDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
@@ -1751,8 +1884,8 @@ void AccessorAssemblerImpl::GenerateLoadICProtoArray(
LoadICProtoArray(&p, handler, throw_reference_error_if_nonexistent);
}
-void AccessorAssemblerImpl::GenerateLoadField() {
- typedef LoadFieldStub::Descriptor Descriptor;
+void AccessorAssembler::GenerateLoadField() {
+ typedef LoadFieldDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = nullptr;
@@ -1761,11 +1894,13 @@ void AccessorAssemblerImpl::GenerateLoadField() {
Node* context = Parameter(Descriptor::kContext);
LoadICParameters p(context, receiver, name, slot, vector);
+ ExitPoint direct_exit(this);
+
HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
- nullptr, kOnlyProperties);
+ nullptr, &direct_exit, kOnlyProperties);
}
-void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
+void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
typedef LoadGlobalWithVectorDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
@@ -1777,8 +1912,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
LoadGlobalIC(&p, typeof_mode);
}
-void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline(
- TypeofMode typeof_mode) {
+void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
typedef LoadGlobalDescriptor Descriptor;
Node* name = Parameter(Descriptor::kName);
@@ -1790,7 +1924,7 @@ void AccessorAssemblerImpl::GenerateLoadGlobalICTrampoline(
LoadGlobalIC(&p, typeof_mode);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICTF() {
+void AccessorAssembler::GenerateKeyedLoadIC() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1803,7 +1937,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTF() {
KeyedLoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() {
+void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
typedef LoadDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1816,7 +1950,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICTrampolineTF() {
KeyedLoadIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() {
+void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
typedef LoadWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1829,7 +1963,7 @@ void AccessorAssemblerImpl::GenerateKeyedLoadICMegamorphic() {
KeyedLoadICGeneric(&p);
}
-void AccessorAssemblerImpl::GenerateStoreIC() {
+void AccessorAssembler::GenerateStoreIC() {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1843,7 +1977,7 @@ void AccessorAssemblerImpl::GenerateStoreIC() {
StoreIC(&p);
}
-void AccessorAssemblerImpl::GenerateStoreICTrampoline() {
+void AccessorAssembler::GenerateStoreICTrampoline() {
typedef StoreDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1857,7 +1991,7 @@ void AccessorAssemblerImpl::GenerateStoreICTrampoline() {
StoreIC(&p);
}
-void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) {
+void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1871,7 +2005,7 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTF(LanguageMode language_mode) {
KeyedStoreIC(&p, language_mode);
}
-void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF(
+void AccessorAssembler::GenerateKeyedStoreICTrampoline(
LanguageMode language_mode) {
typedef StoreDescriptor Descriptor;
@@ -1886,48 +2020,5 @@ void AccessorAssemblerImpl::GenerateKeyedStoreICTrampolineTF(
KeyedStoreIC(&p, language_mode);
}
-//////////////////// AccessorAssembler implementation.
-
-#define DISPATCH_TO_IMPL(Name) \
- void AccessorAssembler::Generate##Name(CodeAssemblerState* state) { \
- AccessorAssemblerImpl assembler(state); \
- assembler.Generate##Name(); \
- }
-
-ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DISPATCH_TO_IMPL)
-#undef DISPATCH_TO_IMPL
-
-void AccessorAssembler::GenerateLoadICProtoArray(
- CodeAssemblerState* state, bool throw_reference_error_if_nonexistent) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadICProtoArray(throw_reference_error_if_nonexistent);
-}
-
-void AccessorAssembler::GenerateLoadGlobalIC(CodeAssemblerState* state,
- TypeofMode typeof_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadGlobalIC(typeof_mode);
-}
-
-void AccessorAssembler::GenerateLoadGlobalICTrampoline(
- CodeAssemblerState* state, TypeofMode typeof_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateLoadGlobalICTrampoline(typeof_mode);
-}
-
-void AccessorAssembler::GenerateKeyedStoreICTF(CodeAssemblerState* state,
- LanguageMode language_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateKeyedStoreICTF(language_mode);
-}
-
-void AccessorAssembler::GenerateKeyedStoreICTrampolineTF(
- CodeAssemblerState* state, LanguageMode language_mode) {
- AccessorAssemblerImpl assembler(state);
- assembler.GenerateKeyedStoreICTrampolineTF(language_mode);
-}
-
-#undef ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE
-
} // namespace internal
} // namespace v8