summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc1105
-rw-r--r--deps/v8/src/ic/accessor-assembler.h186
-rw-r--r--deps/v8/src/ic/binary-op-assembler.cc319
-rw-r--r--deps/v8/src/ic/binary-op-assembler.h60
-rw-r--r--deps/v8/src/ic/handler-configuration-inl.h36
-rw-r--r--deps/v8/src/ic/handler-configuration.cc2
-rw-r--r--deps/v8/src/ic/handler-configuration.h18
-rw-r--r--deps/v8/src/ic/ic-stats.cc3
-rw-r--r--deps/v8/src/ic/ic-stats.h1
-rw-r--r--deps/v8/src/ic/ic.cc126
-rw-r--r--deps/v8/src/ic/ic.h35
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc261
-rw-r--r--deps/v8/src/ic/keyed-store-generic.h3
-rw-r--r--deps/v8/src/ic/stub-cache.cc5
-rw-r--r--deps/v8/src/ic/stub-cache.h18
15 files changed, 1195 insertions, 983 deletions
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index f9efcba05f..99cbd3c3c8 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -5,6 +5,7 @@
#include "src/ic/accessor-assembler.h"
#include "src/ast/ast.h"
+#include "src/base/optional.h"
#include "src/codegen/code-factory.h"
#include "src/ic/handler-configuration.h"
#include "src/ic/ic.h"
@@ -16,6 +17,7 @@
#include "src/objects/heap-number.h"
#include "src/objects/module.h"
#include "src/objects/objects-inl.h"
+#include "src/objects/property-details.h"
#include "src/objects/smi.h"
namespace v8 {
@@ -23,10 +25,6 @@ namespace internal {
using compiler::CodeAssemblerState;
using compiler::Node;
-template <typename T>
-using TNode = compiler::TNode<T>;
-template <typename T>
-using SloppyTNode = compiler::SloppyTNode<T>;
//////////////////// Private helpers.
@@ -66,27 +64,25 @@ TNode<MaybeObject> AccessorAssembler::LoadHandlerDataField(
}
TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
- Node* slot, Node* vector, Node* receiver_map, Label* if_handler,
- TVariable<MaybeObject>* var_handler, Label* if_miss) {
+ TNode<Smi> slot, TNode<FeedbackVector> vector, TNode<Map> receiver_map,
+ Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss) {
Comment("TryMonomorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
// TODO(ishell): add helper class that hides offset computations for a series
// of loads.
- CSA_ASSERT(this, IsFeedbackVector(vector), vector);
int32_t header_size = FeedbackVector::kFeedbackSlotsOffset - kHeapObjectTag;
// Adding |header_size| with a separate IntPtrAdd rather than passing it
// into ElementOffsetFromIndex() allows it to be folded into a single
// [base, index, offset] indirect memory access on x64.
- TNode<IntPtrT> offset =
- ElementOffsetFromIndex(slot, HOLEY_ELEMENTS, SMI_PARAMETERS);
+ TNode<IntPtrT> offset = ElementOffsetFromIndex(slot, HOLEY_ELEMENTS);
TNode<MaybeObject> feedback = ReinterpretCast<MaybeObject>(
Load(MachineType::AnyTagged(), vector,
IntPtrAdd(offset, IntPtrConstant(header_size))));
// Try to quickly handle the monomorphic case without knowing for sure
// if we have a weak reference in feedback.
- GotoIf(IsNotWeakReferenceTo(feedback, CAST(receiver_map)), if_miss);
+ GotoIfNot(IsWeakReferenceTo(feedback, receiver_map), if_miss);
TNode<MaybeObject> handler = UncheckedCast<MaybeObject>(
Load(MachineType::AnyTagged(), vector,
@@ -98,7 +94,7 @@ TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
}
void AccessorAssembler::HandlePolymorphicCase(
- Node* receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler,
+ TNode<Map> receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler,
TVariable<MaybeObject>* var_handler, Label* if_miss) {
Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
@@ -121,8 +117,7 @@ void AccessorAssembler::HandlePolymorphicCase(
TNode<MaybeObject> maybe_cached_map =
LoadWeakFixedArrayElement(feedback, var_index.value());
CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
- GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
- &loop_next);
+ GotoIfNot(IsWeakReferenceTo(maybe_cached_map, receiver_map), &loop_next);
// Found, now call handler.
TNode<MaybeObject> handler =
@@ -157,7 +152,7 @@ void AccessorAssembler::HandleLoadICHandlerCase(
BIND(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler);
- HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
+ HandleLoadICProtoHandler(p, CAST(handler), &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point, ic_mode,
access_mode);
}
@@ -167,8 +162,8 @@ void AccessorAssembler::HandleLoadICHandlerCase(
BIND(&if_smi_handler);
{
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
- handler, miss, exit_point, on_nonexistent,
- support_elements, access_mode);
+ handler, miss, exit_point, ic_mode,
+ on_nonexistent, support_elements, access_mode);
}
BIND(&call_handler);
@@ -237,9 +232,10 @@ void AccessorAssembler::HandleLoadAccessor(
api_holder.value(), p->receiver()));
}
-void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
+void AccessorAssembler::HandleLoadField(SloppyTNode<JSObject> holder,
+ TNode<WordT> handler_word,
Variable* var_double_value,
- Label* rebox_double,
+ Label* rebox_double, Label* miss,
ExitPoint* exit_point) {
Comment("field_load");
TNode<IntPtrT> index =
@@ -261,8 +257,13 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
var_double_value->Bind(
LoadObjectField(holder, offset, MachineType::Float64()));
} else {
- TNode<HeapNumber> heap_number = CAST(LoadObjectField(holder, offset));
- var_double_value->Bind(LoadHeapNumberValue(heap_number));
+ TNode<Object> heap_number = LoadObjectField(holder, offset);
+ // This is not an "old" Smi value from before a Smi->Double transition.
+ // Rather, it's possible that since the last update of this IC, the Double
+ // field transitioned to a Tagged field, and was then assigned a Smi.
+ GotoIf(TaggedIsSmi(heap_number), miss);
+ GotoIfNot(IsHeapNumber(CAST(heap_number)), miss);
+ var_double_value->Bind(LoadHeapNumberValue(CAST(heap_number)));
}
Goto(rebox_double);
}
@@ -276,6 +277,13 @@ void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
exit_point->Return(value);
BIND(&is_double);
+ if (!FLAG_unbox_double_fields) {
+ // This is not an "old" Smi value from before a Smi->Double transition.
+ // Rather, it's possible that since the last update of this IC, the Double
+ // field transitioned to a Tagged field, and was then assigned a Smi.
+ GotoIf(TaggedIsSmi(value), miss);
+ GotoIfNot(IsHeapNumber(CAST(value)), miss);
+ }
var_double_value->Bind(LoadHeapNumberValue(CAST(value)));
Goto(rebox_double);
}
@@ -293,10 +301,10 @@ TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
}
void AccessorAssembler::HandleLoadICSmiHandlerCase(
- const LazyLoadICParameters* p, Node* holder, SloppyTNode<Smi> smi_handler,
- SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
- OnNonExistent on_nonexistent, ElementSupport support_elements,
- LoadAccessMode access_mode) {
+ const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder,
+ SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss,
+ ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
+ ElementSupport support_elements, LoadAccessMode access_mode) {
VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
@@ -388,10 +396,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
Label if_oob(this, Label::kDeferred);
Comment("indexed string");
+ TNode<String> string_holder = CAST(holder);
TNode<IntPtrT> intptr_index = TryToIntptr(p->name(), miss);
- TNode<IntPtrT> length = LoadStringLengthAsWord(holder);
+ TNode<IntPtrT> length = LoadStringLengthAsWord(string_holder);
GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
- TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
+ TNode<Int32T> code = StringCharCodeAt(string_holder, intptr_index);
TNode<String> result = StringFromSingleCharCode(code);
Return(result);
@@ -410,23 +419,25 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
if (access_mode == LoadAccessMode::kHas) {
HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss,
- exit_point);
+ exit_point, ic_mode);
} else {
HandleLoadICSmiHandlerLoadNamedCase(
p, holder, handler_kind, handler_word, &rebox_double, &var_double_value,
- handler, miss, exit_point, on_nonexistent, support_elements);
+ handler, miss, exit_point, ic_mode, on_nonexistent, support_elements);
}
}
void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
- const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
- TNode<WordT> handler_word, Label* rebox_double, Variable* var_double_value,
- SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
- OnNonExistent on_nonexistent, ElementSupport support_elements) {
+ const LazyLoadICParameters* p, TNode<HeapObject> holder,
+ TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double,
+ Variable* var_double_value, SloppyTNode<Object> handler, Label* miss,
+ ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
+ ElementSupport support_elements) {
Label constant(this), field(this), normal(this, Label::kDeferred),
- interceptor(this, Label::kDeferred), nonexistent(this),
- accessor(this, Label::kDeferred), global(this, Label::kDeferred),
- module_export(this, Label::kDeferred), proxy(this, Label::kDeferred),
+ slow(this, Label::kDeferred), interceptor(this, Label::kDeferred),
+ nonexistent(this), accessor(this, Label::kDeferred),
+ global(this, Label::kDeferred), module_export(this, Label::kDeferred),
+ proxy(this, Label::kDeferred),
native_data_property(this, Label::kDeferred),
api_getter(this, Label::kDeferred);
@@ -459,14 +470,16 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)),
&global);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
+
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)),
&module_export, &interceptor);
BIND(&field);
- HandleLoadField(holder, handler_word, var_double_value, rebox_double,
- exit_point);
+ HandleLoadField(CAST(holder), handler_word, var_double_value, rebox_double,
+ miss, exit_point);
BIND(&nonexistent);
// This is a handler for a load of a non-existent value.
@@ -487,7 +500,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&normal);
{
Comment("load_normal");
- TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
+ TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder)));
TVARIABLE(IntPtrT, var_name_index);
Label found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found,
@@ -529,8 +542,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
BIND(&proxy);
{
- VARIABLE(var_index, MachineType::PointerRepresentation());
- VARIABLE(var_unique, MachineRepresentation::kTagged);
+ TVARIABLE(IntPtrT, var_index);
+ TVARIABLE(Name, var_unique);
Label if_index(this), if_unique_name(this),
to_name_failed(this, Label::kDeferred);
@@ -586,20 +599,31 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
p->context(), p->name(), p->receiver(),
holder, p->slot(), p->vector());
}
+ BIND(&slow);
+ {
+ Comment("load_slow");
+ if (ic_mode == ICMode::kGlobalIC) {
+ exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
+ p->name(), p->slot(), p->vector());
+
+ } else {
+ exit_point->ReturnCallRuntime(Runtime::kGetProperty, p->context(),
+ p->receiver(), p->name());
+ }
+ }
BIND(&module_export);
{
Comment("module export");
TNode<UintPtrT> index =
DecodeWord<LoadHandler::ExportsIndexBits>(handler_word);
- Node* module =
- LoadObjectField(p->receiver(), JSModuleNamespace::kModuleOffset,
- MachineType::TaggedPointer());
- TNode<ObjectHashTable> exports = CAST(LoadObjectField(
- module, Module::kExportsOffset, MachineType::TaggedPointer()));
+ TNode<Module> module =
+ CAST(LoadObjectField(p->receiver(), JSModuleNamespace::kModuleOffset));
+ TNode<ObjectHashTable> exports =
+ LoadObjectField<ObjectHashTable>(module, Module::kExportsOffset);
TNode<Cell> cell = CAST(LoadFixedArrayElement(exports, index));
// The handler is only installed for exports that exist.
- Node* value = LoadCellValue(cell);
+ TNode<Object> value = LoadCellValue(cell);
Label is_the_hole(this, Label::kDeferred);
GotoIf(IsTheHole(value), &is_the_hole);
exit_point->Return(value);
@@ -617,10 +641,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
}
void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
- const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
- Label* miss, ExitPoint* exit_point) {
+ const LazyLoadICParameters* p, TNode<HeapObject> holder,
+ TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point,
+ ICMode ic_mode) {
Label return_true(this), return_false(this), return_lookup(this),
- normal(this), global(this);
+ normal(this), global(this), slow(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
&return_true);
@@ -649,6 +674,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
&return_true);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
+
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
&return_lookup);
@@ -676,7 +703,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
BIND(&normal);
{
Comment("has_normal");
- TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
+ TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(holder)));
TVARIABLE(IntPtrT, var_name_index);
Label found(this);
NameDictionaryLookup<NameDictionary>(properties, CAST(p->name()), &found,
@@ -695,6 +722,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
exit_point->Return(TrueConstant());
}
+
+ BIND(&slow);
+ {
+ Comment("load_slow");
+ if (ic_mode == ICMode::kGlobalIC) {
+ exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
+ p->name(), p->slot(), p->vector());
+ } else {
+ exit_point->ReturnCallRuntime(Runtime::kHasProperty, p->context(),
+ p->receiver(), p->name());
+ }
+ }
}
// Performs actions common to both load and store handlers:
@@ -715,8 +754,9 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
// TODO(ishell): Remove templatezation once we move common bits from
// Load/StoreHandler to the base class.
template <typename ICHandler, typename ICParameters>
-Node* AccessorAssembler::HandleProtoHandler(
- const ICParameters* p, Node* handler, const OnCodeHandler& on_code_handler,
+TNode<Object> AccessorAssembler::HandleProtoHandler(
+ const ICParameters* p, TNode<DataHandler> handler,
+ const OnCodeHandler& on_code_handler,
const OnFoundOnReceiver& on_found_on_receiver, Label* miss,
ICMode ic_mode) {
//
@@ -738,8 +778,7 @@ Node* AccessorAssembler::HandleProtoHandler(
Label if_smi_handler(this);
GotoIf(TaggedIsSmi(smi_or_code_handler), &if_smi_handler);
- CSA_ASSERT(this, IsCodeMap(LoadMap(CAST(smi_or_code_handler))));
- on_code_handler(smi_or_code_handler);
+ on_code_handler(CAST(smi_or_code_handler));
BIND(&if_smi_handler);
}
@@ -771,8 +810,8 @@ Node* AccessorAssembler::HandleProtoHandler(
CSA_ASSERT(this, IsWeakOrCleared(data2));
TNode<Context> expected_native_context =
CAST(GetHeapObjectAssumeWeak(data2, miss));
- EmitAccessCheck(expected_native_context, p->context(), p->receiver(),
- &done, miss);
+ EmitAccessCheck(expected_native_context, p->context(),
+ CAST(p->receiver()), &done, miss);
}
// Dictionary lookup on receiver is not necessary for Load/StoreGlobalIC
@@ -807,18 +846,19 @@ Node* AccessorAssembler::HandleProtoHandler(
}
void AccessorAssembler::HandleLoadICProtoHandler(
- const LazyLoadICParameters* p, Node* handler, Variable* var_holder,
- Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
- ExitPoint* exit_point, ICMode ic_mode, LoadAccessMode access_mode) {
+ const LazyLoadICParameters* p, TNode<DataHandler> handler,
+ Variable* var_holder, Variable* var_smi_handler, Label* if_smi_handler,
+ Label* miss, ExitPoint* exit_point, ICMode ic_mode,
+ LoadAccessMode access_mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
- Node* smi_handler = HandleProtoHandler<LoadHandler>(
+ TNode<Smi> smi_handler = CAST(HandleProtoHandler<LoadHandler>(
p, handler,
// Code sub-handlers are not expected in LoadICs, so no |on_code_handler|.
nullptr,
// on_found_on_receiver
- [=](Node* properties, Node* name_index) {
+ [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant());
} else {
@@ -832,7 +872,7 @@ void AccessorAssembler::HandleLoadICProtoHandler(
exit_point->Return(value);
}
},
- miss, ic_mode);
+ miss, ic_mode));
TNode<MaybeObject> maybe_holder_or_constant =
LoadHandlerDataField(handler, 1);
@@ -840,7 +880,7 @@ void AccessorAssembler::HandleLoadICProtoHandler(
Label load_from_cached_holder(this), is_smi(this), done(this);
GotoIf(TaggedIsSmi(maybe_holder_or_constant), &is_smi);
- Branch(IsStrongReferenceTo(maybe_holder_or_constant, NullConstant()), &done,
+ Branch(TaggedEqual(maybe_holder_or_constant, NullConstant()), &done,
&load_from_cached_holder);
BIND(&is_smi);
@@ -878,14 +918,15 @@ void AccessorAssembler::HandleLoadICProtoHandler(
}
void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context,
- TNode<Context> context, Node* receiver,
+ TNode<Context> context,
+ TNode<Object> receiver,
Label* can_access, Label* miss) {
CSA_ASSERT(this, IsNativeContext(expected_native_context));
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
GotoIf(TaggedEqual(expected_native_context, native_context), can_access);
// If the receiver is not a JSGlobalProxy then we miss.
- GotoIfNot(IsJSGlobalProxy(receiver), miss);
+ GotoIfNot(IsJSGlobalProxy(CAST(receiver)), miss);
// For JSGlobalProxy receiver try to compare security tokens of current
// and expected native contexts.
TNode<Object> expected_token = LoadContextElement(
@@ -895,8 +936,8 @@ void AccessorAssembler::EmitAccessCheck(TNode<Context> expected_native_context,
Branch(TaggedEqual(expected_token, current_token), can_access, miss);
}
-void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
- Label* readonly) {
+void AccessorAssembler::JumpIfDataProperty(TNode<Uint32T> details,
+ Label* writable, Label* readonly) {
if (readonly) {
// Accessor properties never have the READ_ONLY attribute set.
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
@@ -911,10 +952,11 @@ void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
}
void AccessorAssembler::HandleStoreICNativeDataProperty(
- const StoreICParameters* p, Node* holder, Node* handler_word) {
+ const StoreICParameters* p, SloppyTNode<HeapObject> holder,
+ TNode<Word32T> handler_word) {
Comment("native_data_property_store");
TNode<IntPtrT> descriptor =
- Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
+ Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<AccessorInfo> accessor_info =
CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
@@ -936,23 +978,30 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_smi_handler);
{
Node* holder = p->receiver();
- TNode<IntPtrT> handler_word = SmiUntag(CAST(handler));
+ TNode<Int32T> handler_word = SmiToInt32(CAST(handler));
- Label if_fast_smi(this), if_proxy(this);
+ Label if_fast_smi(this), if_proxy(this), if_interceptor(this),
+ if_slow(this);
STATIC_ASSERT(StoreHandler::kGlobalProxy + 1 == StoreHandler::kNormal);
- STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kProxy);
+ STATIC_ASSERT(StoreHandler::kNormal + 1 == StoreHandler::kInterceptor);
+ STATIC_ASSERT(StoreHandler::kInterceptor + 1 == StoreHandler::kSlow);
+ STATIC_ASSERT(StoreHandler::kSlow + 1 == StoreHandler::kProxy);
STATIC_ASSERT(StoreHandler::kProxy + 1 == StoreHandler::kKindsNumber);
- TNode<UintPtrT> handler_kind =
- DecodeWord<StoreHandler::KindBits>(handler_word);
- GotoIf(IntPtrLessThan(handler_kind,
- IntPtrConstant(StoreHandler::kGlobalProxy)),
- &if_fast_smi);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)),
+ TNode<Uint32T> handler_kind =
+ DecodeWord32<StoreHandler::KindBits>(handler_word);
+ GotoIf(
+ Int32LessThan(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
+ &if_fast_smi);
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)),
&if_proxy);
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)),
+ &if_interceptor);
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
+ &if_slow);
CSA_ASSERT(this,
- WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)));
+ Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)));
TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
TVARIABLE(IntPtrT, var_name_index);
@@ -976,14 +1025,14 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_fast_smi);
{
- TNode<UintPtrT> handler_kind =
- DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<Uint32T> handler_kind =
+ DecodeWord32<StoreHandler::KindBits>(handler_word);
Label data(this), accessor(this), native_data_property(this);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
&accessor);
- Branch(WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kNativeDataProperty)),
+ Branch(Word32Equal(handler_kind,
+ Int32Constant(StoreHandler::kNativeDataProperty)),
&native_data_property, &data);
BIND(&accessor);
@@ -999,6 +1048,29 @@ void AccessorAssembler::HandleStoreICHandlerCase(
BIND(&if_proxy);
HandleStoreToProxy(p, holder, miss, support_elements);
+
+ BIND(&if_interceptor);
+ {
+ Comment("store_interceptor");
+ TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(),
+ p->value(), p->slot(), p->vector(), p->receiver(),
+ p->name());
+ }
+
+ BIND(&if_slow);
+ {
+ Comment("store_slow");
+ // The slow case calls into the runtime to complete the store without
+ // causing an IC miss that would otherwise cause a transition to the
+ // generic stub.
+ if (ic_mode == ICMode::kGlobalIC) {
+ TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
+ p->slot(), p->vector(), p->receiver(), p->name());
+ } else {
+ TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(),
+ p->receiver(), p->name());
+ }
+ }
}
BIND(&if_nonsmi_handler);
@@ -1111,7 +1183,7 @@ void AccessorAssembler::HandleStoreICTransitionMapHandlerCase(
}
void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
- Node* name_index,
+ TNode<IntPtrT> name_index,
TNode<Word32T> representation,
Node* value, Label* bailout) {
Label r_smi(this), r_double(this), r_heapobject(this), all_fine(this);
@@ -1143,20 +1215,20 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
BIND(&r_heapobject);
{
GotoIf(TaggedIsSmi(value), bailout);
- TNode<MaybeObject> field_type = LoadFieldTypeByKeyIndex(
- descriptors, UncheckedCast<IntPtrT>(name_index));
+ TNode<MaybeObject> field_type =
+ LoadFieldTypeByKeyIndex(descriptors, name_index);
const Address kNoneType = FieldType::None().ptr();
const Address kAnyType = FieldType::Any().ptr();
DCHECK_NE(static_cast<uint32_t>(kNoneType), kClearedWeakHeapObjectLower32);
DCHECK_NE(static_cast<uint32_t>(kAnyType), kClearedWeakHeapObjectLower32);
// FieldType::None can't hold any value.
- GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
- IntPtrConstant(kNoneType)),
- bailout);
+ GotoIf(
+ TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kNoneType))),
+ bailout);
// FieldType::Any can hold any value.
- GotoIf(WordEqual(BitcastMaybeObjectToWord(field_type),
- IntPtrConstant(kAnyType)),
- &all_fine);
+ GotoIf(
+ TaggedEqual(field_type, BitcastWordToTagged(IntPtrConstant(kAnyType))),
+ &all_fine);
// Cleared weak references count as FieldType::None, which can't hold any
// value.
TNode<Map> field_type_map =
@@ -1168,15 +1240,16 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
BIND(&all_fine);
}
-TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(Node* details) {
+TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(TNode<Uint32T> details) {
return Word32Equal(DecodeWord32<PropertyDetails::ConstnessField>(details),
Int32Constant(static_cast<int32_t>(VariableMode::kConst)));
}
void AccessorAssembler::OverwriteExistingFastDataProperty(
- Node* object, Node* object_map, Node* descriptors,
- Node* descriptor_name_index, Node* details, TNode<Object> value,
- Label* slow, bool do_transitioning_store) {
+ SloppyTNode<HeapObject> object, TNode<Map> object_map,
+ TNode<DescriptorArray> descriptors, TNode<IntPtrT> descriptor_name_index,
+ TNode<Uint32T> details, TNode<Object> value, Label* slow,
+ bool do_transitioning_store) {
Label done(this), if_field(this), if_descriptor(this);
CSA_ASSERT(this,
@@ -1192,8 +1265,8 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
TNode<Uint32T> representation =
DecodeWord32<PropertyDetails::RepresentationField>(details);
- CheckFieldType(CAST(descriptors), descriptor_name_index, representation,
- value, slow);
+ CheckFieldType(descriptors, descriptor_name_index, representation, value,
+ slow);
TNode<UintPtrT> field_index =
DecodeWordFromWord32<PropertyDetails::FieldIndexField>(details);
@@ -1224,7 +1297,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
Label if_mutable(this);
GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
TNode<Float64T> current_value =
- LoadObjectField<Float64T>(CAST(object), field_offset);
+ LoadObjectField<Float64T>(object, field_offset);
BranchIfSameNumberValue(current_value, double_value, &done, slow);
BIND(&if_mutable);
}
@@ -1257,8 +1330,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
} else {
Label if_mutable(this);
GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
- TNode<Object> current_value =
- LoadObjectField(CAST(object), field_offset);
+ TNode<Object> current_value = LoadObjectField(object, field_offset);
BranchIfSameValue(current_value, value, &done, slow,
SameValueMode::kNumbersOnly);
BIND(&if_mutable);
@@ -1302,7 +1374,8 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
} else {
Label tagged_rep(this), double_rep(this);
- TNode<PropertyArray> properties = CAST(LoadFastProperties(object));
+ TNode<PropertyArray> properties =
+ CAST(LoadFastProperties(CAST(object)));
Branch(
Word32Equal(representation, Int32Constant(Representation::kDouble)),
&double_rep, &tagged_rep);
@@ -1342,7 +1415,7 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
{
// Check that constant matches value.
TNode<Object> constant = LoadValueByKeyIndex(
- CAST(descriptors), UncheckedCast<IntPtrT>(descriptor_name_index));
+ descriptors, UncheckedCast<IntPtrT>(descriptor_name_index));
GotoIf(TaggedNotEqual(value, constant), slow);
if (do_transitioning_store) {
@@ -1370,10 +1443,11 @@ void AccessorAssembler::CheckPrototypeValidityCell(
}
void AccessorAssembler::HandleStoreAccessor(const StoreICParameters* p,
- Node* holder, Node* handler_word) {
+ SloppyTNode<HeapObject> holder,
+ TNode<Word32T> handler_word) {
Comment("accessor_store");
TNode<IntPtrT> descriptor =
- Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
+ Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
TNode<HeapObject> accessor_pair =
CAST(LoadDescriptorValue(LoadMap(holder), descriptor));
CSA_ASSERT(this, IsAccessorPair(accessor_pair));
@@ -1393,7 +1467,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
OnCodeHandler on_code_handler;
if (support_elements == kSupportElements) {
// Code sub-handlers are expected only in KeyedStoreICs.
- on_code_handler = [=](Node* code_handler) {
+ on_code_handler = [=](TNode<Code> code_handler) {
// This is either element store or transitioning element store.
Label if_element_store(this), if_transitioning_element_store(this);
Branch(IsStoreHandler0Map(LoadMap(handler)), &if_element_store,
@@ -1421,10 +1495,10 @@ void AccessorAssembler::HandleStoreICProtoHandler(
};
}
- Node* smi_handler = HandleProtoHandler<StoreHandler>(
+ TNode<Object> smi_handler = HandleProtoHandler<StoreHandler>(
p, handler, on_code_handler,
// on_found_on_receiver
- [=](Node* properties, Node* name_index) {
+ [=](TNode<NameDictionary> properties, TNode<IntPtrT> name_index) {
TNode<Uint32T> details =
LoadDetailsByKeyIndex<NameDictionary>(properties, name_index);
// Check that the property is a writable data property (no accessor).
@@ -1434,49 +1508,80 @@ void AccessorAssembler::HandleStoreICProtoHandler(
STATIC_ASSERT(kData == 0);
GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
- StoreValueByKeyIndex<NameDictionary>(
- CAST(properties), UncheckedCast<IntPtrT>(name_index), p->value());
+ StoreValueByKeyIndex<NameDictionary>(properties, name_index,
+ p->value());
Return(p->value());
},
miss, ic_mode);
{
Label if_add_normal(this), if_store_global_proxy(this), if_api_setter(this),
- if_accessor(this), if_native_data_property(this);
+ if_accessor(this), if_native_data_property(this), if_slow(this),
+ if_interceptor(this);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
- TNode<IntPtrT> handler_word = SmiUntag(smi_handler);
+ TNode<Int32T> handler_word = SmiToInt32(CAST(smi_handler));
- TNode<UintPtrT> handler_kind =
- DecodeWord<StoreHandler::KindBits>(handler_word);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kNormal)),
+ TNode<Uint32T> handler_kind =
+ DecodeWord32<StoreHandler::KindBits>(handler_word);
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kNormal)),
&if_add_normal);
TNode<MaybeObject> maybe_holder = LoadHandlerDataField(handler, 1);
CSA_ASSERT(this, IsWeakOrCleared(maybe_holder));
TNode<HeapObject> holder = GetHeapObjectAssumeWeak(maybe_holder, miss);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kGlobalProxy)),
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kGlobalProxy)),
&if_store_global_proxy);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kAccessor)),
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kAccessor)),
&if_accessor);
- GotoIf(WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kNativeDataProperty)),
+ GotoIf(Word32Equal(handler_kind,
+ Int32Constant(StoreHandler::kNativeDataProperty)),
&if_native_data_property);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
&if_api_setter);
- GotoIf(WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)),
- &if_api_setter);
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kSlow)),
+ &if_slow);
+
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kInterceptor)),
+ &if_interceptor);
+
+ GotoIf(
+ Word32Equal(handler_kind,
+ Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)),
+ &if_api_setter);
CSA_ASSERT(this,
- WordEqual(handler_kind, IntPtrConstant(StoreHandler::kProxy)));
+ Word32Equal(handler_kind, Int32Constant(StoreHandler::kProxy)));
HandleStoreToProxy(p, holder, miss, support_elements);
+ BIND(&if_slow);
+ {
+ Comment("store_slow");
+ // The slow case calls into the runtime to complete the store without
+ // causing an IC miss that would otherwise cause a transition to the
+ // generic stub.
+ if (ic_mode == ICMode::kGlobalIC) {
+ TailCallRuntime(Runtime::kStoreGlobalIC_Slow, p->context(), p->value(),
+ p->slot(), p->vector(), p->receiver(), p->name());
+ } else {
+ TailCallRuntime(Runtime::kKeyedStoreIC_Slow, p->context(), p->value(),
+ p->receiver(), p->name());
+ }
+ }
+
+ BIND(&if_interceptor);
+ {
+ Comment("store_interceptor");
+ TailCallRuntime(Runtime::kStorePropertyWithInterceptor, p->context(),
+ p->value(), p->slot(), p->vector(), p->receiver(),
+ p->name());
+ }
+
BIND(&if_add_normal);
{
// This is a case of "transitioning store" to a dictionary mode object
@@ -1512,7 +1617,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
// Context is stored either in data2 or data3 field depending on whether
// the access check is enabled for this handler or not.
TNode<MaybeObject> maybe_context = Select<MaybeObject>(
- IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
+ IsSetWord32<LoadHandler::DoAccessCheckOnReceiverBits>(handler_word),
[=] { return LoadHandlerDataField(handler, 3); },
[=] { return LoadHandlerDataField(handler, 2); });
@@ -1530,13 +1635,13 @@ void AccessorAssembler::HandleStoreICProtoHandler(
VARIABLE(api_holder, MachineRepresentation::kTagged, p->receiver());
Label store(this);
- GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kApiSetter)),
+ GotoIf(Word32Equal(handler_kind, Int32Constant(StoreHandler::kApiSetter)),
&store);
- CSA_ASSERT(
- this,
- WordEqual(handler_kind,
- IntPtrConstant(StoreHandler::kApiSetterHolderIsPrototype)));
+ CSA_ASSERT(this,
+ Word32Equal(
+ handler_kind,
+ Int32Constant(StoreHandler::kApiSetterHolderIsPrototype)));
api_holder.Bind(LoadMapPrototype(LoadMap(p->receiver())));
Goto(&store);
@@ -1559,8 +1664,8 @@ void AccessorAssembler::HandleStoreICProtoHandler(
void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
Node* proxy, Label* miss,
ElementSupport support_elements) {
- VARIABLE(var_index, MachineType::PointerRepresentation());
- VARIABLE(var_unique, MachineRepresentation::kTagged);
+ TVARIABLE(IntPtrT, var_index);
+ TVARIABLE(Name, var_unique);
Label if_index(this), if_unique_name(this),
to_name_failed(this, Label::kDeferred);
@@ -1591,128 +1696,200 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
}
}
-void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
- Node* holder, Node* value,
- Label* miss) {
+void AccessorAssembler::HandleStoreICSmiHandlerCase(
+ SloppyTNode<Word32T> handler_word, SloppyTNode<JSObject> holder,
+ SloppyTNode<Object> value, Label* miss) {
Comment("field store");
#ifdef DEBUG
- TNode<UintPtrT> handler_kind =
- DecodeWord<StoreHandler::KindBits>(handler_word);
+ TNode<Uint32T> handler_kind =
+ DecodeWord32<StoreHandler::KindBits>(handler_word);
CSA_ASSERT(
this,
Word32Or(
- WordEqual(handler_kind, IntPtrConstant(StoreHandler::kField)),
- WordEqual(handler_kind, IntPtrConstant(StoreHandler::kConstField))));
+ Word32Equal(handler_kind, Int32Constant(StoreHandler::kField)),
+ Word32Equal(handler_kind, Int32Constant(StoreHandler::kConstField))));
#endif
- TNode<UintPtrT> field_representation =
- DecodeWord<StoreHandler::FieldRepresentationBits>(handler_word);
+ TNode<Uint32T> field_representation =
+ DecodeWord32<StoreHandler::RepresentationBits>(handler_word);
Label if_smi_field(this), if_double_field(this), if_heap_object_field(this),
if_tagged_field(this);
- GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kTagged)),
- &if_tagged_field);
- GotoIf(WordEqual(field_representation,
- IntPtrConstant(StoreHandler::kHeapObject)),
- &if_heap_object_field);
- GotoIf(WordEqual(field_representation, IntPtrConstant(StoreHandler::kDouble)),
- &if_double_field);
- CSA_ASSERT(this, WordEqual(field_representation,
- IntPtrConstant(StoreHandler::kSmi)));
- Goto(&if_smi_field);
+ int32_t case_values[] = {Representation::kTagged, Representation::kHeapObject,
+ Representation::kSmi};
+ Label* case_labels[] = {&if_tagged_field, &if_heap_object_field,
+ &if_smi_field};
+
+ Switch(field_representation, &if_double_field, case_values, case_labels, 3);
BIND(&if_tagged_field);
{
Comment("store tagged field");
- HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
- value, miss);
- }
-
- BIND(&if_double_field);
- {
- Comment("store double field");
- HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
- value, miss);
+ HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
+ Representation::Tagged(), miss);
}
BIND(&if_heap_object_field);
{
+ Comment("heap object field checks");
+ CheckHeapObjectTypeMatchesDescriptor(handler_word, holder, value, miss);
+
Comment("store heap object field");
- HandleStoreFieldAndReturn(handler_word, holder,
- Representation::HeapObject(), value, miss);
+ HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
+ Representation::HeapObject(), miss);
}
BIND(&if_smi_field);
{
+ Comment("smi field checks");
+ GotoIfNot(TaggedIsSmi(value), miss);
+
Comment("store smi field");
- HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
- value, miss);
+ HandleStoreFieldAndReturn(handler_word, holder, value, base::nullopt,
+ Representation::Smi(), miss);
+ }
+
+ BIND(&if_double_field);
+ {
+ CSA_ASSERT(this, Word32Equal(field_representation,
+ Int32Constant(Representation::kDouble)));
+ Comment("double field checks");
+ TNode<Float64T> double_value = TryTaggedToFloat64(value, miss);
+ CheckDescriptorConsidersNumbersMutable(handler_word, holder, miss);
+
+ Comment("store double field");
+ HandleStoreFieldAndReturn(handler_word, holder, value, double_value,
+ Representation::Double(), miss);
}
}
-void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
- Node* holder,
- Representation representation,
- Node* value, Label* miss) {
- Node* prepared_value =
- PrepareValueForStore(handler_word, holder, representation, value, miss);
+void AccessorAssembler::CheckHeapObjectTypeMatchesDescriptor(
+ TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
+ Label* bailout) {
+ GotoIf(TaggedIsSmi(value), bailout);
- Label if_inobject(this), if_out_of_object(this);
- Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
- &if_out_of_object);
+ Label done(this);
+ // Skip field type check in favor of constant value check when storing
+ // to constant field.
+ GotoIf(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
+ Int32Constant(StoreHandler::kConstField)),
+ &done);
+ TNode<IntPtrT> descriptor =
+ Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
+ TNode<MaybeObject> maybe_field_type =
+ LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
- BIND(&if_inobject);
+ GotoIf(TaggedIsSmi(maybe_field_type), &done);
+ // Check that value type matches the field type.
{
- StoreNamedField(handler_word, holder, true, representation, prepared_value,
- miss);
- Return(value);
+ TNode<HeapObject> field_type =
+ GetHeapObjectAssumeWeak(maybe_field_type, bailout);
+ Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout);
}
+ BIND(&done);
+}
- BIND(&if_out_of_object);
- {
- StoreNamedField(handler_word, holder, false, representation, prepared_value,
- miss);
- Return(value);
- }
+void AccessorAssembler::CheckDescriptorConsidersNumbersMutable(
+ TNode<Word32T> handler_word, TNode<JSObject> holder, Label* bailout) {
+ // We have to check that the representation is Double. Checking the value
+ // (either in the field or being assigned) is not enough, as we could have
+ // transitioned to Tagged but still be holding a HeapNumber, which would no
+ // longer be allowed to be mutable.
+
+ // TODO(leszeks): We could skip the representation check in favor of a
+ // constant value check in HandleStoreFieldAndReturn here, but then
+ // HandleStoreFieldAndReturn would need an IsHeapNumber check in case both the
+ // representation changed and the value is no longer a HeapNumber.
+ TNode<IntPtrT> descriptor_entry =
+ Signed(DecodeWordFromWord32<StoreHandler::DescriptorBits>(handler_word));
+ TNode<DescriptorArray> descriptors = LoadMapDescriptors(LoadMap(holder));
+ TNode<Uint32T> details =
+ LoadDetailsByDescriptorEntry(descriptors, descriptor_entry);
+
+ GotoIfNot(IsEqualInWord32<PropertyDetails::RepresentationField>(
+ details, Representation::kDouble),
+ bailout);
}
-Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
- Representation representation,
- Node* value, Label* bailout) {
- if (representation.IsDouble()) {
- value = TryTaggedToFloat64(value, bailout);
+void AccessorAssembler::HandleStoreFieldAndReturn(
+ TNode<Word32T> handler_word, TNode<JSObject> holder, TNode<Object> value,
+ base::Optional<TNode<Float64T>> double_value, Representation representation,
+ Label* miss) {
+ Label done(this);
- } else if (representation.IsHeapObject()) {
- GotoIf(TaggedIsSmi(value), bailout);
+ bool store_value_as_double = representation.IsDouble();
- Label done(this);
- // Skip field type check in favor of constant value check when storing
- // to constant field.
- GotoIf(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
- IntPtrConstant(StoreHandler::kConstField)),
- &done);
- TNode<IntPtrT> descriptor =
- Signed(DecodeWord<StoreHandler::DescriptorBits>(handler_word));
- TNode<MaybeObject> maybe_field_type =
- LoadDescriptorValueOrFieldType(LoadMap(holder), descriptor);
+ TNode<BoolT> is_inobject =
+ IsSetWord32<StoreHandler::IsInobjectBits>(handler_word);
+ TNode<HeapObject> property_storage = Select<HeapObject>(
+ is_inobject, [&]() { return holder; },
+ [&]() { return LoadFastProperties(holder); });
- GotoIf(TaggedIsSmi(maybe_field_type), &done);
- // Check that value type matches the field type.
- {
- TNode<HeapObject> field_type =
- GetHeapObjectAssumeWeak(maybe_field_type, bailout);
- Branch(TaggedEqual(LoadMap(CAST(value)), field_type), &done, bailout);
+ TNode<UintPtrT> index =
+ DecodeWordFromWord32<StoreHandler::FieldIndexBits>(handler_word);
+ TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
+
+ // For Double fields, we want to mutate the current double-value
+ // field rather than changing it to point at a new HeapNumber.
+ if (store_value_as_double) {
+ TVARIABLE(HeapObject, actual_property_storage, property_storage);
+ TVARIABLE(IntPtrT, actual_offset, offset);
+
+ Label property_and_offset_ready(this);
+
+ // If we are unboxing double fields, and this is an in-object field, the
+ // property_storage and offset are already pointing to the double-valued
+ // field.
+ if (FLAG_unbox_double_fields) {
+ GotoIf(is_inobject, &property_and_offset_ready);
}
- BIND(&done);
- } else if (representation.IsSmi()) {
- GotoIfNot(TaggedIsSmi(value), bailout);
+ // Store the double value directly into the mutable HeapNumber.
+ TNode<Object> field = LoadObjectField(property_storage, offset);
+ CSA_ASSERT(this, IsHeapNumber(CAST(field)));
+ actual_property_storage = CAST(field);
+ actual_offset = IntPtrConstant(HeapNumber::kValueOffset);
+ Goto(&property_and_offset_ready);
+
+ BIND(&property_and_offset_ready);
+ property_storage = actual_property_storage.value();
+ offset = actual_offset.value();
+ }
+
+ // Do constant value check if necessary.
+ Label do_store(this);
+ GotoIfNot(Word32Equal(DecodeWord32<StoreHandler::KindBits>(handler_word),
+ Int32Constant(StoreHandler::kConstField)),
+ &do_store);
+ {
+ if (store_value_as_double) {
+ Label done(this);
+ TNode<Float64T> current_value =
+ LoadObjectField<Float64T>(property_storage, offset);
+ BranchIfSameNumberValue(current_value, *double_value, &done, miss);
+ BIND(&done);
+ Return(value);
+ } else {
+ TNode<Object> current_value = LoadObjectField(property_storage, offset);
+ GotoIfNot(TaggedEqual(current_value, value), miss);
+ Return(value);
+ }
+ }
+ BIND(&do_store);
+ // Do the store.
+ if (store_value_as_double) {
+ StoreObjectFieldNoWriteBarrier(property_storage, offset, *double_value,
+ MachineRepresentation::kFloat64);
+ } else if (representation.IsSmi()) {
+ TNode<Smi> value_smi = CAST(value);
+ StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
} else {
- DCHECK(representation.IsTagged());
+ StoreObjectField(property_storage, offset, value);
}
- return value;
+
+ Return(value);
}
Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
@@ -1737,7 +1914,7 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
BIND(&if_smi_hash);
{
TNode<Int32T> hash = SmiToInt32(CAST(properties));
- TNode<Word32T> encoded_hash =
+ TNode<Int32T> encoded_hash =
Word32Shl(hash, Int32Constant(PropertyArray::HashField::kShift));
var_encoded_hash.Bind(encoded_hash);
var_length.Bind(IntPtrOrSmiConstant(0, mode));
@@ -1813,59 +1990,6 @@ Node* AccessorAssembler::ExtendPropertiesBackingStore(Node* object,
}
}
-void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
- bool is_inobject,
- Representation representation,
- Node* value, Label* bailout) {
- bool store_value_as_double = representation.IsDouble();
- Node* property_storage = object;
- if (!is_inobject) {
- property_storage = LoadFastProperties(object);
- }
-
- TNode<UintPtrT> index =
- DecodeWord<StoreHandler::FieldIndexBits>(handler_word);
- TNode<IntPtrT> offset = Signed(TimesTaggedSize(index));
- if (representation.IsDouble()) {
- if (!FLAG_unbox_double_fields || !is_inobject) {
- // Load the mutable heap number.
- property_storage = LoadObjectField(property_storage, offset);
- // Store the double value into it.
- offset = IntPtrConstant(HeapNumber::kValueOffset);
- }
- }
-
- // Do constant value check if necessary.
- Label const_checked(this);
- GotoIfNot(WordEqual(DecodeWord<StoreHandler::KindBits>(handler_word),
- IntPtrConstant(StoreHandler::kConstField)),
- &const_checked);
- {
- if (store_value_as_double) {
- TNode<Float64T> current_value =
- LoadObjectField<Float64T>(CAST(property_storage), offset);
- BranchIfSameNumberValue(current_value, UncheckedCast<Float64T>(value),
- &const_checked, bailout);
- } else {
- TNode<Object> current_value = LoadObjectField(property_storage, offset);
- Branch(TaggedEqual(current_value, UncheckedCast<Object>(value)),
- &const_checked, bailout);
- }
- }
-
- BIND(&const_checked);
- // Do the store.
- if (store_value_as_double) {
- StoreObjectFieldNoWriteBarrier(property_storage, offset, value,
- MachineRepresentation::kFloat64);
- } else if (representation.IsSmi()) {
- TNode<Smi> value_smi = CAST(value);
- StoreObjectFieldNoWriteBarrier(property_storage, offset, value_smi);
- } else {
- StoreObjectField(property_storage, offset, value);
- }
-}
-
void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
Node* elements,
Node* intptr_index,
@@ -2012,8 +2136,7 @@ void AccessorAssembler::EmitElementLoad(
if (access_mode == LoadAccessMode::kHas) {
exit_point->Return(TrueConstant());
} else {
- TNode<RawPtrT> backing_store =
- LoadJSTypedArrayBackingStore(CAST(object));
+ TNode<RawPtrT> data_ptr = LoadJSTypedArrayDataPtr(CAST(object));
Label uint8_elements(this), int8_elements(this), uint16_elements(this),
int16_elements(this), uint32_elements(this), int32_elements(this),
@@ -2039,50 +2162,48 @@ void AccessorAssembler::EmitElementLoad(
BIND(&uint8_elements);
{
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
- Node* element =
- Load(MachineType::Uint8(), backing_store, intptr_index);
+ Node* element = Load(MachineType::Uint8(), data_ptr, intptr_index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&int8_elements);
{
Comment("INT8_ELEMENTS");
- Node* element =
- Load(MachineType::Int8(), backing_store, intptr_index);
+ Node* element = Load(MachineType::Int8(), data_ptr, intptr_index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&uint16_elements);
{
Comment("UINT16_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
- Node* element = Load(MachineType::Uint16(), backing_store, index);
+ Node* element = Load(MachineType::Uint16(), data_ptr, index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&int16_elements);
{
Comment("INT16_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(1));
- Node* element = Load(MachineType::Int16(), backing_store, index);
+ Node* element = Load(MachineType::Int16(), data_ptr, index);
exit_point->Return(SmiFromInt32(element));
}
BIND(&uint32_elements);
{
Comment("UINT32_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Uint32(), backing_store, index);
+ Node* element = Load(MachineType::Uint32(), data_ptr, index);
exit_point->Return(ChangeUint32ToTagged(element));
}
BIND(&int32_elements);
{
Comment("INT32_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Int32(), backing_store, index);
+ Node* element = Load(MachineType::Int32(), data_ptr, index);
exit_point->Return(ChangeInt32ToTagged(element));
}
BIND(&float32_elements);
{
Comment("FLOAT32_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Float32(), backing_store, index);
+ Node* element = Load(MachineType::Float32(), data_ptr, index);
var_double_value->Bind(ChangeFloat32ToFloat64(element));
Goto(rebox_double);
}
@@ -2090,7 +2211,7 @@ void AccessorAssembler::EmitElementLoad(
{
Comment("FLOAT64_ELEMENTS");
TNode<IntPtrT> index = WordShl(intptr_index, IntPtrConstant(3));
- Node* element = Load(MachineType::Float64(), backing_store, index);
+ Node* element = Load(MachineType::Float64(), data_ptr, index);
var_double_value->Bind(element);
Goto(rebox_double);
}
@@ -2098,15 +2219,13 @@ void AccessorAssembler::EmitElementLoad(
{
Comment("BIGINT64_ELEMENTS");
exit_point->Return(LoadFixedTypedArrayElementAsTagged(
- backing_store, intptr_index, BIGINT64_ELEMENTS,
- INTPTR_PARAMETERS));
+ data_ptr, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
}
BIND(&biguint64_elements);
{
Comment("BIGUINT64_ELEMENTS");
exit_point->Return(LoadFixedTypedArrayElementAsTagged(
- backing_store, intptr_index, BIGUINT64_ELEMENTS,
- INTPTR_PARAMETERS));
+ data_ptr, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS));
}
}
}
@@ -2152,7 +2271,8 @@ void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
BIND(&cont);
}
-void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
+void AccessorAssembler::GenericElementLoad(Node* receiver,
+ TNode<Map> receiver_map,
SloppyTNode<Int32T> instance_type,
Node* index, Label* slow) {
Comment("integer index");
@@ -2213,11 +2333,9 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
}
}
-void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
- SloppyTNode<Int32T> instance_type,
- const LoadICParameters* p,
- Label* slow,
- UseStubCache use_stub_cache) {
+void AccessorAssembler::GenericPropertyLoad(
+ Node* receiver, TNode<Map> receiver_map, SloppyTNode<Int32T> instance_type,
+ const LoadICParameters* p, Label* slow, UseStubCache use_stub_cache) {
ExitPoint direct_exit(this);
Comment("key is unique name");
@@ -2317,13 +2435,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
BIND(&lookup_prototype_chain);
{
- VARIABLE(var_holder_map, MachineRepresentation::kTagged);
+ TVARIABLE(Map, var_holder_map);
VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32);
Label return_undefined(this), is_private_symbol(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_map = receiver_map;
var_holder_instance_type.Bind(instance_type);
GotoIf(IsPrivateSymbol(name), &is_private_symbol);
@@ -2338,7 +2456,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
GotoIf(TaggedEqual(proto, NullConstant()), &return_undefined);
TNode<Map> proto_map = LoadMap(proto);
TNode<Uint16T> proto_instance_type = LoadMapInstanceType(proto_map);
- var_holder_map.Bind(proto_map);
+ var_holder_map = 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,
@@ -2394,8 +2512,6 @@ enum AccessorAssembler::StubCacheTable : int {
};
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).
TNode<Uint32T> hash_field = LoadNameHashField(name);
CSA_ASSERT(this,
@@ -2422,7 +2538,7 @@ Node* AccessorAssembler::StubCacheSecondaryOffset(Node* name, Node* seed) {
// Use the seed from the primary cache in the secondary cache.
TNode<Int32T> name32 = TruncateIntPtrToInt32(BitcastTaggedToWord(name));
- TNode<Word32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
+ TNode<Int32T> hash = Int32Sub(TruncateIntPtrToInt32(seed), name32);
hash = Int32Add(hash, Int32Constant(StubCache::kSecondaryMagic));
int32_t mask = (StubCache::kSecondaryTableSize - 1)
<< StubCache::kCacheIndexShift;
@@ -2436,7 +2552,8 @@ void AccessorAssembler::TryProbeStubCacheTable(
StubCache::Table table = static_cast<StubCache::Table>(table_id);
// The {table_offset} holds the entry offset times four (due to masking
// and shifting optimizations).
- const int kMultiplier = sizeof(StubCache::Entry) >> Name::kHashShift;
+ const int kMultiplier =
+ sizeof(StubCache::Entry) >> StubCache::kCacheIndexShift;
entry_offset = IntPtrMul(entry_offset, IntPtrConstant(kMultiplier));
TNode<ExternalReference> key_base = ExternalConstant(
@@ -2527,7 +2644,7 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LazyLoadICParameters* p,
Label try_polymorphic(this), if_handler(this, &var_handler);
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), recv_map, &if_handler,
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), recv_map, &if_handler,
&var_handler, &try_polymorphic);
BIND(&if_handler);
@@ -2589,8 +2706,8 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) {
// Check monomorphic case.
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler,
- &var_handler, &try_polymorphic);
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
+ &if_handler, &var_handler, &try_polymorphic);
BIND(&if_handler);
{
LazyLoadICParameters lazy_p(p);
@@ -2673,21 +2790,25 @@ void AccessorAssembler::LoadIC_NoFeedback(const LoadICParameters* p) {
}
}
-void AccessorAssembler::LoadGlobalIC(Node* vector, Node* slot,
+void AccessorAssembler::LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
+ const LazyNode<Smi>& lazy_smi_slot,
+ const LazyNode<UintPtrT>& lazy_slot,
const LazyNode<Context>& lazy_context,
const LazyNode<Name>& lazy_name,
TypeofMode typeof_mode,
- ExitPoint* exit_point,
- ParameterMode slot_mode) {
+ ExitPoint* exit_point) {
Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred);
- GotoIf(IsUndefined(vector), &miss);
-
- LoadGlobalIC_TryPropertyCellCase(CAST(vector), slot, lazy_context, exit_point,
- &try_handler, &miss, slot_mode);
+ GotoIf(IsUndefined(maybe_feedback_vector), &miss);
+ {
+ TNode<FeedbackVector> vector = CAST(maybe_feedback_vector);
+ TNode<UintPtrT> slot = lazy_slot();
+ LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
+ &try_handler, &miss);
- BIND(&try_handler);
- LoadGlobalIC_TryHandlerCase(CAST(vector), slot, lazy_context, lazy_name,
- typeof_mode, exit_point, &miss, slot_mode);
+ BIND(&try_handler);
+ LoadGlobalIC_TryHandlerCase(vector, slot, lazy_smi_slot, lazy_context,
+ lazy_name, typeof_mode, exit_point, &miss);
+ }
BIND(&miss);
{
@@ -2695,20 +2816,19 @@ void AccessorAssembler::LoadGlobalIC(Node* vector, Node* slot,
TNode<Context> context = lazy_context();
TNode<Name> name = lazy_name();
exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Miss, context, name,
- ParameterToTagged(slot, slot_mode), vector,
+ lazy_smi_slot(), maybe_feedback_vector,
SmiConstant(typeof_mode));
}
}
void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
- TNode<FeedbackVector> vector, Node* slot,
+ TNode<FeedbackVector> vector, TNode<UintPtrT> slot,
const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
- Label* try_handler, Label* miss, ParameterMode slot_mode) {
+ Label* try_handler, Label* miss) {
Comment("LoadGlobalIC_TryPropertyCellCase");
Label if_lexical_var(this), if_property_cell(this);
- TNode<MaybeObject> maybe_weak_ref =
- LoadFeedbackVectorSlot(vector, slot, 0, slot_mode);
+ TNode<MaybeObject> maybe_weak_ref = LoadFeedbackVectorSlot(vector, slot);
Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
BIND(&if_property_cell);
@@ -2739,16 +2859,16 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
}
void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
- TNode<FeedbackVector> vector, Node* slot,
- const LazyNode<Context>& lazy_context, const LazyNode<Name>& lazy_name,
- TypeofMode typeof_mode, ExitPoint* exit_point, Label* miss,
- ParameterMode slot_mode) {
+ TNode<FeedbackVector> vector, TNode<UintPtrT> slot,
+ const LazyNode<Smi>& lazy_smi_slot, const LazyNode<Context>& lazy_context,
+ const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
+ ExitPoint* exit_point, Label* miss) {
Comment("LoadGlobalIC_TryHandlerCase");
Label call_handler(this), non_smi(this);
TNode<MaybeObject> feedback_element =
- LoadFeedbackVectorSlot(vector, slot, kTaggedSize, slot_mode);
+ LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
TNode<Object> handler = CAST(feedback_element);
GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), miss);
@@ -2757,14 +2877,14 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
: OnNonExistent::kReturnUndefined;
TNode<Context> context = lazy_context();
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<JSGlobalProxy> receiver =
CAST(LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX));
TNode<Object> holder =
LoadContextElement(native_context, Context::EXTENSION_INDEX);
LazyLoadICParameters p([=] { return context; }, receiver, lazy_name,
- ParameterToTagged(slot, slot_mode), vector, holder);
+ lazy_smi_slot, vector, holder);
HandleLoadICHandlerCase(&p, handler, miss, exit_point, ICMode::kGlobalIC,
on_nonexistent);
@@ -2788,8 +2908,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
// Check monomorphic case.
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler,
- &var_handler, &try_polymorphic);
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
+ &if_handler, &var_handler, &try_polymorphic);
BIND(&if_handler);
{
LazyLoadICParameters lazy_p(p);
@@ -2840,13 +2960,13 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
// We might have a name in feedback, and a weak fixed array in the next
// slot.
Comment("KeyedLoadIC_try_polymorphic_name");
- TVARIABLE(Object, var_name, p->name());
+ TVARIABLE(Name, var_name);
TVARIABLE(IntPtrT, var_index);
- Label if_polymorphic_name(this, &var_name), if_internalized(this),
- if_notinternalized(this, Label::kDeferred);
+ Label if_polymorphic_name(this), feedback_matches(this),
+ if_internalized(this), if_notinternalized(this, Label::kDeferred);
// Fast-case: The recorded {feedback} matches the {name}.
- GotoIf(TaggedEqual(strong_feedback, p->name()), &if_polymorphic_name);
+ GotoIf(TaggedEqual(strong_feedback, p->name()), &feedback_matches);
// Try to internalize the {name} if it isn't already.
TryToName(p->name(), &miss, &var_index, &if_internalized, &var_name, &miss,
@@ -2861,16 +2981,15 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
BIND(&if_notinternalized);
{
- // Try to internalize the {name}.
- TNode<ExternalReference> function = ExternalConstant(
- ExternalReference::try_internalize_string_function());
- TNode<ExternalReference> const isolate_ptr =
- ExternalConstant(ExternalReference::isolate_address(isolate()));
- var_name = CAST(
- CallCFunction(function, MachineType::AnyTagged(),
- std::make_pair(MachineType::Pointer(), isolate_ptr),
- std::make_pair(MachineType::AnyTagged(), p->name())));
- Goto(&if_internalized);
+ TVARIABLE(IntPtrT, var_index);
+ TryInternalizeString(CAST(p->name()), &miss, &var_index, &if_internalized,
+ &var_name, &miss, &miss);
+ }
+
+ BIND(&feedback_matches);
+ {
+ var_name = CAST(p->name());
+ Goto(&if_polymorphic_name);
}
BIND(&if_polymorphic_name);
@@ -2896,71 +3015,74 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
}
void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
- TVARIABLE(IntPtrT, var_index);
- TVARIABLE(Object, var_unique, p->name());
- Label if_index(this), if_unique_name(this), if_notunique(this),
- if_other(this, Label::kDeferred), if_runtime(this, Label::kDeferred);
+ TVARIABLE(Object, var_name, p->name());
+ Label if_runtime(this, Label::kDeferred);
Node* receiver = p->receiver();
GotoIf(TaggedIsSmi(receiver), &if_runtime);
GotoIf(IsNullOrUndefined(receiver), &if_runtime);
- TryToName(p->name(), &if_index, &var_index, &if_unique_name, &var_unique,
- &if_other, &if_notunique);
-
- BIND(&if_other);
{
- TNode<Name> name =
- CAST(CallBuiltin(Builtins::kToName, p->context(), p->name()));
- var_unique = name;
- TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique,
- &if_runtime, &if_notunique);
- }
+ TVARIABLE(IntPtrT, var_index);
+ TVARIABLE(Name, var_unique);
+ Label if_index(this), if_unique_name(this, &var_name), if_notunique(this),
+ if_other(this, Label::kDeferred);
- BIND(&if_index);
- {
- TNode<Map> receiver_map = LoadMap(receiver);
- TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
- GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
- &if_runtime);
- }
+ TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
+ &var_unique, &if_other, &if_notunique);
- BIND(&if_unique_name);
- {
- LoadICParameters pp(p, var_unique.value());
- TNode<Map> receiver_map = LoadMap(receiver);
- TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
- GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
- &if_runtime);
- }
+ BIND(&if_unique_name);
+ {
+ LoadICParameters pp(p, var_unique.value());
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
+ GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
+ &if_runtime);
+ }
- BIND(&if_notunique);
- {
- if (FLAG_internalize_on_the_fly) {
- // Ideally we could return undefined directly here if the name is not
- // found in the string table, i.e. it was never internalized, but that
- // invariant doesn't hold with named property interceptors (at this
- // point), so we take the {if_runtime} path instead.
- Label if_in_string_table(this);
- TryInternalizeString(var_unique.value(), &if_index, &var_index,
- &if_in_string_table, &var_unique, &if_runtime,
- &if_runtime);
+ BIND(&if_other);
+ {
+ var_name = CallBuiltin(Builtins::kToName, p->context(), var_name.value());
+ TryToName(var_name.value(), &if_index, &var_index, &if_unique_name,
+ &var_unique, &if_runtime, &if_notunique);
+ }
- BIND(&if_in_string_table);
- {
- // TODO(bmeurer): We currently use a version of GenericPropertyLoad
- // here, where we don't try to probe the megamorphic stub cache after
- // successfully internalizing the incoming string. Past experiments
- // with this have shown that it causes too much traffic on the stub
- // cache. We may want to re-evaluate that in the future.
- LoadICParameters pp(p, var_unique.value());
- TNode<Map> receiver_map = LoadMap(receiver);
- TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
- GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
- &if_runtime, kDontUseStubCache);
+ BIND(&if_notunique);
+ {
+ if (FLAG_internalize_on_the_fly) {
+ // Ideally we could return undefined directly here if the name is not
+ // found in the string table, i.e. it was never internalized, but that
+ // invariant doesn't hold with named property interceptors (at this
+ // point), so we take the {if_runtime} path instead.
+ Label if_in_string_table(this);
+ TryInternalizeString(CAST(var_name.value()), &if_index, &var_index,
+ &if_in_string_table, &var_unique, &if_runtime,
+ &if_runtime);
+
+ BIND(&if_in_string_table);
+ {
+ // TODO(bmeurer): We currently use a version of GenericPropertyLoad
+ // here, where we don't try to probe the megamorphic stub cache
+ // after successfully internalizing the incoming string. Past
+ // experiments with this have shown that it causes too much traffic
+ // on the stub cache. We may want to re-evaluate that in the future.
+ LoadICParameters pp(p, var_unique.value());
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
+ GenericPropertyLoad(receiver, receiver_map, instance_type, &pp,
+ &if_runtime, kDontUseStubCache);
+ }
+ } else {
+ Goto(&if_runtime);
}
- } else {
- Goto(&if_runtime);
+ }
+
+ BIND(&if_index);
+ {
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
+ GenericElementLoad(receiver, receiver_map, instance_type,
+ var_index.value(), &if_runtime);
}
}
@@ -2970,7 +3092,7 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
// TODO(jkummerow): Should we use the GetProperty TF stub instead?
TailCallRuntime(Runtime::kGetProperty, p->context(), p->receiver(),
- var_unique.value());
+ var_name.value());
}
}
@@ -2982,22 +3104,20 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p,
Node* receiver = p->receiver();
TNode<Map> receiver_map = LoadReceiverMap(receiver);
TNode<Name> name = CAST(p->name());
- Node* vector = p->vector();
- Node* slot = p->slot();
+ TNode<FeedbackVector> vector = CAST(p->vector());
+ TNode<Smi> slot = p->slot();
TNode<Context> context = p->context();
// When we get here, we know that the {name} matches the recorded
// feedback name in the {vector} and can safely be used for the
// LoadIC handler logic below.
CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
- CSA_ASSERT(this,
- TaggedEqual(
- name, LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS)),
+ CSA_ASSERT(this, TaggedEqual(name, LoadFeedbackVectorSlot(vector, slot)),
name, vector);
// Check if we have a matching handler for the {receiver_map}.
TNode<MaybeObject> feedback_element =
- LoadFeedbackVectorSlot(vector, slot, kTaggedSize, SMI_PARAMETERS);
+ LoadFeedbackVectorSlot(vector, slot, kTaggedSize);
TNode<WeakFixedArray> array = CAST(feedback_element);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss);
@@ -3038,8 +3158,8 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
// Check monomorphic case.
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler,
- &var_handler, &try_polymorphic);
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
+ &if_handler, &var_handler, &try_polymorphic);
BIND(&if_handler);
{
Comment("StoreIC_if_handler");
@@ -3082,17 +3202,12 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
Label if_lexical_var(this), if_heapobject(this);
TNode<MaybeObject> maybe_weak_ref =
- LoadFeedbackVectorSlot(pp->vector(), pp->slot(), 0, SMI_PARAMETERS);
+ LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot());
Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_heapobject);
BIND(&if_heapobject);
{
Label try_handler(this), miss(this, Label::kDeferred);
- // We use pre-monomorphic state for global stores that run into
- // interceptors because the property doesn't exist yet. Using
- // pre-monomorphic state gives it a chance to find more information the
- // second time.
- GotoIf(TaggedEqual(maybe_weak_ref, PremonomorphicSymbolConstant()), &miss);
CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
TNode<PropertyCell> property_cell =
@@ -3105,13 +3220,13 @@ void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
BIND(&try_handler);
{
Comment("StoreGlobalIC_try_handler");
- TNode<MaybeObject> handler = LoadFeedbackVectorSlot(
- pp->vector(), pp->slot(), kTaggedSize, SMI_PARAMETERS);
+ TNode<MaybeObject> handler =
+ LoadFeedbackVectorSlot(CAST(pp->vector()), pp->slot(), kTaggedSize);
GotoIf(TaggedEqual(handler, UninitializedSymbolConstant()), &miss);
DCHECK_NULL(pp->receiver());
- TNode<Context> native_context = LoadNativeContext(pp->context());
+ TNode<NativeContext> native_context = LoadNativeContext(pp->context());
StoreICParameters p(
pp->context(),
LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX),
@@ -3225,8 +3340,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
// Check monomorphic case.
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), receiver_map, &if_handler,
- &var_handler, &try_polymorphic);
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), receiver_map,
+ &if_handler, &var_handler, &try_polymorphic);
BIND(&if_handler);
{
Comment("KeyedStoreIC_if_handler");
@@ -3266,8 +3381,8 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
GotoIfNot(TaggedEqual(strong_feedback, p->name()), &miss);
// If the name comparison succeeded, we know we have a feedback vector
// with at least one map/handler pair.
- TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(
- p->vector(), p->slot(), kTaggedSize, SMI_PARAMETERS);
+ TNode<MaybeObject> feedback_element =
+ LoadFeedbackVectorSlot(CAST(p->vector()), p->slot(), kTaggedSize);
TNode<WeakFixedArray> array = CAST(feedback_element);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
&miss);
@@ -3296,16 +3411,20 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
GotoIf(IsUndefined(p->vector()), &miss);
TNode<MaybeObject> feedback =
- TryMonomorphicCase(p->slot(), p->vector(), array_map, &if_handler,
+ TryMonomorphicCase(p->slot(), CAST(p->vector()), array_map, &if_handler,
&var_handler, &try_polymorphic);
BIND(&if_handler);
{
Comment("StoreInArrayLiteralIC_if_handler");
// This is a stripped-down version of HandleStoreICHandlerCase.
+ Label if_transitioning_element_store(this), if_smi_handler(this);
+
+ // Check used to identify the Slow case.
+ // Currently only the Slow case uses a Smi handler.
+ GotoIf(TaggedIsSmi(var_handler.value()), &if_smi_handler);
TNode<HeapObject> handler = CAST(var_handler.value());
- Label if_transitioning_element_store(this);
GotoIfNot(IsCode(handler), &if_transitioning_element_store);
TailCallStub(StoreWithVectorDescriptor{}, CAST(handler), p->context(),
p->receiver(), p->name(), p->value(), p->slot(),
@@ -3324,6 +3443,22 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
p->receiver(), p->name(), transition_map, p->value(),
p->slot(), p->vector());
}
+
+ BIND(&if_smi_handler);
+ {
+#ifdef DEBUG
+ // A check to ensure that no other Smi handler uses this path.
+ TNode<Int32T> handler_word = SmiToInt32(CAST(var_handler.value()));
+ TNode<Uint32T> handler_kind =
+ DecodeWord32<StoreHandler::KindBits>(handler_word);
+ CSA_ASSERT(this, Word32Equal(handler_kind,
+ Int32Constant(StoreHandler::kSlow)));
+#endif
+
+ Comment("StoreInArrayLiteralIC_Slow");
+ TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, p->context(),
+ p->value(), p->receiver(), p->name());
+ }
}
BIND(&try_polymorphic);
@@ -3366,7 +3501,7 @@ void AccessorAssembler::GenerateLoadIC() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3379,7 +3514,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3392,7 +3527,7 @@ void AccessorAssembler::GenerateLoadIC_Megamorphic() {
BIND(&if_handler);
LazyLoadICParameters p([=] { return context; }, receiver,
- [=] { return name; }, slot, vector);
+ [=] { return name; }, [=] { return slot; }, vector);
HandleLoadICHandlerCase(&p, CAST(var_handler.value()), &miss, &direct_exit);
BIND(&miss);
@@ -3405,8 +3540,8 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
- Node* vector = Parameter(Descriptor::kVector);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
+ TNode<FeedbackVector> vector = CAST(Parameter(Descriptor::kVector));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
ExitPoint direct_exit(this);
@@ -3414,8 +3549,7 @@ void AccessorAssembler::GenerateLoadIC_Noninlined() {
Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
TNode<Map> receiver_map = LoadReceiverMap(receiver);
- TNode<MaybeObject> feedback_element =
- LoadFeedbackVectorSlot(vector, slot, 0, SMI_PARAMETERS);
+ TNode<MaybeObject> feedback_element = LoadFeedbackVectorSlot(vector, slot);
TNode<HeapObject> feedback = CAST(feedback_element);
LoadICParameters p(context, receiver, name, slot, vector);
@@ -3439,7 +3573,7 @@ void AccessorAssembler::GenerateLoadIC_NoFeedback() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
LoadICParameters p(context, receiver, name, slot, UndefinedConstant());
@@ -3475,13 +3609,17 @@ void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
using Descriptor = LoadGlobalWithVectorDescriptor;
TNode<Name> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
- Node* vector = Parameter(Descriptor::kVector);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
+ TNode<HeapObject> vector = CAST(Parameter(Descriptor::kVector));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
ExitPoint direct_exit(this);
LoadGlobalIC(
- vector, slot,
+ vector,
+ // lazy_smi_slot
+ [=] { return slot; },
+ // lazy_slot
+ [=] { return Unsigned(SmiUntag(slot)); },
// lazy_context
[=] { return context; },
// lazy_name
@@ -3506,7 +3644,7 @@ void AccessorAssembler::GenerateKeyedLoadIC() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3519,7 +3657,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3532,7 +3670,7 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
@@ -3545,7 +3683,7 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline_Megamorphic() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
@@ -3558,7 +3696,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3571,7 +3709,7 @@ void AccessorAssembler::GenerateStoreGlobalIC() {
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3584,7 +3722,7 @@ void AccessorAssembler::GenerateStoreGlobalICTrampoline() {
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
@@ -3597,7 +3735,7 @@ void AccessorAssembler::GenerateStoreIC() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3611,7 +3749,7 @@ void AccessorAssembler::GenerateStoreICTrampoline() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
@@ -3625,7 +3763,7 @@ void AccessorAssembler::GenerateKeyedStoreIC() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3639,7 +3777,7 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TNode<FeedbackVector> vector = LoadFeedbackVectorForStub();
@@ -3653,7 +3791,7 @@ void AccessorAssembler::GenerateStoreInArrayLiteralIC() {
Node* array = Parameter(Descriptor::kReceiver);
TNode<Object> index = CAST(Parameter(Descriptor::kName));
Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3671,7 +3809,7 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() {
// can be tail called from it. However, the feedback slot and vector are not
// used.
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TNode<JSFunction> object_fn =
CAST(LoadContextElement(native_context, Context::OBJECT_FUNCTION_INDEX));
TNode<Map> initial_map = CAST(
@@ -3724,7 +3862,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
TNode<Object> source = CAST(Parameter(Descriptor::kSource));
TNode<Smi> flags = CAST(Parameter(Descriptor::kFlags));
TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
- TNode<HeapObject> vector = CAST(Parameter(Descriptor::kVector));
+ TNode<HeapObject> maybe_vector = CAST(Parameter(Descriptor::kVector));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), miss(this, Label::kDeferred),
@@ -3734,10 +3872,11 @@ void AccessorAssembler::GenerateCloneObjectIC() {
TNode<Map> source_map = LoadReceiverMap(source);
GotoIf(IsDeprecatedMap(source_map), &miss);
- GotoIf(IsUndefined(vector), &slow);
+ GotoIf(IsUndefined(maybe_vector), &slow);
- TNode<MaybeObject> feedback = TryMonomorphicCase(
- slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
+ TNode<MaybeObject> feedback =
+ TryMonomorphicCase(slot, CAST(maybe_vector), source_map, &if_handler,
+ &var_handler, &try_polymorphic);
BIND(&if_handler);
{
@@ -3801,30 +3940,28 @@ void AccessorAssembler::GenerateCloneObjectIC() {
// Just copy the fields as raw data (pretending that there are no mutable
// HeapNumbers). This doesn't need write barriers.
- BuildFastLoop(
+ BuildFastLoop<IntPtrT>(
source_start, source_size,
- [=](Node* field_index) {
- TNode<IntPtrT> field_offset =
- TimesTaggedSize(UncheckedCast<IntPtrT>(field_index));
+ [=](TNode<IntPtrT> field_index) {
+ TNode<IntPtrT> field_offset = TimesTaggedSize(field_index);
TNode<TaggedT> field =
LoadObjectField<TaggedT>(CAST(source), field_offset);
TNode<IntPtrT> result_offset =
IntPtrAdd(field_offset, field_offset_difference);
StoreObjectFieldNoWriteBarrier(object, result_offset, field);
},
- 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
+ 1, IndexAdvanceMode::kPost);
// If mutable HeapNumbers can occur, we need to go through the {object}
// again here and properly clone them. We use a second loop here to
// ensure that the GC (and heap verifier) always sees properly initialized
// objects, i.e. never hits undefined values in double fields.
if (!FLAG_unbox_double_fields) {
- BuildFastLoop(
+ BuildFastLoop<IntPtrT>(
source_start, source_size,
- [=](Node* field_index) {
- TNode<IntPtrT> result_offset =
- IntPtrAdd(TimesTaggedSize(UncheckedCast<IntPtrT>(field_index)),
- field_offset_difference);
+ [=](TNode<IntPtrT> field_index) {
+ TNode<IntPtrT> result_offset = IntPtrAdd(
+ TimesTaggedSize(field_index), field_offset_difference);
TNode<Object> field = LoadObjectField(object, result_offset);
Label if_done(this), if_mutableheapnumber(this, Label::kDeferred);
GotoIf(TaggedIsSmi(field), &if_done);
@@ -3838,7 +3975,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
}
BIND(&if_done);
},
- 1, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
+ 1, IndexAdvanceMode::kPost);
}
Return(object);
@@ -3867,14 +4004,15 @@ void AccessorAssembler::GenerateCloneObjectIC() {
BIND(&slow);
{
TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot,
- vector);
+ maybe_vector);
}
BIND(&miss);
{
Comment("CloneObjectIC_miss");
- TNode<HeapObject> map_or_result = CAST(CallRuntime(
- Runtime::kCloneObjectIC_Miss, context, source, flags, slot, vector));
+ TNode<HeapObject> map_or_result =
+ CAST(CallRuntime(Runtime::kCloneObjectIC_Miss, context, source, flags,
+ slot, maybe_vector));
var_handler = UncheckedCast<MaybeObject>(map_or_result);
GotoIf(IsMap(map_or_result), &if_handler);
CSA_ASSERT(this, IsJSObject(map_or_result));
@@ -3887,7 +4025,7 @@ void AccessorAssembler::GenerateKeyedHasIC() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3911,7 +4049,7 @@ void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() {
Node* receiver = Parameter(Descriptor::kReceiver);
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* slot = Parameter(Descriptor::kSlot);
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
Node* vector = Parameter(Descriptor::kVector);
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
@@ -3919,5 +4057,54 @@ void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() {
KeyedLoadICPolymorphicName(&p, LoadAccessMode::kHas);
}
+void AccessorAssembler::BranchIfPrototypesHaveNoElements(
+ TNode<Map> receiver_map, Label* definitely_no_elements,
+ Label* possibly_elements) {
+ TVARIABLE(Map, var_map, receiver_map);
+ Label loop_body(this, &var_map);
+ TNode<FixedArray> empty_fixed_array = EmptyFixedArrayConstant();
+ TNode<NumberDictionary> empty_slow_element_dictionary =
+ EmptySlowElementDictionaryConstant();
+ Goto(&loop_body);
+
+ BIND(&loop_body);
+ {
+ TNode<Map> map = var_map.value();
+ TNode<HeapObject> prototype = LoadMapPrototype(map);
+ GotoIf(IsNull(prototype), definitely_no_elements);
+ TNode<Map> prototype_map = LoadMap(prototype);
+ TNode<Uint16T> prototype_instance_type = LoadMapInstanceType(prototype_map);
+
+ // Pessimistically assume elements if a Proxy, Special API Object,
+ // or JSPrimitiveWrapper wrapper is found on the prototype chain. After this
+ // instance type check, it's not necessary to check for interceptors or
+ // access checks.
+ Label if_custom(this, Label::kDeferred), if_notcustom(this);
+ Branch(IsCustomElementsReceiverInstanceType(prototype_instance_type),
+ &if_custom, &if_notcustom);
+
+ BIND(&if_custom);
+ {
+ // For string JSPrimitiveWrapper wrappers we still support the checks as
+ // long as they wrap the empty string.
+ GotoIfNot(
+ InstanceTypeEqual(prototype_instance_type, JS_PRIMITIVE_WRAPPER_TYPE),
+ possibly_elements);
+ TNode<Object> prototype_value =
+ LoadJSPrimitiveWrapperValue(CAST(prototype));
+ Branch(IsEmptyString(prototype_value), &if_notcustom, possibly_elements);
+ }
+
+ BIND(&if_notcustom);
+ {
+ TNode<FixedArrayBase> prototype_elements = LoadElements(CAST(prototype));
+ var_map = prototype_map;
+ GotoIf(TaggedEqual(prototype_elements, empty_fixed_array), &loop_body);
+ Branch(TaggedEqual(prototype_elements, empty_slow_element_dictionary),
+ &loop_body, possibly_elements);
+ }
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h
index 0de2292fd6..ccc2de9323 100644
--- a/deps/v8/src/ic/accessor-assembler.h
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -5,6 +5,7 @@
#ifndef V8_IC_ACCESSOR_ASSEMBLER_H_
#define V8_IC_ACCESSOR_ASSEMBLER_H_
+#include "src/base/optional.h"
#include "src/codegen/code-stub-assembler.h"
namespace v8 {
@@ -19,10 +20,6 @@ class ExitPoint;
class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
public:
using Node = compiler::Node;
- template <class T>
- using TNode = compiler::TNode<T>;
- template <class T>
- using SloppyTNode = compiler::SloppyTNode<T>;
explicit AccessorAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
@@ -69,7 +66,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
struct LoadICParameters {
LoadICParameters(TNode<Context> context, Node* receiver, TNode<Object> name,
- Node* slot, Node* vector, Node* holder = nullptr)
+ TNode<Smi> slot, Node* vector, Node* holder = nullptr)
: context_(context),
receiver_(receiver),
name_(name),
@@ -88,7 +85,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<Context> context() const { return context_; }
Node* receiver() const { return receiver_; }
TNode<Object> name() const { return name_; }
- Node* slot() const { return slot_; }
+ TNode<Smi> slot() const { return slot_; }
Node* vector() const { return vector_; }
Node* holder() const { return holder_; }
@@ -96,15 +93,15 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<Context> context_;
Node* receiver_;
TNode<Object> name_;
- Node* slot_;
+ TNode<Smi> slot_;
Node* vector_;
Node* holder_;
};
struct LazyLoadICParameters {
LazyLoadICParameters(LazyNode<Context> context, Node* receiver,
- LazyNode<Object> name, Node* slot, Node* vector,
- Node* holder = nullptr)
+ LazyNode<Object> name, LazyNode<Smi> slot,
+ Node* vector, Node* holder = nullptr)
: context_(context),
receiver_(receiver),
name_(name),
@@ -114,19 +111,17 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
explicit LazyLoadICParameters(const LoadICParameters* p)
: receiver_(p->receiver()),
- slot_(p->slot()),
vector_(p->vector()),
holder_(p->holder()) {
- TNode<Context> p_context = p->context();
- context_ = [=] { return p_context; };
- TNode<Object> p_name = p->name();
- name_ = [=] { return p_name; };
+ slot_ = [=] { return p->slot(); };
+ context_ = [=] { return p->context(); };
+ name_ = [=] { return p->name(); };
}
TNode<Context> context() const { return context_(); }
Node* receiver() const { return receiver_; }
TNode<Object> name() const { return name_(); }
- Node* slot() const { return slot_; }
+ TNode<Smi> slot() const { return slot_(); }
Node* vector() const { return vector_; }
Node* holder() const { return holder_; }
@@ -134,16 +129,17 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
LazyNode<Context> context_;
Node* receiver_;
LazyNode<Object> name_;
- Node* slot_;
+ LazyNode<Smi> slot_;
Node* vector_;
Node* holder_;
};
- void LoadGlobalIC(Node* vector, Node* slot,
+ void LoadGlobalIC(TNode<HeapObject> maybe_feedback_vector,
+ const LazyNode<Smi>& lazy_smi_slot,
+ const LazyNode<UintPtrT>& lazy_slot,
const LazyNode<Context>& lazy_context,
const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
- ExitPoint* exit_point,
- ParameterMode slot_mode = SMI_PARAMETERS);
+ ExitPoint* exit_point);
// Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
// construction on common paths.
@@ -157,8 +153,8 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
protected:
struct StoreICParameters : public LoadICParameters {
StoreICParameters(TNode<Context> context, Node* receiver,
- TNode<Object> name, SloppyTNode<Object> value, Node* slot,
- Node* vector)
+ TNode<Object> name, SloppyTNode<Object> value,
+ TNode<Smi> slot, Node* vector)
: LoadICParameters(context, receiver, name, slot, vector),
value_(value) {}
@@ -185,20 +181,22 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
Label* miss,
StoreTransitionMapFlags flags);
- void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
+ void JumpIfDataProperty(TNode<Uint32T> details, Label* writable,
+ Label* readonly);
void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield3 = nullptr);
- void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
- Node* descriptors,
- Node* descriptor_name_index,
- Node* details, TNode<Object> value,
- Label* slow,
+ void OverwriteExistingFastDataProperty(SloppyTNode<HeapObject> object,
+ TNode<Map> object_map,
+ TNode<DescriptorArray> descriptors,
+ TNode<IntPtrT> descriptor_name_index,
+ TNode<Uint32T> details,
+ TNode<Object> value, Label* slow,
bool do_transitioning_store);
- void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
- TNode<Word32T> representation, Node* value,
- Label* bailout);
+ void CheckFieldType(TNode<DescriptorArray> descriptors,
+ TNode<IntPtrT> name_index, TNode<Word32T> representation,
+ Node* value, Label* bailout);
private:
// Stub generation entry points.
@@ -232,12 +230,11 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
// IC dispatcher behavior.
// Checks monomorphic case. Returns {feedback} entry of the vector.
- TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector,
- Node* receiver_map, Label* if_handler,
- TVariable<MaybeObject>* var_handler,
- Label* if_miss);
- void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
- Label* if_handler,
+ TNode<MaybeObject> TryMonomorphicCase(
+ TNode<Smi> slot, TNode<FeedbackVector> vector, TNode<Map> receiver_map,
+ Label* if_handler, TVariable<MaybeObject>* var_handler, Label* if_miss);
+ void HandlePolymorphicCase(TNode<Map> receiver_map,
+ TNode<WeakFixedArray> feedback, Label* if_handler,
TVariable<MaybeObject>* var_handler,
Label* if_miss);
@@ -249,15 +246,14 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
ElementSupport support_elements = kOnlyProperties,
LoadAccessMode access_mode = LoadAccessMode::kLoad);
- void HandleLoadICSmiHandlerCase(const LazyLoadICParameters* p, Node* holder,
- SloppyTNode<Smi> smi_handler,
- SloppyTNode<Object> handler, Label* miss,
- ExitPoint* exit_point,
- OnNonExistent on_nonexistent,
- ElementSupport support_elements,
- LoadAccessMode access_mode);
+ void HandleLoadICSmiHandlerCase(
+ const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder,
+ SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss,
+ ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
+ ElementSupport support_elements, LoadAccessMode access_mode);
- void HandleLoadICProtoHandler(const LazyLoadICParameters* p, Node* handler,
+ void HandleLoadICProtoHandler(const LazyLoadICParameters* p,
+ TNode<DataHandler> handler,
Variable* var_holder, Variable* var_smi_handler,
Label* if_smi_handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode,
@@ -273,40 +269,43 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<WordT> handler_word, TNode<DataHandler> handler,
TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
- void HandleLoadField(Node* holder, Node* handler_word,
+ void HandleLoadField(SloppyTNode<JSObject> holder, TNode<WordT> handler_word,
Variable* var_double_value, Label* rebox_double,
- ExitPoint* exit_point);
+ Label* miss, ExitPoint* exit_point);
void EmitAccessCheck(TNode<Context> expected_native_context,
- TNode<Context> context, Node* receiver,
+ TNode<Context> context, TNode<Object> receiver,
Label* can_access, Label* miss);
void HandleLoadICSmiHandlerLoadNamedCase(
- const LazyLoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
- TNode<WordT> handler_word, Label* rebox_double,
- Variable* var_double_value, SloppyTNode<Object> handler, Label* miss,
- ExitPoint* exit_point, OnNonExistent on_nonexistent,
+ const LazyLoadICParameters* p, TNode<HeapObject> holder,
+ TNode<IntPtrT> handler_kind, TNode<WordT> handler_word,
+ Label* rebox_double, Variable* var_double_value,
+ SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
+ ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements);
void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p,
- Node* holder,
+ TNode<HeapObject> holder,
TNode<IntPtrT> handler_kind,
- Label* miss, ExitPoint* exit_point);
+ Label* miss, ExitPoint* exit_point,
+ ICMode ic_mode);
// LoadGlobalIC implementation.
- void LoadGlobalIC_TryPropertyCellCase(
- TNode<FeedbackVector> vector, Node* slot,
- const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
- Label* try_handler, Label* miss,
- ParameterMode slot_mode = SMI_PARAMETERS);
+ void LoadGlobalIC_TryPropertyCellCase(TNode<FeedbackVector> vector,
+ TNode<UintPtrT> slot,
+ const LazyNode<Context>& lazy_context,
+ ExitPoint* exit_point,
+ Label* try_handler, Label* miss);
- void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot,
+ void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector,
+ TNode<UintPtrT> slot,
+ const LazyNode<Smi>& lazy_smi_slot,
const LazyNode<Context>& lazy_context,
const LazyNode<Name>& lazy_name,
TypeofMode typeof_mode,
- ExitPoint* exit_point, Label* miss,
- ParameterMode slot_mode);
+ ExitPoint* exit_point, Label* miss);
// StoreIC implementation.
@@ -314,59 +313,66 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<StoreHandler> handler, Label* miss,
ICMode ic_mode,
ElementSupport support_elements);
- void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
- Node* value, Label* miss);
- void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
- Representation representation, Node* value,
- Label* miss);
+ void HandleStoreICSmiHandlerCase(SloppyTNode<Word32T> handler_word,
+ SloppyTNode<JSObject> holder,
+ SloppyTNode<Object> value, Label* miss);
+ void HandleStoreFieldAndReturn(TNode<Word32T> handler_word,
+ TNode<JSObject> holder, TNode<Object> value,
+ base::Optional<TNode<Float64T>> double_value,
+ Representation representation, Label* miss);
void CheckPrototypeValidityCell(TNode<Object> maybe_validity_cell,
Label* miss);
- void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
- Node* handler_word);
+ void HandleStoreICNativeDataProperty(const StoreICParameters* p,
+ SloppyTNode<HeapObject> holder,
+ TNode<Word32T> handler_word);
void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
ElementSupport support_elements);
- void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
- Node* handler_word);
+ void HandleStoreAccessor(const StoreICParameters* p,
+ SloppyTNode<HeapObject> holder,
+ TNode<Word32T> handler_word);
// KeyedLoadIC_Generic implementation.
- void GenericElementLoad(Node* receiver, Node* receiver_map,
+ void GenericElementLoad(Node* receiver, TNode<Map> receiver_map,
SloppyTNode<Int32T> instance_type, Node* index,
Label* slow);
enum UseStubCache { kUseStubCache, kDontUseStubCache };
- void GenericPropertyLoad(Node* receiver, Node* receiver_map,
+ void GenericPropertyLoad(Node* receiver, TNode<Map> receiver_map,
SloppyTNode<Int32T> instance_type,
const LoadICParameters* p, Label* slow,
UseStubCache use_stub_cache = kUseStubCache);
// Low-level helpers.
- using OnCodeHandler = std::function<void(Node* code_handler)>;
- using OnFoundOnReceiver =
- std::function<void(Node* properties, Node* name_index)>;
+ using OnCodeHandler = std::function<void(TNode<Code> code_handler)>;
+ using OnFoundOnReceiver = std::function<void(TNode<NameDictionary> properties,
+ TNode<IntPtrT> name_index)>;
template <typename ICHandler, typename ICParameters>
- Node* HandleProtoHandler(const ICParameters* p, Node* handler,
- const OnCodeHandler& on_code_handler,
- const OnFoundOnReceiver& on_found_on_receiver,
- Label* miss, ICMode ic_mode);
-
- Node* PrepareValueForStore(Node* handler_word, Node* holder,
- Representation representation, Node* value,
- Label* bailout);
+ TNode<Object> HandleProtoHandler(
+ const ICParameters* p, TNode<DataHandler> handler,
+ const OnCodeHandler& on_code_handler,
+ const OnFoundOnReceiver& on_found_on_receiver, Label* miss,
+ ICMode ic_mode);
+
+ void CheckHeapObjectTypeMatchesDescriptor(TNode<Word32T> handler_word,
+ TNode<JSObject> holder,
+ TNode<Object> value,
+ Label* bailout);
+ // Double fields store double values in a mutable box, where stores are
+ // writes into this box rather than HeapNumber assignment.
+ void CheckDescriptorConsidersNumbersMutable(TNode<Word32T> handler_word,
+ TNode<JSObject> holder,
+ Label* bailout);
// Extends properties backing store by JSObject::kFieldsAdded elements,
// returns updated properties backing store.
Node* ExtendPropertiesBackingStore(Node* object, Node* index);
- void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
- Representation representation, Node* value,
- Label* bailout);
-
void EmitFastElementsBoundsCheck(Node* object, Node* elements,
Node* intptr_index,
Node* is_jsarray_condition, Label* miss);
@@ -379,7 +385,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
LoadAccessMode access_mode = LoadAccessMode::kLoad);
void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
Label* miss);
- TNode<BoolT> IsPropertyDetailsConst(Node* details);
+ TNode<BoolT> IsPropertyDetailsConst(TNode<Uint32T> details);
// Stub cache access helpers.
@@ -395,6 +401,10 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<Map> map, Label* if_handler,
TVariable<MaybeObject>* var_handler,
Label* if_miss);
+
+ void BranchIfPrototypesHaveNoElements(TNode<Map> receiver_map,
+ Label* definitely_no_elements,
+ Label* possibly_elements);
};
// Abstraction over direct and indirect exit points. Direct exits correspond to
diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc
index f6bec6eab9..ee488100e9 100644
--- a/deps/v8/src/ic/binary-op-assembler.cc
+++ b/deps/v8/src/ic/binary-op-assembler.cc
@@ -9,21 +9,19 @@
namespace v8 {
namespace internal {
-using compiler::Node;
-
-Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
- Node* rhs, Node* slot_id,
- Node* feedback_vector,
- bool rhs_is_smi) {
+TNode<Object> BinaryOpAssembler::Generate_AddWithFeedback(
+ TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
// Shared entry for floating point addition.
Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
check_rhsisoddball(this, Label::kDeferred),
call_with_oddball_feedback(this), call_with_any_feedback(this),
call_add_stub(this), end(this), bigint(this, Label::kDeferred);
- VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64);
- VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64);
- VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
- VARIABLE(var_result, MachineRepresentation::kTagged);
+ TVARIABLE(Float64T, var_fadd_lhs);
+ TVARIABLE(Float64T, var_fadd_rhs);
+ TVARIABLE(Smi, var_type_feedback);
+ TVARIABLE(Object, var_result);
// Check if the {lhs} is a Smi or a HeapObject.
Label if_lhsissmi(this);
@@ -32,13 +30,14 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
// both Smi and Number operations, so this path should not be marked as
// Deferred.
Label if_lhsisnotsmi(this,
- rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
+ rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
BIND(&if_lhsissmi);
{
Comment("lhs is Smi");
- if (!rhs_is_smi) {
+ TNode<Smi> lhs_smi = CAST(lhs);
+ if (!rhs_known_smi) {
// Check if the {rhs} is also a Smi.
Label if_rhsissmi(this), if_rhsisnotsmi(this);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
@@ -46,10 +45,11 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&if_rhsisnotsmi);
{
// Check if the {rhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
+ TNode<HeapObject> rhs_heap_object = CAST(rhs);
+ GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
- var_fadd_lhs.Bind(SmiToFloat64(lhs));
- var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
+ var_fadd_lhs = SmiToFloat64(lhs_smi);
+ var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
Goto(&do_fadd);
}
@@ -62,21 +62,21 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
// is for AddSmi operation. For the normal Add operation, we want to fast
// path both Smi and Number operations, so this path should not be marked
// as Deferred.
+ TNode<Smi> rhs_smi = CAST(rhs);
Label if_overflow(this,
- rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
- TNode<Smi> smi_result = TrySmiAdd(CAST(lhs), CAST(rhs), &if_overflow);
+ rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
+ TNode<Smi> smi_result = TrySmiAdd(lhs_smi, rhs_smi, &if_overflow);
// Not overflowed.
{
- var_type_feedback.Bind(
- SmiConstant(BinaryOperationFeedback::kSignedSmall));
- var_result.Bind(smi_result);
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
+ var_result = smi_result;
Goto(&end);
}
BIND(&if_overflow);
{
- var_fadd_lhs.Bind(SmiToFloat64(lhs));
- var_fadd_rhs.Bind(SmiToFloat64(rhs));
+ var_fadd_lhs = SmiToFloat64(lhs_smi);
+ var_fadd_rhs = SmiToFloat64(rhs_smi);
Goto(&do_fadd);
}
}
@@ -85,9 +85,10 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&if_lhsisnotsmi);
{
// Check if {lhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber);
+ TNode<HeapObject> lhs_heap_object = CAST(lhs);
+ GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
- if (!rhs_is_smi) {
+ if (!rhs_known_smi) {
// Check if the {rhs} is Smi.
Label if_rhsissmi(this), if_rhsisnotsmi(this);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
@@ -95,29 +96,30 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
BIND(&if_rhsisnotsmi);
{
// Check if the {rhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
+ TNode<HeapObject> rhs_heap_object = CAST(rhs);
+ GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
- var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
- var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
+ var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
+ var_fadd_rhs = LoadHeapNumberValue(rhs_heap_object);
Goto(&do_fadd);
}
BIND(&if_rhsissmi);
}
{
- var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
- var_fadd_rhs.Bind(SmiToFloat64(rhs));
+ var_fadd_lhs = LoadHeapNumberValue(lhs_heap_object);
+ var_fadd_rhs = SmiToFloat64(CAST(rhs));
Goto(&do_fadd);
}
}
BIND(&do_fadd);
{
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
TNode<Float64T> value =
Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
TNode<HeapNumber> result = AllocateHeapNumberWithValue(value);
- var_result.Bind(result);
+ var_result = result;
Goto(&end);
}
@@ -125,7 +127,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
{
// No checks on rhs are done yet. We just know lhs is not a number or Smi.
Label if_lhsisoddball(this), if_lhsisnotoddball(this);
- TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
TNode<BoolT> lhs_is_oddball =
InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
@@ -135,39 +137,40 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
// Check if {rhs} is a HeapNumber.
- Branch(IsHeapNumber(rhs), &call_with_oddball_feedback,
+ Branch(IsHeapNumber(CAST(rhs)), &call_with_oddball_feedback,
&check_rhsisoddball);
}
BIND(&if_lhsisnotoddball);
{
+ // Check if the {rhs} is a smi, and exit the string and bigint check early
+ // if it is.
+ GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
+ TNode<HeapObject> rhs_heap_object = CAST(rhs);
+
Label lhs_is_string(this), lhs_is_bigint(this);
GotoIf(IsStringInstanceType(lhs_instance_type), &lhs_is_string);
GotoIf(IsBigIntInstanceType(lhs_instance_type), &lhs_is_bigint);
Goto(&call_with_any_feedback);
BIND(&lhs_is_bigint);
- {
- GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
- Branch(IsBigInt(rhs), &bigint, &call_with_any_feedback);
- }
+ Branch(IsBigInt(rhs_heap_object), &bigint, &call_with_any_feedback);
BIND(&lhs_is_string);
- // Check if the {rhs} is a smi, and exit the string check early if it is.
- GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
-
- TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
+ {
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs_heap_object);
- // Exit unless {rhs} is a string. Since {lhs} is a string we no longer
- // need an Oddball check.
- GotoIfNot(IsStringInstanceType(rhs_instance_type),
- &call_with_any_feedback);
+ // Exit unless {rhs} is a string. Since {lhs} is a string we no longer
+ // need an Oddball check.
+ GotoIfNot(IsStringInstanceType(rhs_instance_type),
+ &call_with_any_feedback);
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString));
- var_result.Bind(
- CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kString);
+ var_result =
+ CallBuiltin(Builtins::kStringAdd_CheckNone, context, lhs, rhs);
- Goto(&end);
+ Goto(&end);
+ }
}
}
@@ -175,7 +178,7 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
{
// Check if rhs is an oddball. At this point we know lhs is either a
// Smi or number or oddball and rhs is not a number or Smi.
- TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
TNode<BoolT> rhs_is_oddball =
InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
GotoIf(rhs_is_oddball, &call_with_oddball_feedback);
@@ -186,59 +189,58 @@ Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
{
// Both {lhs} and {rhs} are of BigInt type.
Label bigint_too_big(this);
- var_result.Bind(
- CallBuiltin(Builtins::kBigIntAddNoThrow, context, lhs, rhs));
+ var_result = CallBuiltin(Builtins::kBigIntAddNoThrow, context, lhs, rhs);
// Check for sentinel that signals BigIntTooBig exception.
GotoIf(TaggedIsSmi(var_result.value()), &bigint_too_big);
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt);
Goto(&end);
BIND(&bigint_too_big);
{
// Update feedback to prevent deopt loop.
UpdateFeedback(SmiConstant(BinaryOperationFeedback::kAny),
- feedback_vector, slot_id);
+ maybe_feedback_vector, slot_id);
ThrowRangeError(context, MessageTemplate::kBigIntTooBig);
}
}
BIND(&call_with_oddball_feedback);
{
- var_type_feedback.Bind(
- SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
Goto(&call_add_stub);
}
BIND(&call_with_any_feedback);
{
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
Goto(&call_add_stub);
}
BIND(&call_add_stub);
{
- var_result.Bind(CallBuiltin(Builtins::kAdd, context, lhs, rhs));
+ var_result = CallBuiltin(Builtins::kAdd, context, lhs, rhs);
Goto(&end);
}
BIND(&end);
- UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_id);
return var_result.value();
}
-Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
- Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector,
+TNode<Object> BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
+ TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
const SmiOperation& smiOperation, const FloatOperation& floatOperation,
- Operation op, bool rhs_is_smi) {
+ Operation op, bool rhs_known_smi) {
Label do_float_operation(this), end(this), call_stub(this),
check_rhsisoddball(this, Label::kDeferred), call_with_any_feedback(this),
if_lhsisnotnumber(this, Label::kDeferred),
if_bigint(this, Label::kDeferred);
- VARIABLE(var_float_lhs, MachineRepresentation::kFloat64);
- VARIABLE(var_float_rhs, MachineRepresentation::kFloat64);
- VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
- VARIABLE(var_result, MachineRepresentation::kTagged);
+ TVARIABLE(Float64T, var_float_lhs);
+ TVARIABLE(Float64T, var_float_rhs);
+ TVARIABLE(Smi, var_type_feedback);
+ TVARIABLE(Object, var_result);
Label if_lhsissmi(this);
// If rhs is known to be an Smi (in the SubSmi, MulSmi, DivSmi, ModSmi
@@ -246,25 +248,28 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
// operation, we want to fast path both Smi and Number operations, so this
// path should not be marked as Deferred.
Label if_lhsisnotsmi(this,
- rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
+ rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
Branch(TaggedIsNotSmi(lhs), &if_lhsisnotsmi, &if_lhsissmi);
// Check if the {lhs} is a Smi or a HeapObject.
BIND(&if_lhsissmi);
{
Comment("lhs is Smi");
- if (!rhs_is_smi) {
+ TNode<Smi> lhs_smi = CAST(lhs);
+ if (!rhs_known_smi) {
// Check if the {rhs} is also a Smi.
Label if_rhsissmi(this), if_rhsisnotsmi(this);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
BIND(&if_rhsisnotsmi);
{
// Check if {rhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
+ TNode<HeapObject> rhs_heap_object = CAST(rhs);
+ GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
// Perform a floating point operation.
- var_float_lhs.Bind(SmiToFloat64(lhs));
- var_float_rhs.Bind(LoadHeapNumberValue(rhs));
+ var_float_lhs = SmiToFloat64(lhs_smi);
+ var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
Goto(&do_float_operation);
}
@@ -273,7 +278,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
Comment("perform smi operation");
- var_result.Bind(smiOperation(lhs, rhs, &var_type_feedback));
+ var_result = smiOperation(lhs_smi, CAST(rhs), &var_type_feedback);
Goto(&end);
}
}
@@ -282,9 +287,10 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
Comment("lhs is not Smi");
// Check if the {lhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(lhs), &if_lhsisnotnumber);
+ TNode<HeapObject> lhs_heap_object = CAST(lhs);
+ GotoIfNot(IsHeapNumber(lhs_heap_object), &if_lhsisnotnumber);
- if (!rhs_is_smi) {
+ if (!rhs_known_smi) {
// Check if the {rhs} is a Smi.
Label if_rhsissmi(this), if_rhsisnotsmi(this);
Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
@@ -292,11 +298,12 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_rhsisnotsmi);
{
// Check if the {rhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
+ TNode<HeapObject> rhs_heap_object = CAST(rhs);
+ GotoIfNot(IsHeapNumber(rhs_heap_object), &check_rhsisoddball);
// Perform a floating point operation.
- var_float_lhs.Bind(LoadHeapNumberValue(lhs));
- var_float_rhs.Bind(LoadHeapNumberValue(rhs));
+ var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
+ var_float_rhs = LoadHeapNumberValue(rhs_heap_object);
Goto(&do_float_operation);
}
@@ -305,19 +312,19 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
// Perform floating point operation.
- var_float_lhs.Bind(LoadHeapNumberValue(lhs));
- var_float_rhs.Bind(SmiToFloat64(rhs));
+ var_float_lhs = LoadHeapNumberValue(lhs_heap_object);
+ var_float_rhs = SmiToFloat64(CAST(rhs));
Goto(&do_float_operation);
}
}
BIND(&do_float_operation);
{
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
- Node* lhs_value = var_float_lhs.value();
- Node* rhs_value = var_float_rhs.value();
- Node* value = floatOperation(lhs_value, rhs_value);
- var_result.Bind(AllocateHeapNumberWithValue(value));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
+ TNode<Float64T> lhs_value = var_float_lhs.value();
+ TNode<Float64T> rhs_value = var_float_rhs.value();
+ TNode<Float64T> value = floatOperation(lhs_value, rhs_value);
+ var_result = AllocateHeapNumberWithValue(value);
Goto(&end);
}
@@ -325,7 +332,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
// No checks on rhs are done yet. We just know lhs is not a number or Smi.
Label if_left_bigint(this), if_left_oddball(this);
- TNode<Uint16T> lhs_instance_type = LoadInstanceType(lhs);
+ TNode<Uint16T> lhs_instance_type = LoadInstanceType(CAST(lhs));
GotoIf(IsBigIntInstanceType(lhs_instance_type), &if_left_bigint);
TNode<BoolT> lhs_is_oddball =
InstanceTypeEqual(lhs_instance_type, ODDBALL_TYPE);
@@ -338,18 +345,18 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_rhsissmi);
{
- var_type_feedback.Bind(
- SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ var_type_feedback =
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
Goto(&call_stub);
}
BIND(&if_rhsisnotsmi);
{
// Check if {rhs} is a HeapNumber.
- GotoIfNot(IsHeapNumber(rhs), &check_rhsisoddball);
+ GotoIfNot(IsHeapNumber(CAST(rhs)), &check_rhsisoddball);
- var_type_feedback.Bind(
- SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ var_type_feedback =
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
Goto(&call_stub);
}
}
@@ -357,7 +364,7 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
BIND(&if_left_bigint);
{
GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
- Branch(IsBigInt(rhs), &if_bigint, &call_with_any_feedback);
+ Branch(IsBigInt(CAST(rhs)), &if_bigint, &call_with_any_feedback);
}
}
@@ -365,39 +372,38 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
{
// Check if rhs is an oddball. At this point we know lhs is either a
// Smi or number or oddball and rhs is not a number or Smi.
- TNode<Uint16T> rhs_instance_type = LoadInstanceType(rhs);
+ TNode<Uint16T> rhs_instance_type = LoadInstanceType(CAST(rhs));
GotoIf(IsBigIntInstanceType(rhs_instance_type), &if_bigint);
TNode<BoolT> rhs_is_oddball =
InstanceTypeEqual(rhs_instance_type, ODDBALL_TYPE);
GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
- var_type_feedback.Bind(
- SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumberOrOddball);
Goto(&call_stub);
}
// This handles the case where at least one input is a BigInt.
BIND(&if_bigint);
{
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kBigInt));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kBigInt);
if (op == Operation::kAdd) {
- var_result.Bind(CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs));
+ var_result = CallBuiltin(Builtins::kBigIntAdd, context, lhs, rhs);
} else {
- var_result.Bind(CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
- SmiConstant(op)));
+ var_result = CallRuntime(Runtime::kBigIntBinaryOp, context, lhs, rhs,
+ SmiConstant(op));
}
Goto(&end);
}
BIND(&call_with_any_feedback);
{
- var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ var_type_feedback = SmiConstant(BinaryOperationFeedback::kAny);
Goto(&call_stub);
}
BIND(&call_stub);
{
- Node* result;
+ TNode<Object> result;
switch (op) {
case Operation::kSubtract:
result = CallBuiltin(Builtins::kSubtract, context, lhs, rhs);
@@ -414,34 +420,35 @@ Node* BinaryOpAssembler::Generate_BinaryOperationWithFeedback(
default:
UNREACHABLE();
}
- var_result.Bind(result);
+ var_result = result;
Goto(&end);
}
BIND(&end);
- UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ UpdateFeedback(var_type_feedback.value(), maybe_feedback_vector, slot_id);
return var_result.value();
}
-Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
- Node* rhs, Node* slot_id,
- Node* feedback_vector,
- bool rhs_is_smi) {
- auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
+TNode<Object> BinaryOpAssembler::Generate_SubtractWithFeedback(
+ TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
+ auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
+ TVariable<Smi>* var_type_feedback) {
Label end(this);
TVARIABLE(Number, var_result);
// If rhs is known to be an Smi (for SubSmi) we want to fast path Smi
// operation. For the normal Sub operation, we want to fast path both
// Smi and Number operations, so this path should not be marked as Deferred.
Label if_overflow(this,
- rhs_is_smi ? Label::kDeferred : Label::kNonDeferred);
- var_result = TrySmiSub(CAST(lhs), CAST(rhs), &if_overflow);
- var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall));
+ rhs_known_smi ? Label::kDeferred : Label::kNonDeferred);
+ var_result = TrySmiSub(lhs, rhs, &if_overflow);
+ *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
Goto(&end);
BIND(&if_overflow);
{
- var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ *var_type_feedback = SmiConstant(BinaryOperationFeedback::kNumber);
TNode<Float64T> value = Float64Sub(SmiToFloat64(lhs), SmiToFloat64(rhs));
var_result = AllocateHeapNumberWithValue(value);
Goto(&end);
@@ -450,91 +457,97 @@ Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
BIND(&end);
return var_result.value();
};
- auto floatFunction = [=](Node* lhs, Node* rhs) {
+ auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
return Float64Sub(lhs, rhs);
};
return Generate_BinaryOperationWithFeedback(
- context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction,
- Operation::kSubtract, rhs_is_smi);
+ context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
+ floatFunction, Operation::kSubtract, rhs_known_smi);
}
-Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs,
- Node* rhs, Node* slot_id,
- Node* feedback_vector,
- bool rhs_is_smi) {
- auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
- TNode<Number> result = SmiMul(CAST(lhs), CAST(rhs));
- var_type_feedback->Bind(SelectSmiConstant(
+TNode<Object> BinaryOpAssembler::Generate_MultiplyWithFeedback(
+ TNode<Context> context, TNode<Object> lhs, TNode<Object> rhs,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
+ auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
+ TVariable<Smi>* var_type_feedback) {
+ TNode<Number> result = SmiMul(lhs, rhs);
+ *var_type_feedback = SelectSmiConstant(
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
- BinaryOperationFeedback::kNumber));
+ BinaryOperationFeedback::kNumber);
return result;
};
- auto floatFunction = [=](Node* lhs, Node* rhs) {
+ auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
return Float64Mul(lhs, rhs);
};
return Generate_BinaryOperationWithFeedback(
- context, lhs, rhs, slot_id, feedback_vector, smiFunction, floatFunction,
- Operation::kMultiply, rhs_is_smi);
+ context, lhs, rhs, slot_id, maybe_feedback_vector, smiFunction,
+ floatFunction, Operation::kMultiply, rhs_known_smi);
}
-Node* BinaryOpAssembler::Generate_DivideWithFeedback(
- Node* context, Node* dividend, Node* divisor, Node* slot_id,
- Node* feedback_vector, bool rhs_is_smi) {
- auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
- VARIABLE(var_result, MachineRepresentation::kTagged);
+TNode<Object> BinaryOpAssembler::Generate_DivideWithFeedback(
+ TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
+ auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
+ TVariable<Smi>* var_type_feedback) {
+ TVARIABLE(Object, var_result);
// If rhs is known to be an Smi (for DivSmi) we want to fast path Smi
// operation. For the normal Div operation, we want to fast path both
// Smi and Number operations, so this path should not be marked as Deferred.
- Label bailout(this, rhs_is_smi ? Label::kDeferred : Label::kNonDeferred),
+ Label bailout(this, rhs_known_smi ? Label::kDeferred : Label::kNonDeferred),
end(this);
- var_result.Bind(TrySmiDiv(CAST(lhs), CAST(rhs), &bailout));
- var_type_feedback->Bind(SmiConstant(BinaryOperationFeedback::kSignedSmall));
+ var_result = TrySmiDiv(lhs, rhs, &bailout);
+ *var_type_feedback = SmiConstant(BinaryOperationFeedback::kSignedSmall);
Goto(&end);
BIND(&bailout);
{
- var_type_feedback->Bind(
- SmiConstant(BinaryOperationFeedback::kSignedSmallInputs));
+ *var_type_feedback =
+ SmiConstant(BinaryOperationFeedback::kSignedSmallInputs);
TNode<Float64T> value = Float64Div(SmiToFloat64(lhs), SmiToFloat64(rhs));
- var_result.Bind(AllocateHeapNumberWithValue(value));
+ var_result = AllocateHeapNumberWithValue(value);
Goto(&end);
}
BIND(&end);
return var_result.value();
};
- auto floatFunction = [=](Node* lhs, Node* rhs) {
+ auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
return Float64Div(lhs, rhs);
};
return Generate_BinaryOperationWithFeedback(
- context, dividend, divisor, slot_id, feedback_vector, smiFunction,
- floatFunction, Operation::kDivide, rhs_is_smi);
+ context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
+ floatFunction, Operation::kDivide, rhs_known_smi);
}
-Node* BinaryOpAssembler::Generate_ModulusWithFeedback(
- Node* context, Node* dividend, Node* divisor, Node* slot_id,
- Node* feedback_vector, bool rhs_is_smi) {
- auto smiFunction = [=](Node* lhs, Node* rhs, Variable* var_type_feedback) {
- TNode<Number> result = SmiMod(CAST(lhs), CAST(rhs));
- var_type_feedback->Bind(SelectSmiConstant(
+TNode<Object> BinaryOpAssembler::Generate_ModulusWithFeedback(
+ TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
+ auto smiFunction = [=](TNode<Smi> lhs, TNode<Smi> rhs,
+ TVariable<Smi>* var_type_feedback) {
+ TNode<Number> result = SmiMod(lhs, rhs);
+ *var_type_feedback = SelectSmiConstant(
TaggedIsSmi(result), BinaryOperationFeedback::kSignedSmall,
- BinaryOperationFeedback::kNumber));
+ BinaryOperationFeedback::kNumber);
return result;
};
- auto floatFunction = [=](Node* lhs, Node* rhs) {
+ auto floatFunction = [=](TNode<Float64T> lhs, TNode<Float64T> rhs) {
return Float64Mod(lhs, rhs);
};
return Generate_BinaryOperationWithFeedback(
- context, dividend, divisor, slot_id, feedback_vector, smiFunction,
- floatFunction, Operation::kModulus, rhs_is_smi);
+ context, dividend, divisor, slot_id, maybe_feedback_vector, smiFunction,
+ floatFunction, Operation::kModulus, rhs_known_smi);
}
-Node* BinaryOpAssembler::Generate_ExponentiateWithFeedback(
- Node* context, Node* base, Node* exponent, Node* slot_id,
- Node* feedback_vector, bool rhs_is_smi) {
+TNode<Object> BinaryOpAssembler::Generate_ExponentiateWithFeedback(
+ TNode<Context> context, TNode<Object> base, TNode<Object> exponent,
+ TNode<UintPtrT> slot_id, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi) {
// We currently don't optimize exponentiation based on feedback.
TNode<Smi> dummy_feedback = SmiConstant(BinaryOperationFeedback::kAny);
- UpdateFeedback(dummy_feedback, feedback_vector, slot_id);
+ UpdateFeedback(dummy_feedback, maybe_feedback_vector, slot_id);
return CallBuiltin(Builtins::kExponentiate, context, base, exponent);
}
diff --git a/deps/v8/src/ic/binary-op-assembler.h b/deps/v8/src/ic/binary-op-assembler.h
index 26324660c8..37484909d4 100644
--- a/deps/v8/src/ic/binary-op-assembler.h
+++ b/deps/v8/src/ic/binary-op-assembler.h
@@ -17,44 +17,50 @@ class CodeAssemblerState;
class BinaryOpAssembler : public CodeStubAssembler {
public:
- using Node = compiler::Node;
-
explicit BinaryOpAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
- Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs,
- Node* slot_id, Node* feedback_vector,
- bool rhs_is_smi);
+ TNode<Object> Generate_AddWithFeedback(
+ TNode<Context> context, TNode<Object> left, TNode<Object> right,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
- Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs,
- Node* slot_id, Node* feedback_vector,
- bool rhs_is_smi);
+ TNode<Object> Generate_SubtractWithFeedback(
+ TNode<Context> context, TNode<Object> left, TNode<Object> right,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
- Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs,
- Node* slot_id, Node* feedback_vector,
- bool rhs_is_smi);
+ TNode<Object> Generate_MultiplyWithFeedback(
+ TNode<Context> context, TNode<Object> left, TNode<Object> right,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
- Node* Generate_DivideWithFeedback(Node* context, Node* dividend,
- Node* divisor, Node* slot_id,
- Node* feedback_vector, bool rhs_is_smi);
+ TNode<Object> Generate_DivideWithFeedback(
+ TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
- Node* Generate_ModulusWithFeedback(Node* context, Node* dividend,
- Node* divisor, Node* slot_id,
- Node* feedback_vector, bool rhs_is_smi);
+ TNode<Object> Generate_ModulusWithFeedback(
+ TNode<Context> context, TNode<Object> dividend, TNode<Object> divisor,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
- Node* Generate_ExponentiateWithFeedback(Node* context, Node* dividend,
- Node* divisor, Node* slot_id,
- Node* feedback_vector,
- bool rhs_is_smi);
+ TNode<Object> Generate_ExponentiateWithFeedback(
+ TNode<Context> context, TNode<Object> base, TNode<Object> exponent,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
+ bool rhs_known_smi);
private:
- using SmiOperation = std::function<Node*(Node*, Node*, Variable*)>;
- using FloatOperation = std::function<Node*(Node*, Node*)>;
-
- Node* Generate_BinaryOperationWithFeedback(
- Node* context, Node* lhs, Node* rhs, Node* slot_id, Node* feedback_vector,
+ using SmiOperation =
+ std::function<TNode<Object>(TNode<Smi>, TNode<Smi>, TVariable<Smi>*)>;
+ using FloatOperation =
+ std::function<TNode<Float64T>(TNode<Float64T>, TNode<Float64T>)>;
+
+ TNode<Object> Generate_BinaryOperationWithFeedback(
+ TNode<Context> context, TNode<Object> left, TNode<Object> right,
+ TNode<UintPtrT> slot, TNode<HeapObject> maybe_feedback_vector,
const SmiOperation& smiOperation, const FloatOperation& floatOperation,
- Operation op, bool rhs_is_smi);
+ Operation op, bool rhs_known_smi);
};
} // namespace internal
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index c0ff8a4c9b..95ef353277 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -43,6 +43,11 @@ Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) {
return handle(Smi::FromInt(config), isolate);
}
+Handle<Smi> LoadHandler::LoadSlow(Isolate* isolate) {
+ int config = KindBits::encode(kSlow);
+ return handle(Smi::FromInt(config), isolate);
+}
+
Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
int config = KindBits::encode(kField) |
IsInobjectBits::encode(field_index.is_inobject()) |
@@ -127,6 +132,16 @@ Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) {
return handle(Smi::FromInt(config), isolate);
}
+Handle<Smi> StoreHandler::StoreInterceptor(Isolate* isolate) {
+ int config = KindBits::encode(kInterceptor);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+Handle<Smi> StoreHandler::StoreSlow(Isolate* isolate) {
+ int config = KindBits::encode(kSlow);
+ return handle(Smi::FromInt(config), isolate);
+}
+
Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
int config = KindBits::encode(kProxy);
return handle(Smi::FromInt(config), isolate);
@@ -135,29 +150,12 @@ Handle<Smi> StoreHandler::StoreProxy(Isolate* isolate) {
Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation) {
- FieldRepresentation field_rep;
- switch (representation.kind()) {
- case Representation::kSmi:
- field_rep = kSmi;
- break;
- case Representation::kDouble:
- field_rep = kDouble;
- break;
- case Representation::kHeapObject:
- field_rep = kHeapObject;
- break;
- case Representation::kTagged:
- field_rep = kTagged;
- break;
- default:
- UNREACHABLE();
- }
-
+ DCHECK(!representation.IsNone());
DCHECK(kind == kField || kind == kConstField);
int config = KindBits::encode(kind) |
IsInobjectBits::encode(field_index.is_inobject()) |
- FieldRepresentationBits::encode(field_rep) |
+ RepresentationBits::encode(representation.kind()) |
DescriptorBits::encode(descriptor) |
FieldIndexBits::encode(field_index.index());
return handle(Smi::FromInt(config), isolate);
diff --git a/deps/v8/src/ic/handler-configuration.cc b/deps/v8/src/ic/handler-configuration.cc
index 814935c6eb..3af5fe4953 100644
--- a/deps/v8/src/ic/handler-configuration.cc
+++ b/deps/v8/src/ic/handler-configuration.cc
@@ -196,7 +196,7 @@ MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
bool is_dictionary_map = transition_map->is_dictionary_map();
#ifdef DEBUG
if (!is_dictionary_map) {
- int descriptor = transition_map->LastAdded();
+ InternalIndex descriptor = transition_map->LastAdded();
Handle<DescriptorArray> descriptors(transition_map->instance_descriptors(),
isolate);
PropertyDetails details = descriptors->GetDetails(descriptor);
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index 80d19d73ec..fd0cee2920 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -43,6 +43,7 @@ class LoadHandler final : public DataHandler {
kApiGetter,
kApiGetterHolderIsPrototype,
kInterceptor,
+ kSlow,
kProxy,
kNonExistent,
kModuleExport
@@ -113,6 +114,9 @@ class LoadHandler final : public DataHandler {
// interceptor.
static inline Handle<Smi> LoadInterceptor(Isolate* isolate);
+ // Creates a Smi-handler for loading a property from a object.
+ static inline Handle<Smi> LoadSlow(Isolate* isolate);
+
// Creates a Smi-handler for loading a field from fast object.
static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
@@ -197,13 +201,13 @@ class StoreHandler final : public DataHandler {
kApiSetterHolderIsPrototype,
kGlobalProxy,
kNormal,
+ kInterceptor,
+ kSlow,
kProxy,
kKindsNumber // Keep last
};
using KindBits = BitField<Kind, 0, 4>;
- enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
-
// Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object.
@@ -231,10 +235,10 @@ class StoreHandler final : public DataHandler {
// Encoding when KindBits contains kField or kTransitionToField.
//
using IsInobjectBits = DescriptorBits::Next<bool, 1>;
- using FieldRepresentationBits = IsInobjectBits::Next<FieldRepresentation, 2>;
+ using RepresentationBits = IsInobjectBits::Next<Representation::Kind, 3>;
// +1 here is to cover all possible JSObject header sizes.
using FieldIndexBits =
- FieldRepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
+ RepresentationBits::Next<unsigned, kDescriptorIndexBitCount + 1>;
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldIndexBits::kLastUsedBit < kSmiValueSize);
@@ -283,6 +287,12 @@ class StoreHandler final : public DataHandler {
// Creates a Smi-handler for storing a property to a slow object.
static inline Handle<Smi> StoreNormal(Isolate* isolate);
+ // Creates a Smi-handler for storing a property to an interceptor.
+ static inline Handle<Smi> StoreInterceptor(Isolate* isolate);
+
+ // Creates a Smi-handler for storing a property.
+ static inline Handle<Smi> StoreSlow(Isolate* isolate);
+
// Creates a Smi-handler for storing a property on a proxy.
static inline Handle<Smi> StoreProxy(Isolate* isolate);
diff --git a/deps/v8/src/ic/ic-stats.cc b/deps/v8/src/ic/ic-stats.cc
index f387239aee..54d4856631 100644
--- a/deps/v8/src/ic/ic-stats.cc
+++ b/deps/v8/src/ic/ic-stats.cc
@@ -94,6 +94,7 @@ ICInfo::ICInfo()
script_offset(0),
script_name(nullptr),
line_num(-1),
+ column_num(-1),
is_constructor(false),
is_optimized(false),
map(nullptr),
@@ -106,6 +107,7 @@ void ICInfo::Reset() {
script_offset = 0;
script_name = nullptr;
line_num = -1;
+ column_num = -1;
is_constructor = false;
is_optimized = false;
state.clear();
@@ -127,6 +129,7 @@ void ICInfo::AppendToTracedValue(v8::tracing::TracedValue* value) const {
if (script_offset) value->SetInteger("offset", script_offset);
if (script_name) value->SetString("scriptName", script_name);
if (line_num != -1) value->SetInteger("lineNum", line_num);
+ if (column_num != -1) value->SetInteger("columnNum", column_num);
if (is_constructor) value->SetInteger("constructor", is_constructor);
if (!state.empty()) value->SetString("state", state);
if (map) {
diff --git a/deps/v8/src/ic/ic-stats.h b/deps/v8/src/ic/ic-stats.h
index 76c65c3862..44b968c6c0 100644
--- a/deps/v8/src/ic/ic-stats.h
+++ b/deps/v8/src/ic/ic-stats.h
@@ -34,6 +34,7 @@ struct ICInfo {
int script_offset;
const char* script_name;
int line_num;
+ int column_num;
bool is_constructor;
bool is_optimized;
std::string state;
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index 54f4be7a22..4ac5fd7abe 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -15,6 +15,7 @@
#include "src/execution/execution.h"
#include "src/execution/frames-inl.h"
#include "src/execution/isolate-inl.h"
+#include "src/execution/protectors-inl.h"
#include "src/execution/runtime-profiler.h"
#include "src/handles/handles-inl.h"
#include "src/ic/call-optimization.h"
@@ -47,8 +48,6 @@ char IC::TransitionMarkFromState(IC::State state) {
return 'X';
case UNINITIALIZED:
return '0';
- case PREMONOMORPHIC:
- return '.';
case MONOMORPHIC:
return '1';
case RECOMPUTE_HANDLER:
@@ -343,11 +342,6 @@ bool IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
return changed;
}
-void IC::ConfigureVectorState(Handle<Map> map) {
- nexus()->ConfigurePremonomorphic(map);
- OnFeedbackChanged("Premonomorphic");
-}
-
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Handle<Object> handler) {
ConfigureVectorState(name, map, MaybeObjectHandle(handler));
@@ -383,11 +377,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// of its properties; throw a TypeError in that case.
if (IsAnyHas() ? !object->IsJSReceiver()
: object->IsNullOrUndefined(isolate())) {
- if (use_ic && state() != PREMONOMORPHIC) {
+ if (use_ic) {
// Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
update_receiver_map(object);
- PatchCache(name, slow_stub());
+ SetCache(name, LoadHandler::LoadSlow(isolate()));
TraceIC("LoadIC", name);
}
@@ -490,7 +484,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
} else {
// Given combination of indices can't be encoded, so use slow stub.
TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
- PatchCache(name, slow_stub());
+ SetCache(name, LoadHandler::LoadSlow(isolate()));
}
TraceIC("LoadGlobalIC", name);
}
@@ -613,11 +607,11 @@ bool IC::IsTransitionOfMonomorphicTarget(Map source_map, Map target_map) {
return transitioned_map == target_map;
}
-void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
- PatchCache(name, MaybeObjectHandle(handler));
+void IC::SetCache(Handle<Name> name, Handle<Object> handler) {
+ SetCache(name, MaybeObjectHandle(handler));
}
-void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
+void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) {
DCHECK(IsHandler(*handler));
// Currently only load and store ICs support non-code handlers.
DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas());
@@ -625,7 +619,6 @@ void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
case NO_FEEDBACK:
UNREACHABLE();
case UNINITIALIZED:
- case PREMONOMORPHIC:
UpdateMonomorphicIC(handler, name);
break;
case RECOMPUTE_HANDLER:
@@ -659,7 +652,7 @@ __attribute__((__aligned__(32)))
void LoadIC::UpdateCaches(LookupIterator* lookup) {
Handle<Object> code;
if (lookup->state() == LookupIterator::ACCESS_CHECK) {
- code = slow_stub();
+ code = LoadHandler::LoadSlow(isolate());
} else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
@@ -683,7 +676,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = ComputeHandler(lookup);
}
- PatchCache(lookup->name(), code);
+ SetCache(lookup->name(), code);
TraceIC("LoadIC", lookup->name());
}
@@ -798,7 +791,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
isolate());
if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ return LoadHandler::LoadSlow(isolate());
}
if ((getter->IsFunctionTemplateInfo() &&
@@ -807,7 +800,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
JSFunction::cast(*getter).shared().BreakAtEntry())) {
// Do not install an IC if the api function has a breakpoint.
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ return LoadHandler::LoadSlow(isolate());
}
Handle<Smi> smi_handler;
@@ -817,7 +810,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
!holder->HasFastProperties()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ return LoadHandler::LoadSlow(isolate());
}
CallOptimization::HolderLookup holder_lookup;
@@ -868,7 +861,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
!holder->HasFastProperties() ||
(info->is_sloppy() && !receiver->IsJSReceiver())) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ return LoadHandler::LoadSlow(isolate());
}
Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
@@ -1076,7 +1069,7 @@ bool AllowConvertHoleElementToUndefined(Isolate* isolate,
}
// For other {receiver}s we need to check the "no elements" protector.
- if (isolate->IsNoElementsProtectorIntact()) {
+ if (Protectors::IsNoElementsIntact(isolate)) {
if (receiver_map->IsStringMap()) {
return true;
}
@@ -1315,12 +1308,11 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
case LookupIterator::INTERCEPTOR: {
Handle<JSObject> holder = it->GetHolder<JSObject>();
InterceptorInfo info = holder->GetNamedInterceptor();
- if (it->HolderIsReceiverOrHiddenPrototype()) {
- return !info.non_masking() && receiver.is_identical_to(holder) &&
- !info.setter().IsUndefined(isolate());
- } else if (!info.getter().IsUndefined(isolate()) ||
- !info.query().IsUndefined(isolate())) {
- return false;
+ if ((it->HolderIsReceiverOrHiddenPrototype() &&
+ !info.non_masking()) ||
+ !info.getter().IsUndefined(isolate()) ||
+ !info.query().IsUndefined(isolate())) {
+ return true;
}
break;
}
@@ -1403,7 +1395,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
} else {
// Given combination of indices can't be encoded, so use slow stub.
TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_SlowStub);
- PatchCache(name, slow_stub());
+ SetCache(name, StoreHandler::StoreSlow(isolate()));
}
TraceIC("StoreGlobalIC", name);
}
@@ -1432,11 +1424,11 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
// If the object is undefined or null it's illegal to try to set any
// properties on it; throw a TypeError in that case.
if (object->IsNullOrUndefined(isolate())) {
- if (use_ic && state() != PREMONOMORPHIC) {
+ if (use_ic) {
// Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), StoreIC_NonReceiver);
update_receiver_map(object);
- PatchCache(name, slow_stub());
+ SetCache(name, StoreHandler::StoreSlow(isolate()));
TraceIC("StoreIC", name);
}
return TypeError(MessageTemplate::kNonObjectPropertyStore, object, name);
@@ -1481,30 +1473,11 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
}
handler = ComputeHandler(lookup);
} else {
- if (state() == UNINITIALIZED && IsStoreGlobalIC() &&
- lookup->state() == LookupIterator::INTERCEPTOR) {
- InterceptorInfo info =
- lookup->GetHolder<JSObject>()->GetNamedInterceptor();
- if (!lookup->HolderIsReceiverOrHiddenPrototype() &&
- !info.getter().IsUndefined(isolate())) {
- // Utilize premonomorphic state for global store ics that run into
- // an interceptor because the property doesn't exist yet.
- // After we actually set the property, we'll have more information.
- // Premonomorphism gives us a chance to find more information the
- // second time.
- TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_Premonomorphic);
- ConfigureVectorState(receiver_map());
- TraceIC("StoreGlobalIC", lookup->name());
- return;
- }
- }
-
set_slow_stub_reason("LookupForWrite said 'false'");
- // TODO(marja): change slow_stub to return MaybeObjectHandle.
- handler = MaybeObjectHandle(slow_stub());
+ handler = MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
- PatchCache(lookup->name(), handler);
+ SetCache(lookup->name(), handler);
TraceIC("StoreIC", lookup->name());
}
@@ -1542,12 +1515,27 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
case LookupIterator::INTERCEPTOR: {
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
- USE(holder);
+ InterceptorInfo info = holder->GetNamedInterceptor();
+
+ // If the interceptor is on the receiver
+ if (lookup->HolderIsReceiverOrHiddenPrototype() && !info.non_masking()) {
+ // return a store interceptor smi handler if there is one,
+ if (!info.setter().IsUndefined(isolate())) {
+ return MaybeObjectHandle(StoreHandler::StoreInterceptor(isolate()));
+ }
+ // otherwise return a slow-case smi handler.
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
+ }
- DCHECK(!holder->GetNamedInterceptor().setter().IsUndefined(isolate()));
- // TODO(jgruber): Update counter name.
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreInterceptorStub);
- return MaybeObjectHandle(BUILTIN_CODE(isolate(), StoreInterceptorIC));
+ // If the interceptor is a getter/query interceptor on the prototype
+ // chain, return an invalidatable slow handler so it can turn fast if the
+ // interceptor is masked by a regular property later.
+ DCHECK(!info.getter().IsUndefined(isolate()) ||
+ !info.query().IsUndefined(isolate()));
+ Handle<Object> handler = StoreHandler::StoreThroughPrototype(
+ isolate(), receiver_map(), holder,
+ StoreHandler::StoreSlow(isolate()));
+ return MaybeObjectHandle(handler);
}
case LookupIterator::ACCESSOR: {
@@ -1559,7 +1547,9 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
if (!holder->HasFastProperties()) {
set_slow_stub_reason("accessor on slow map");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ MaybeObjectHandle handler =
+ MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
+ return handler;
}
Handle<Object> accessors = lookup->GetAccessors();
if (accessors->IsAccessorInfo()) {
@@ -1567,18 +1557,18 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
if (v8::ToCData<Address>(info->setter()) == kNullAddress) {
set_slow_stub_reason("setter == kNullAddress");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
if (AccessorInfo::cast(*accessors).is_special_data_property() &&
!lookup->HolderIsReceiverOrHiddenPrototype()) {
set_slow_stub_reason("special data property in prototype chain");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
if (!AccessorInfo::IsCompatibleReceiverMap(info, receiver_map())) {
set_slow_stub_reason("incompatible receiver type");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
Handle<Smi> smi_handler = StoreHandler::StoreNativeDataProperty(
@@ -1598,7 +1588,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
if (!setter->IsJSFunction() && !setter->IsFunctionTemplateInfo()) {
set_slow_stub_reason("setter not a function");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
if ((setter->IsFunctionTemplateInfo() &&
@@ -1607,7 +1597,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
JSFunction::cast(*setter).shared().BreakAtEntry())) {
// Do not install an IC if the api function has a breakpoint.
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
CallOptimization call_optimization(isolate(), setter);
@@ -1631,11 +1621,11 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
}
set_slow_stub_reason("incompatible receiver");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
} else if (setter->IsFunctionTemplateInfo()) {
set_slow_stub_reason("setter non-simple template");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
Handle<Smi> smi_handler =
@@ -1651,7 +1641,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
isolate(), receiver_map(), holder, smi_handler));
}
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
case LookupIterator::DATA: {
@@ -1694,7 +1684,7 @@ MaybeObjectHandle StoreIC::ComputeHandler(LookupIterator* lookup) {
DCHECK_EQ(kDescriptor, lookup->property_details().location());
set_slow_stub_reason("constant property");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return MaybeObjectHandle(slow_stub());
+ return MaybeObjectHandle(StoreHandler::StoreSlow(isolate()));
}
case LookupIterator::JSPROXY: {
Handle<JSReceiver> receiver =
@@ -1905,7 +1895,7 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
// TODO(mvstanton): Consider embedding store_mode in the state of the slow
// keyed store ic for uniformity.
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
- handler = slow_stub();
+ handler = StoreHandler::StoreSlow(isolate());
} else {
{
@@ -2532,7 +2522,7 @@ static bool CanFastCloneObject(Handle<Map> map) {
}
DescriptorArray descriptors = map->instance_descriptors();
- for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
+ for (InternalIndex i : map->IterateOwnDescriptors()) {
PropertyDetails details = descriptors.GetDetails(i);
Name key = descriptors.GetKey(i);
if (details.kind() != kData || !details.IsEnumerable() ||
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index 29f3b4a60a..a3c68f4fbf 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -74,8 +74,6 @@ class IC {
// Configure for most states.
bool ConfigureVectorState(IC::State new_state, Handle<Object> key);
- // Configure the vector for PREMONOMORPHIC.
- void ConfigureVectorState(Handle<Map> map);
// Configure the vector for MONOMORPHIC.
void ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Handle<Object> handler);
@@ -103,8 +101,8 @@ class IC {
void CopyICToMegamorphicCache(Handle<Name> name);
bool IsTransitionOfMonomorphicTarget(Map source_map, Map target_map);
- void PatchCache(Handle<Name> name, Handle<Object> handler);
- void PatchCache(Handle<Name> name, const MaybeObjectHandle& handler);
+ void SetCache(Handle<Name> name, Handle<Object> handler);
+ void SetCache(Handle<Name> name, const MaybeObjectHandle& handler);
FeedbackSlotKind kind() const { return kind_; }
bool IsGlobalIC() const { return IsLoadGlobalIC() || IsStoreGlobalIC(); }
bool IsLoadIC() const { return IsLoadICKind(kind_); }
@@ -188,11 +186,6 @@ class LoadIC : public IC {
Handle<Name> name);
protected:
- virtual Handle<Code> slow_stub() const {
- return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow)
- : BUILTIN_CODE(isolate(), LoadIC_Slow);
- }
-
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupIterator* lookup);
@@ -211,11 +204,6 @@ class LoadGlobalIC : public LoadIC {
: LoadIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
-
- protected:
- Handle<Code> slow_stub() const override {
- return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
- }
};
class KeyedLoadIC : public LoadIC {
@@ -268,11 +256,6 @@ class StoreIC : public IC {
protected:
// Stub accessors.
- virtual Handle<Code> slow_stub() const {
- // All StoreICs share the same slow stub.
- return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
- }
-
// Update the inline cache and the global stub cache based on the
// lookup result.
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
@@ -292,11 +275,6 @@ class StoreGlobalIC : public StoreIC {
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
Handle<Object> value);
-
- protected:
- Handle<Code> slow_stub() const override {
- return BUILTIN_CODE(isolate(), StoreGlobalIC_Slow);
- }
};
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
@@ -328,10 +306,6 @@ class KeyedStoreIC : public StoreIC {
KeyedAccessStoreMode store_mode,
Handle<Map> new_receiver_map);
- Handle<Code> slow_stub() const override {
- return BUILTIN_CODE(isolate(), KeyedStoreIC_Slow);
- }
-
private:
Handle<Map> ComputeTransitionedMap(Handle<Map> map,
TransitionMode transition_mode);
@@ -356,11 +330,6 @@ class StoreInArrayLiteralIC : public KeyedStoreIC {
}
void Store(Handle<JSArray> array, Handle<Object> index, Handle<Object> value);
-
- private:
- Handle<Code> slow_stub() const override {
- return BUILTIN_CODE(isolate(), StoreInArrayLiteralIC_Slow);
- }
};
} // namespace internal
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index bb4e6cb427..ff830a022e 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -16,10 +16,6 @@
namespace v8 {
namespace internal {
-using Node = compiler::Node;
-template <class T>
-using TNode = compiler::TNode<T>;
-
enum class StoreMode { kOrdinary, kInLiteral };
class KeyedStoreGenericAssembler : public AccessorAssembler {
@@ -62,9 +58,11 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
TNode<Object> key, TNode<Object> value,
Maybe<LanguageMode> language_mode);
- void EmitGenericElementStore(Node* receiver, TNode<Map> receiver_map,
- Node* instance_type, TNode<IntPtrT> index,
- Node* value, Node* context, Label* slow);
+ void EmitGenericElementStore(TNode<JSObject> receiver,
+ TNode<Map> receiver_map,
+ TNode<Uint16T> instance_type,
+ TNode<IntPtrT> index, TNode<Object> value,
+ TNode<Context> context, Label* slow);
// If language mode is not provided it is deduced from the feedback slot's
// kind.
@@ -86,38 +84,46 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
Label* non_fast_elements,
Label* only_fast_elements);
- void TryRewriteElements(Node* receiver, TNode<Map> receiver_map,
- Node* elements, Node* native_context,
+ void TryRewriteElements(TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<FixedArrayBase> elements,
+ TNode<NativeContext> native_context,
ElementsKind from_kind, ElementsKind to_kind,
Label* bailout);
- void StoreElementWithCapacity(Node* receiver, TNode<Map> receiver_map,
+ void StoreElementWithCapacity(TNode<JSObject> receiver,
+ TNode<Map> receiver_map,
SloppyTNode<FixedArrayBase> elements,
TNode<Word32T> elements_kind,
- TNode<IntPtrT> index, Node* value,
- Node* context, Label* slow,
+ TNode<IntPtrT> index, SloppyTNode<Object> value,
+ TNode<Context> context, Label* slow,
UpdateLength update_length);
- void MaybeUpdateLengthAndReturn(Node* receiver, Node* index, Node* value,
+ void MaybeUpdateLengthAndReturn(TNode<JSObject> receiver,
+ TNode<IntPtrT> index, TNode<Object> value,
UpdateLength update_length);
- void TryChangeToHoleyMapHelper(Node* receiver, TNode<Map> receiver_map,
- Node* native_context, ElementsKind packed_kind,
+ void TryChangeToHoleyMapHelper(TNode<JSObject> receiver,
+ TNode<Map> receiver_map,
+ TNode<NativeContext> native_context,
+ ElementsKind packed_kind,
ElementsKind holey_kind, Label* done,
Label* map_mismatch, Label* bailout);
- void TryChangeToHoleyMap(Node* receiver, TNode<Map> receiver_map,
- TNode<Word32T> current_elements_kind, Node* context,
- ElementsKind packed_kind, Label* bailout);
- void TryChangeToHoleyMapMulti(Node* receiver, TNode<Map> receiver_map,
+ void TryChangeToHoleyMap(TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind,
+ TNode<Context> context, ElementsKind packed_kind,
+ Label* bailout);
+ void TryChangeToHoleyMapMulti(TNode<JSObject> receiver,
+ TNode<Map> receiver_map,
TNode<Word32T> current_elements_kind,
- Node* context, ElementsKind packed_kind,
+ TNode<Context> context,
+ ElementsKind packed_kind,
ElementsKind packed_kind_2, Label* bailout);
- void LookupPropertyOnPrototypeChain(TNode<Map> receiver_map, Node* name,
- Label* accessor,
- Variable* var_accessor_pair,
- Variable* var_accessor_holder,
- Label* readonly, Label* bailout);
+ void LookupPropertyOnPrototypeChain(
+ TNode<Map> receiver_map, TNode<Name> name, Label* accessor,
+ TVariable<Object>* var_accessor_pair,
+ TVariable<HeapObject>* var_accessor_holder, Label* readonly,
+ Label* bailout);
TNode<Map> FindCandidateStoreICTransitionMapHandler(TNode<Map> map,
TNode<Name> name,
@@ -173,18 +179,18 @@ void KeyedStoreGenericGenerator::SetPropertyInLiteral(
void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
TNode<Map> receiver_map, Label* non_fast_elements,
Label* only_fast_elements) {
- VARIABLE(var_map, MachineRepresentation::kTagged);
- var_map.Bind(receiver_map);
+ TVARIABLE(Map, var_map);
+ var_map = receiver_map;
Label loop_body(this, &var_map);
Goto(&loop_body);
BIND(&loop_body);
{
- Node* map = var_map.value();
+ TNode<Map> map = var_map.value();
TNode<HeapObject> prototype = LoadMapPrototype(map);
GotoIf(IsNull(prototype), only_fast_elements);
TNode<Map> prototype_map = LoadMap(prototype);
- var_map.Bind(prototype_map);
+ var_map = prototype_map;
TNode<Uint16T> instance_type = LoadMapInstanceType(prototype_map);
GotoIf(IsCustomElementsReceiverInstanceType(instance_type),
non_fast_elements);
@@ -196,9 +202,9 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
}
void KeyedStoreGenericAssembler::TryRewriteElements(
- Node* receiver, TNode<Map> receiver_map, Node* elements,
- Node* native_context, ElementsKind from_kind, ElementsKind to_kind,
- Label* bailout) {
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<FixedArrayBase> elements, TNode<NativeContext> native_context,
+ ElementsKind from_kind, ElementsKind to_kind, Label* bailout) {
DCHECK(IsFastPackedElementsKind(from_kind));
ElementsKind holey_from_kind = GetHoleyElementsKind(from_kind);
ElementsKind holey_to_kind = GetHoleyElementsKind(to_kind);
@@ -206,12 +212,12 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
TrapAllocationMemento(receiver, bailout);
}
Label perform_transition(this), check_holey_map(this);
- VARIABLE(var_target_map, MachineRepresentation::kTagged);
+ TVARIABLE(Map, var_target_map);
// Check if the receiver has the default |from_kind| map.
{
TNode<Map> packed_map = LoadJSArrayElementsMap(from_kind, native_context);
GotoIf(TaggedNotEqual(receiver_map, packed_map), &check_holey_map);
- var_target_map.Bind(
+ var_target_map = CAST(
LoadContextElement(native_context, Context::ArrayMapIndex(to_kind)));
Goto(&perform_transition);
}
@@ -222,7 +228,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
TNode<Object> holey_map = LoadContextElement(
native_context, Context::ArrayMapIndex(holey_from_kind));
GotoIf(TaggedNotEqual(receiver_map, holey_map), bailout);
- var_target_map.Bind(LoadContextElement(
+ var_target_map = CAST(LoadContextElement(
native_context, Context::ArrayMapIndex(holey_to_kind)));
Goto(&perform_transition);
}
@@ -240,9 +246,9 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
- Node* receiver, TNode<Map> receiver_map, Node* native_context,
- ElementsKind packed_kind, ElementsKind holey_kind, Label* done,
- Label* map_mismatch, Label* bailout) {
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<NativeContext> native_context, ElementsKind packed_kind,
+ ElementsKind holey_kind, Label* done, Label* map_mismatch, Label* bailout) {
TNode<Map> packed_map = LoadJSArrayElementsMap(packed_kind, native_context);
GotoIf(TaggedNotEqual(receiver_map, packed_map), map_mismatch);
if (AllocationSite::ShouldTrack(packed_kind, holey_kind)) {
@@ -255,23 +261,23 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapHelper(
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
- Node* receiver, TNode<Map> receiver_map,
- TNode<Word32T> current_elements_kind, Node* context,
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind, TNode<Context> context,
ElementsKind packed_kind, Label* bailout) {
ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
Label already_holey(this);
GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind)),
&already_holey);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, bailout, bailout);
BIND(&already_holey);
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
- Node* receiver, TNode<Map> receiver_map,
- TNode<Word32T> current_elements_kind, Node* context,
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<Word32T> current_elements_kind, TNode<Context> context,
ElementsKind packed_kind, ElementsKind packed_kind_2, Label* bailout) {
ElementsKind holey_kind = GetHoleyElementsKind(packed_kind);
ElementsKind holey_kind_2 = GetHoleyElementsKind(packed_kind_2);
@@ -282,7 +288,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
GotoIf(Word32Equal(current_elements_kind, Int32Constant(holey_kind_2)),
&already_holey);
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, &check_other_kind,
bailout);
@@ -294,7 +300,8 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
}
void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
- Node* receiver, Node* index, Node* value, UpdateLength update_length) {
+ TNode<JSObject> receiver, TNode<IntPtrT> index, TNode<Object> value,
+ UpdateLength update_length) {
if (update_length != kDontChangeLength) {
TNode<Smi> new_length = SmiTag(Signed(IntPtrAdd(index, IntPtrConstant(1))));
StoreObjectFieldNoWriteBarrier(receiver, JSArray::kLengthOffset, new_length,
@@ -304,10 +311,10 @@ void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
}
void KeyedStoreGenericAssembler::StoreElementWithCapacity(
- Node* receiver, TNode<Map> receiver_map,
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
SloppyTNode<FixedArrayBase> elements, TNode<Word32T> elements_kind,
- TNode<IntPtrT> index, Node* value, Node* context, Label* slow,
- UpdateLength update_length) {
+ TNode<IntPtrT> index, SloppyTNode<Object> value, TNode<Context> context,
+ Label* slow, UpdateLength update_length) {
if (update_length != kDontChangeLength) {
CSA_ASSERT(this, InstanceTypeEqual(LoadMapInstanceType(receiver_map),
JS_ARRAY_TYPE));
@@ -331,8 +338,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// FixedArray backing store -> Smi or object elements.
{
- TNode<IntPtrT> offset = ElementOffsetFromIndex(
- index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> offset =
+ ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize);
// Check if we're about to overwrite the hole. We can safely do that
// only if there can be no setters on the prototype chain.
// If we know that we're storing beyond the previous array length, we
@@ -387,8 +394,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// Transition to the required ElementsKind.
{
Label transition_to_double(this), transition_to_object(this);
- TNode<Context> native_context = LoadNativeContext(context);
- Branch(TaggedEqual(LoadMap(value), HeapNumberMapConstant()),
+ TNode<NativeContext> native_context = LoadNativeContext(context);
+ Branch(TaggedEqual(LoadMap(CAST(value)), HeapNumberMapConstant()),
&transition_to_double, &transition_to_object);
BIND(&transition_to_double);
{
@@ -401,11 +408,11 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
PACKED_SMI_ELEMENTS, target_kind, slow);
// Reload migrated elements.
TNode<FixedArrayBase> double_elements = LoadElements(receiver);
- TNode<IntPtrT> double_offset = ElementOffsetFromIndex(
- index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> double_offset =
+ ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, kHeaderSize);
// Make sure we do not store signalling NaNs into double arrays.
TNode<Float64T> double_value =
- Float64SilenceNaN(LoadHeapNumberValue(value));
+ Float64SilenceNaN(LoadHeapNumberValue(CAST(value)));
StoreNoWriteBarrier(MachineRepresentation::kFloat64, double_elements,
double_offset, double_value);
MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
@@ -434,8 +441,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
&check_cow_elements);
// FixedDoubleArray backing store -> double elements.
{
- TNode<IntPtrT> offset = ElementOffsetFromIndex(
- index, PACKED_DOUBLE_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> offset =
+ ElementOffsetFromIndex(index, PACKED_DOUBLE_ELEMENTS, kHeaderSize);
// Check if we're about to overwrite the hole. We can safely do that
// only if there can be no setters on the prototype chain.
{
@@ -457,7 +464,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// Try to store the value as a double.
{
Label non_number_value(this);
- Node* double_value = TryTaggedToFloat64(value, &non_number_value);
+ TNode<Float64T> double_value =
+ TryTaggedToFloat64(value, &non_number_value);
// Make sure we do not store signalling NaNs into double arrays.
double_value = Float64SilenceNaN(double_value);
@@ -475,7 +483,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
// Transition to object elements.
{
- TNode<Context> native_context = LoadNativeContext(context);
+ TNode<NativeContext> native_context = LoadNativeContext(context);
ElementsKind target_kind = update_length == kBumpLengthWithGap
? HOLEY_ELEMENTS
: PACKED_ELEMENTS;
@@ -483,8 +491,8 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
PACKED_DOUBLE_ELEMENTS, target_kind, slow);
// Reload migrated elements.
TNode<FixedArrayBase> fast_elements = LoadElements(receiver);
- TNode<IntPtrT> fast_offset = ElementOffsetFromIndex(
- index, PACKED_ELEMENTS, INTPTR_PARAMETERS, kHeaderSize);
+ TNode<IntPtrT> fast_offset =
+ ElementOffsetFromIndex(index, PACKED_ELEMENTS, kHeaderSize);
Store(fast_elements, fast_offset, value);
MaybeUpdateLengthAndReturn(receiver, index, value, update_length);
}
@@ -498,8 +506,9 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
void KeyedStoreGenericAssembler::EmitGenericElementStore(
- Node* receiver, TNode<Map> receiver_map, Node* instance_type,
- TNode<IntPtrT> index, Node* value, Node* context, Label* slow) {
+ TNode<JSObject> receiver, TNode<Map> receiver_map,
+ TNode<Uint16T> instance_type, TNode<IntPtrT> index, TNode<Object> value,
+ TNode<Context> context, Label* slow) {
Label if_fast(this), if_in_bounds(this), if_out_of_bounds(this),
if_increment_length_by_one(this), if_bump_length_with_gap(this),
if_grow(this), if_nonfast(this), if_typed_array(this),
@@ -517,7 +526,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
BIND(&if_array);
{
- TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(receiver));
+ TNode<IntPtrT> length = SmiUntag(LoadFastJSArrayLength(CAST(receiver)));
GotoIf(UintPtrLessThan(index, length), &if_in_bounds);
TNode<IntPtrT> capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
GotoIf(UintPtrGreaterThanOrEqual(index, capacity), &if_grow);
@@ -595,32 +604,32 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
- TNode<Map> receiver_map, Node* name, Label* accessor,
- Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
+ TNode<Map> receiver_map, TNode<Name> name, Label* accessor,
+ TVariable<Object>* var_accessor_pair,
+ TVariable<HeapObject>* var_accessor_holder, Label* readonly,
Label* bailout) {
Label ok_to_write(this);
- VARIABLE(var_holder, MachineRepresentation::kTagged);
- var_holder.Bind(LoadMapPrototype(receiver_map));
- VARIABLE(var_holder_map, MachineRepresentation::kTagged);
- var_holder_map.Bind(LoadMap(var_holder.value()));
+ TVARIABLE(HeapObject, var_holder);
+ TVARIABLE(Map, var_holder_map);
+ var_holder = LoadMapPrototype(receiver_map);
+ var_holder_map = LoadMap(var_holder.value());
- Variable* merged_variables[] = {&var_holder, &var_holder_map};
- Label loop(this, arraysize(merged_variables), merged_variables);
+ Label loop(this, {&var_holder, &var_holder_map});
Goto(&loop);
BIND(&loop);
{
- Node* holder = var_holder.value();
+ TNode<HeapObject> holder = var_holder.value();
GotoIf(IsNull(holder), &ok_to_write);
- Node* holder_map = var_holder_map.value();
+ TNode<Map> holder_map = var_holder_map.value();
TNode<Uint16T> instance_type = LoadMapInstanceType(holder_map);
Label next_proto(this);
{
Label found(this), found_fast(this), found_dict(this), found_global(this);
TVARIABLE(HeapObject, var_meta_storage);
TVARIABLE(IntPtrT, var_entry);
- TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
- &found_dict, &found_global, &var_meta_storage,
- &var_entry, &next_proto, bailout);
+ TryLookupProperty(CAST(holder), holder_map, instance_type, name,
+ &found_fast, &found_dict, &found_global,
+ &var_meta_storage, &var_entry, &next_proto, bailout);
BIND(&found_fast);
{
TNode<DescriptorArray> descriptors = CAST(var_meta_storage.value());
@@ -631,10 +640,10 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
// Accessor case.
// TODO(jkummerow): Implement a trimmed-down
// LoadAccessorFromFastObject.
- VARIABLE(var_details, MachineRepresentation::kWord32);
+ TVARIABLE(Uint32T, var_details);
LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
&var_details, var_accessor_pair);
- var_accessor_holder->Bind(holder);
+ *var_accessor_holder = holder;
Goto(accessor);
}
@@ -648,9 +657,9 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
if (accessor != nullptr) {
// Accessor case.
- var_accessor_pair->Bind(
- LoadValueByKeyIndex<NameDictionary>(dictionary, entry));
- var_accessor_holder->Bind(holder);
+ *var_accessor_pair =
+ LoadValueByKeyIndex<NameDictionary>(dictionary, entry);
+ *var_accessor_holder = holder;
Goto(accessor);
} else {
Goto(&ok_to_write);
@@ -666,14 +675,14 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
TNode<Object> value =
LoadObjectField(property_cell, PropertyCell::kValueOffset);
GotoIf(TaggedEqual(value, TheHoleConstant()), &next_proto);
- TNode<Int32T> details = LoadAndUntagToWord32ObjectField(
- property_cell, PropertyCell::kPropertyDetailsRawOffset);
+ TNode<Uint32T> details = Unsigned(LoadAndUntagToWord32ObjectField(
+ property_cell, PropertyCell::kPropertyDetailsRawOffset));
JumpIfDataProperty(details, &ok_to_write, readonly);
if (accessor != nullptr) {
// Accessor case.
- var_accessor_pair->Bind(value);
- var_accessor_holder->Bind(holder);
+ *var_accessor_pair = value;
+ *var_accessor_holder = holder;
Goto(accessor);
} else {
Goto(&ok_to_write);
@@ -686,8 +695,8 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
GotoIf(InstanceTypeEqual(instance_type, JS_TYPED_ARRAY_TYPE), bailout);
TNode<HeapObject> proto = LoadMapPrototype(holder_map);
GotoIf(IsNull(proto), &ok_to_write);
- var_holder.Bind(proto);
- var_holder_map.Bind(LoadMap(proto));
+ var_holder = proto;
+ var_holder_map = LoadMap(proto);
Goto(&loop);
}
BIND(&ok_to_write);
@@ -763,8 +772,10 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
const StoreICParameters* p, ExitPoint* exit_point, Label* slow,
Maybe<LanguageMode> maybe_language_mode) {
CSA_ASSERT(this, IsSimpleObjectMap(receiver_map));
- VARIABLE(var_accessor_pair, MachineRepresentation::kTagged);
- VARIABLE(var_accessor_holder, MachineRepresentation::kTagged);
+ // TODO(rmcilroy) Type as Struct once we use a trimmed down
+ // LoadAccessorFromFastObject instead of LoadPropertyFromFastObject.
+ TVARIABLE(Object, var_accessor_pair);
+ TVARIABLE(HeapObject, var_accessor_holder);
Label fast_properties(this), dictionary_properties(this), accessor(this),
readonly(this);
TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
@@ -792,11 +803,11 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (ShouldCallSetter()) {
// Accessor case.
// TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
- VARIABLE(var_details, MachineRepresentation::kWord32);
+ TVARIABLE(Uint32T, var_details);
LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
name_index, &var_details,
&var_accessor_pair);
- var_accessor_holder.Bind(receiver);
+ var_accessor_holder = receiver;
Goto(&accessor);
} else {
// Handle accessor to data property reconfiguration in runtime.
@@ -836,7 +847,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
TVARIABLE(IntPtrT, var_name_index);
Label dictionary_found(this, &var_name_index), not_found(this);
- TNode<NameDictionary> properties = CAST(LoadSlowProperties(CAST(receiver)));
+ TNode<NameDictionary> properties = CAST(LoadSlowProperties(receiver));
NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
&var_name_index, &not_found);
BIND(&dictionary_found);
@@ -849,9 +860,9 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (ShouldCallSetter()) {
// Accessor case.
- var_accessor_pair.Bind(LoadValueByKeyIndex<NameDictionary>(
- properties, var_name_index.value()));
- var_accessor_holder.Bind(receiver);
+ var_accessor_pair = LoadValueByKeyIndex<NameDictionary>(
+ properties, var_name_index.value());
+ var_accessor_holder = receiver;
Goto(&accessor);
} else {
// We must reconfigure an accessor property to a data property
@@ -870,6 +881,11 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&not_found);
{
+ // TODO(jkummerow): Also add support to correctly handle integer exotic
+ // cases for typed arrays and remove this check here.
+ GotoIf(InstanceTypeEqual(LoadMapInstanceType(receiver_map),
+ JS_TYPED_ARRAY_TYPE),
+ slow);
CheckForAssociatedProtector(name, slow);
Label extensible(this), is_private_symbol(this);
TNode<Uint32T> bitfield3 = LoadMapBitField3(receiver_map);
@@ -909,7 +925,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&accessor);
{
Label not_callable(this);
- Node* accessor_pair = var_accessor_pair.value();
+ TNode<Struct> accessor_pair = CAST(var_accessor_pair.value());
GotoIf(IsAccessorInfoMap(LoadMap(accessor_pair)), slow);
CSA_ASSERT(this, HasInstanceType(accessor_pair, ACCESSOR_PAIR_TYPE));
TNode<HeapObject> setter =
@@ -951,7 +967,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
LanguageMode language_mode;
if (maybe_language_mode.To(&language_mode)) {
if (language_mode == LanguageMode::kStrict) {
- Node* type = Typeof(p->receiver());
+ TNode<String> type = Typeof(p->receiver());
ThrowTypeError(p->context(), MessageTemplate::kStrictReadOnlyProperty,
name, type, p->receiver());
} else {
@@ -969,15 +985,16 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
// Helper that is used by the public KeyedStoreGeneric and by SetProperty.
void KeyedStoreGenericAssembler::KeyedStoreGeneric(
- TNode<Context> context, TNode<Object> receiver, TNode<Object> key,
+ TNode<Context> context, TNode<Object> receiver_maybe_smi, TNode<Object> key,
TNode<Object> value, Maybe<LanguageMode> language_mode) {
TVARIABLE(IntPtrT, var_index);
- TVARIABLE(Object, var_unique, key);
+ TVARIABLE(Name, var_unique);
Label if_index(this), if_unique_name(this), not_internalized(this),
slow(this);
- GotoIf(TaggedIsSmi(receiver), &slow);
- TNode<Map> receiver_map = LoadMap(CAST(receiver));
+ GotoIf(TaggedIsSmi(receiver_maybe_smi), &slow);
+ TNode<HeapObject> receiver = CAST(receiver_maybe_smi);
+ TNode<Map> receiver_map = LoadMap(receiver);
TNode<Uint16T> instance_type = LoadMapInstanceType(receiver_map);
// Receivers requiring non-standard element accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime.
@@ -989,14 +1006,14 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
BIND(&if_index);
{
Comment("integer index");
- EmitGenericElementStore(receiver, receiver_map, instance_type,
+ EmitGenericElementStore(CAST(receiver), receiver_map, instance_type,
var_index.value(), value, context, &slow);
}
BIND(&if_unique_name);
{
Comment("key is unique name");
- StoreICParameters p(context, receiver, var_unique.value(), value, nullptr,
+ StoreICParameters p(context, receiver, var_unique.value(), value, {},
nullptr);
ExitPoint direct_exit(this);
EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit,
@@ -1006,7 +1023,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
BIND(&not_internalized);
{
if (FLAG_internalize_on_the_fly) {
- TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
+ TryInternalizeString(CAST(key), &if_index, &var_index, &if_unique_name,
&var_unique, &slow, &slow);
} else {
Goto(&slow);
@@ -1049,30 +1066,34 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
void KeyedStoreGenericAssembler::StoreIC_NoFeedback() {
using Descriptor = StoreDescriptor;
- Node* receiver = Parameter(Descriptor::kReceiver);
+ TNode<Object> receiver_maybe_smi = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> name = CAST(Parameter(Descriptor::kName));
- Node* value = Parameter(Descriptor::kValue);
- Node* slot = Parameter(Descriptor::kSlot);
- Node* context = Parameter(Descriptor::kContext);
+ TNode<Object> value = CAST(Parameter(Descriptor::kValue));
+ TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
+ TNode<Context> context = CAST(Parameter(Descriptor::kContext));
Label miss(this, Label::kDeferred), store_property(this);
- GotoIf(TaggedIsSmi(receiver), &miss);
- TNode<Map> receiver_map = LoadMap(receiver);
- TNode<Uint16T> 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(IsSpecialReceiverInstanceType(instance_type), &miss);
+ GotoIf(TaggedIsSmi(receiver_maybe_smi), &miss);
+
{
- StoreICParameters p(CAST(context), receiver, name, value, slot,
- UndefinedConstant());
- EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
+ TNode<HeapObject> receiver = CAST(receiver_maybe_smi);
+ TNode<Map> receiver_map = LoadMap(receiver);
+ TNode<Uint16T> 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(IsSpecialReceiverInstanceType(instance_type), &miss);
+ {
+ StoreICParameters p(context, receiver, name, value, slot,
+ UndefinedConstant());
+ EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &miss);
+ }
}
BIND(&miss);
{
TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot,
- UndefinedConstant(), receiver, name);
+ UndefinedConstant(), receiver_maybe_smi, name);
}
}
@@ -1082,7 +1103,7 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
TNode<Name> unique_name,
TNode<Object> value,
LanguageMode language_mode) {
- StoreICParameters p(context, receiver, unique_name, value, nullptr, nullptr);
+ StoreICParameters p(context, receiver, unique_name, value, {}, nullptr);
Label done(this), slow(this, Label::kDeferred);
ExitPoint exit_point(this, [&](Node* result) { Goto(&done); });
diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h
index efee0da80e..8047fe6493 100644
--- a/deps/v8/src/ic/keyed-store-generic.h
+++ b/deps/v8/src/ic/keyed-store-generic.h
@@ -13,9 +13,6 @@ namespace internal {
class KeyedStoreGenericGenerator {
public:
- template <class T>
- using TNode = compiler::TNode<T>;
-
static void Generate(compiler::CodeAssemblerState* state);
// Building block for fast path of Object.assign implementation.
diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc
index 04381bf693..c1d9aea374 100644
--- a/deps/v8/src/ic/stub-cache.cc
+++ b/deps/v8/src/ic/stub-cache.cc
@@ -26,11 +26,10 @@ void StubCache::Initialize() {
Clear();
}
-// Hash algorithm for the primary table. This algorithm is replicated in
-// assembler for every architecture. Returns an index into the table that
+// Hash algorithm for the primary table. This algorithm is replicated in
+// the AccessorAssembler. Returns an index into the table that
// is scaled by 1 << kCacheIndexShift.
int StubCache::PrimaryOffset(Name name, Map map) {
- STATIC_ASSERT(kCacheIndexShift == Name::kHashShift);
// Compute the hash of the name (use entire hash field).
DCHECK(name.HasHashCode());
uint32_t field = name.hash_field();
diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h
index 87acc0e007..dc3317588d 100644
--- a/deps/v8/src/ic/stub-cache.h
+++ b/deps/v8/src/ic/stub-cache.h
@@ -78,10 +78,15 @@ class V8_EXPORT_PRIVATE StubCache {
Isolate* isolate() { return isolate_; }
- // Setting the entry size such that the index is shifted by Name::kHashShift
- // is convenient; shifting down the length field (to extract the hash code)
- // automatically discards the hash bit field.
- static const int kCacheIndexShift = Name::kHashShift;
+ // Ideally we would set kCacheIndexShift to Name::kHashShift, such that
+ // the bit field inside the hash field gets shifted out implicitly. However,
+ // sizeof(Entry) needs to be a multiple of 1 << kCacheIndexShift, and it
+ // isn't clear whether letting one bit of the bit field leak into the index
+ // computation is bad enough to warrant an additional shift to get rid of it.
+ static const int kCacheIndexShift = 2;
+ // The purpose of the static assert is to make us reconsider this choice
+ // if the bit field ever grows even more.
+ STATIC_ASSERT(kCacheIndexShift == Name::kHashShift - 1);
static const int kPrimaryTableBits = 11;
static const int kPrimaryTableSize = (1 << kPrimaryTableBits);
@@ -125,7 +130,10 @@ class V8_EXPORT_PRIVATE StubCache {
// of sizeof(Entry). This makes it easier to avoid making mistakes
// in the hashed offset computations.
static Entry* entry(Entry* table, int offset) {
- const int multiplier = sizeof(*table) >> Name::kHashShift;
+ // The size of {Entry} must be a multiple of 1 << kCacheIndexShift.
+ STATIC_ASSERT((sizeof(*table) >> kCacheIndexShift) << kCacheIndexShift ==
+ sizeof(*table));
+ const int multiplier = sizeof(*table) >> kCacheIndexShift;
return reinterpret_cast<Entry*>(reinterpret_cast<Address>(table) +
offset * multiplier);
}