summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
authorUjjwal Sharma <usharma1998@gmail.com>2019-03-15 18:35:06 +0530
committerRefael Ackermann <refack@gmail.com>2019-03-28 16:36:18 -0400
commitf579e1194046c50f2e6bb54348d48c8e7d1a53cf (patch)
tree9125787c758358365f74f9fd9673c14f57e67870 /deps/v8/src/ic
parent2c73868b0471fbd4038f500d076df056cbf697fe (diff)
downloadandroid-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.tar.gz
android-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.tar.bz2
android-node-v8-f579e1194046c50f2e6bb54348d48c8e7d1a53cf.zip
deps: update V8 to 7.4.288.13
PR-URL: https://github.com/nodejs/node/pull/26685 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michaƫl Zasso <targos@protonmail.com> Reviewed-By: Refael Ackermann <refack@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc893
-rw-r--r--deps/v8/src/ic/accessor-assembler.h46
-rw-r--r--deps/v8/src/ic/handler-configuration.h4
-rw-r--r--deps/v8/src/ic/ic.cc491
-rw-r--r--deps/v8/src/ic/ic.h44
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc94
-rw-r--r--deps/v8/src/ic/stub-cache.cc9
-rw-r--r--deps/v8/src/ic/stub-cache.h4
8 files changed, 934 insertions, 651 deletions
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index 0bbc9391b0..bc636e4164 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -99,84 +99,48 @@ TNode<MaybeObject> AccessorAssembler::TryMonomorphicCase(
void AccessorAssembler::HandlePolymorphicCase(
Node* receiver_map, TNode<WeakFixedArray> feedback, Label* if_handler,
- TVariable<MaybeObject>* var_handler, Label* if_miss,
- int min_feedback_capacity) {
+ TVariable<MaybeObject>* var_handler, Label* if_miss) {
Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
- // Deferred so the unrolled case can omit frame construction in bytecode
- // handler.
- Label loop(this, Label::kDeferred);
-
// Iterate {feedback} array.
const int kEntrySize = 2;
- // Loading feedback's length is delayed until we need it when looking past
- // the first {min_feedback_capacity} (map, handler) pairs.
- Node* length = nullptr;
- CSA_ASSERT(this, SmiGreaterThanOrEqual(
- LoadWeakFixedArrayLength(feedback),
- SmiConstant(min_feedback_capacity * kEntrySize)));
-
- const int kUnrolledIterations = IC::kMaxPolymorphicMapCount;
- for (int i = 0; i < kUnrolledIterations; i++) {
- int map_index = i * kEntrySize;
- int handler_index = i * kEntrySize + 1;
-
- if (i >= min_feedback_capacity) {
- if (length == nullptr) length = LoadWeakFixedArrayLength(feedback);
- GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), CAST(length)),
- if_miss);
- }
+ // Load the {feedback} array length.
+ TNode<IntPtrT> length = LoadAndUntagWeakFixedArrayLength(feedback);
+ CSA_ASSERT(this, IntPtrLessThanOrEqual(IntPtrConstant(1), length));
- Label next_entry(this);
+ // This is a hand-crafted loop that only compares against the {length}
+ // in the end, since we already know that we will have at least a single
+ // entry in the {feedback} array anyways.
+ TVARIABLE(IntPtrT, var_index, IntPtrConstant(0));
+ Label loop(this, &var_index), loop_next(this);
+ Goto(&loop);
+ BIND(&loop);
+ {
TNode<MaybeObject> maybe_cached_map =
- LoadWeakFixedArrayElement(feedback, map_index);
+ LoadWeakFixedArrayElement(feedback, var_index.value());
CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
- &next_entry);
+ &loop_next);
// Found, now call handler.
TNode<MaybeObject> handler =
- LoadWeakFixedArrayElement(feedback, handler_index);
+ LoadWeakFixedArrayElement(feedback, var_index.value(), kTaggedSize);
*var_handler = handler;
Goto(if_handler);
- BIND(&next_entry);
+ BIND(&loop_next);
+ var_index =
+ Signed(IntPtrAdd(var_index.value(), IntPtrConstant(kEntrySize)));
+ Branch(IntPtrLessThan(var_index.value(), length), &loop, if_miss);
}
- Goto(&loop);
-
- // Loop from {kUnrolledIterations}*kEntrySize to {length}.
- BIND(&loop);
- Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize);
- Node* end_index = LoadAndUntagWeakFixedArrayLength(feedback);
- BuildFastLoop(
- start_index, end_index,
- [this, receiver_map, feedback, if_handler, var_handler](Node* index) {
- Label next_entry(this);
- TNode<MaybeObject> maybe_cached_map =
- LoadWeakFixedArrayElement(feedback, index);
- CSA_ASSERT(this, IsWeakOrCleared(maybe_cached_map));
- GotoIf(IsNotWeakReferenceTo(maybe_cached_map, CAST(receiver_map)),
- &next_entry);
-
- // Found, now call handler.
- TNode<MaybeObject> handler =
- LoadWeakFixedArrayElement(feedback, index, kTaggedSize);
- *var_handler = handler;
- Goto(if_handler);
-
- BIND(&next_entry);
- },
- kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
- // The loop falls through if no handler was found.
- Goto(if_miss);
}
void AccessorAssembler::HandleLoadICHandlerCase(
const LoadICParameters* p, TNode<Object> handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
- ElementSupport support_elements) {
+ ElementSupport support_elements, LoadAccessMode access_mode) {
Comment("have_handler");
VARIABLE(var_holder, MachineRepresentation::kTagged, p->holder);
@@ -195,14 +159,15 @@ void AccessorAssembler::HandleLoadICHandlerCase(
{
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
handler, miss, exit_point, on_nonexistent,
- support_elements);
+ support_elements, access_mode);
}
BIND(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(CAST(handler))), &call_handler);
HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss, exit_point, ic_mode);
+ &if_smi_handler, miss, exit_point, ic_mode,
+ access_mode);
}
BIND(&call_handler);
@@ -276,8 +241,8 @@ void AccessorAssembler::HandleLoadAccessor(
BIND(&load);
Callable callable = CodeFactory::CallApiCallback(isolate());
TNode<IntPtrT> argc = IntPtrConstant(0);
- exit_point->Return(CallStub(callable, nullptr, context, callback, argc,
- data, api_holder.value(), p->receiver));
+ exit_point->Return(CallStub(callable, context, callback, argc, data,
+ api_holder.value(), p->receiver));
}
BIND(&runtime);
@@ -343,7 +308,8 @@ TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
void AccessorAssembler::HandleLoadICSmiHandlerCase(
const LoadICParameters* p, Node* holder, SloppyTNode<Smi> smi_handler,
SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
- OnNonExistent on_nonexistent, ElementSupport support_elements) {
+ OnNonExistent on_nonexistent, ElementSupport support_elements,
+ LoadAccessMode access_mode) {
VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
@@ -354,8 +320,17 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
Label if_element(this), if_indexed_string(this), if_property(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
&if_element);
- Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kIndexedString)),
- &if_indexed_string, &if_property);
+
+ if (access_mode == LoadAccessMode::kHas) {
+ CSA_ASSERT(this,
+ WordNotEqual(handler_kind,
+ IntPtrConstant(LoadHandler::kIndexedString)));
+ Goto(&if_property);
+ } else {
+ Branch(
+ WordEqual(handler_kind, IntPtrConstant(LoadHandler::kIndexedString)),
+ &if_indexed_string, &if_property);
+ }
BIND(&if_element);
Comment("element_load");
@@ -370,7 +345,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
EmitElementLoad(holder, elements, elements_kind, intptr_index,
is_jsarray_condition, &if_hole, &rebox_double,
&var_double_value, &unimplemented_elements_kind, &if_oob,
- miss, exit_point);
+ miss, exit_point, access_mode);
BIND(&unimplemented_elements_kind);
{
@@ -404,41 +379,63 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
miss);
BIND(&return_undefined);
- exit_point->Return(UndefinedConstant());
+ exit_point->Return(access_mode == LoadAccessMode::kHas
+ ? FalseConstant()
+ : UndefinedConstant());
}
BIND(&if_hole);
{
Comment("convert hole");
+
GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
GotoIf(IsNoElementsProtectorCellInvalid(), miss);
- exit_point->Return(UndefinedConstant());
+ exit_point->Return(access_mode == LoadAccessMode::kHas
+ ? FalseConstant()
+ : UndefinedConstant());
}
- BIND(&if_indexed_string);
- {
- Label if_oob(this, Label::kDeferred);
-
- Comment("indexed string");
- Node* intptr_index = TryToIntptr(p->name, miss);
- Node* length = LoadStringLengthAsWord(holder);
- GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
- TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
- TNode<String> result = StringFromSingleCharCode(code);
- Return(result);
-
- BIND(&if_oob);
- Node* allow_out_of_bounds =
- IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
- GotoIfNot(allow_out_of_bounds, miss);
- GotoIf(IsNoElementsProtectorCellInvalid(), miss);
- Return(UndefinedConstant());
+ if (access_mode != LoadAccessMode::kHas) {
+ BIND(&if_indexed_string);
+ {
+ Label if_oob(this, Label::kDeferred);
+
+ Comment("indexed string");
+ Node* intptr_index = TryToIntptr(p->name, miss);
+ Node* length = LoadStringLengthAsWord(holder);
+ GotoIf(UintPtrGreaterThanOrEqual(intptr_index, length), &if_oob);
+ TNode<Int32T> code = StringCharCodeAt(holder, intptr_index);
+ TNode<String> result = StringFromSingleCharCode(code);
+ Return(result);
+
+ BIND(&if_oob);
+ Node* allow_out_of_bounds =
+ IsSetWord<LoadHandler::AllowOutOfBoundsBits>(handler_word);
+ GotoIfNot(allow_out_of_bounds, miss);
+ GotoIf(IsNoElementsProtectorCellInvalid(), miss);
+ Return(UndefinedConstant());
+ }
}
BIND(&if_property);
Comment("property_load");
}
+ if (access_mode == LoadAccessMode::kHas) {
+ HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss,
+ exit_point);
+ } else {
+ HandleLoadICSmiHandlerLoadNamedCase(
+ p, holder, handler_kind, handler_word, &rebox_double, &var_double_value,
+ handler, miss, exit_point, on_nonexistent, support_elements);
+ }
+}
+
+void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
+ const LoadICParameters* 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) {
Label constant(this), field(this), normal(this, Label::kDeferred),
interceptor(this, Label::kDeferred), nonexistent(this),
accessor(this, Label::kDeferred), global(this, Label::kDeferred),
@@ -478,7 +475,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
&module_export, &interceptor);
BIND(&field);
- HandleLoadField(holder, handler_word, &var_double_value, &rebox_double,
+ HandleLoadField(holder, handler_word, var_double_value, rebox_double,
exit_point);
BIND(&nonexistent);
@@ -625,8 +622,88 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
}
}
- BIND(&rebox_double);
- exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
+ BIND(rebox_double);
+ exit_point->Return(AllocateHeapNumberWithValue(var_double_value->value()));
+}
+
+void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
+ const LoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
+ Label* miss, ExitPoint* exit_point) {
+ Label return_true(this), return_false(this), return_lookup(this),
+ normal(this), global(this);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
+ &return_true);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
+ &return_true);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
+ &return_false);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
+ &normal);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
+ &return_true);
+
+ GotoIf(
+ WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNativeDataProperty)),
+ &return_true);
+
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kApiGetter)),
+ &return_true);
+
+ GotoIf(WordEqual(handler_kind,
+ IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
+ &return_true);
+
+ Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
+ &return_lookup);
+
+ BIND(&return_true);
+ exit_point->Return(TrueConstant());
+
+ BIND(&return_false);
+ exit_point->Return(FalseConstant());
+
+ BIND(&return_lookup);
+ {
+ CSA_ASSERT(
+ this,
+ Word32Or(
+ WordEqual(handler_kind, IntPtrConstant(LoadHandler::kInterceptor)),
+ Word32Or(
+ WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)),
+ WordEqual(handler_kind,
+ IntPtrConstant(LoadHandler::kModuleExport)))));
+ exit_point->ReturnCallStub(
+ Builtins::CallableFor(isolate(), Builtins::kHasProperty), p->context,
+ p->receiver, p->name);
+ }
+
+ BIND(&normal);
+ {
+ Comment("has_normal");
+ TNode<NameDictionary> properties = CAST(LoadSlowProperties(holder));
+ TVARIABLE(IntPtrT, var_name_index);
+ Label found(this);
+ NameDictionaryLookup<NameDictionary>(properties, CAST(p->name), &found,
+ &var_name_index, miss);
+
+ BIND(&found);
+ exit_point->Return(TrueConstant());
+ }
+
+ BIND(&global);
+ {
+ CSA_ASSERT(this, IsPropertyCell(holder));
+ // Ensure the property cell doesn't contain the hole.
+ Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
+ GotoIf(IsTheHole(value), miss);
+
+ exit_point->Return(TrueConstant());
+ }
}
// Performs actions common to both load and store handlers:
@@ -743,7 +820,7 @@ Node* AccessorAssembler::HandleProtoHandler(
void AccessorAssembler::HandleLoadICProtoHandler(
const LoadICParameters* p, Node* handler, Variable* var_holder,
Variable* var_smi_handler, Label* if_smi_handler, Label* miss,
- ExitPoint* exit_point, ICMode ic_mode) {
+ ExitPoint* exit_point, ICMode ic_mode, LoadAccessMode access_mode) {
DCHECK_EQ(MachineRepresentation::kTagged, var_holder->rep());
DCHECK_EQ(MachineRepresentation::kTagged, var_smi_handler->rep());
@@ -753,14 +830,18 @@ void AccessorAssembler::HandleLoadICProtoHandler(
nullptr,
// on_found_on_receiver
[=](Node* properties, Node* name_index) {
- VARIABLE(var_details, MachineRepresentation::kWord32);
- VARIABLE(var_value, MachineRepresentation::kTagged);
- LoadPropertyFromNameDictionary(properties, name_index, &var_details,
- &var_value);
- Node* value =
- CallGetterIfAccessor(var_value.value(), var_details.value(),
- p->context, p->receiver, miss);
- exit_point->Return(value);
+ if (access_mode == LoadAccessMode::kHas) {
+ exit_point->Return(TrueConstant());
+ } else {
+ VARIABLE(var_details, MachineRepresentation::kWord32);
+ VARIABLE(var_value, MachineRepresentation::kTagged);
+ LoadPropertyFromNameDictionary(properties, name_index, &var_details,
+ &var_value);
+ Node* value =
+ CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context, p->receiver, miss);
+ exit_point->Return(value);
+ }
},
miss, ic_mode);
@@ -831,13 +912,8 @@ void AccessorAssembler::HandleStoreICNativeDataProperty(
Node* accessor_info = LoadDescriptorValue(LoadMap(holder), descriptor);
CSA_CHECK(this, IsAccessorInfo(accessor_info));
- // TODO(8580): Get the language mode lazily when required to avoid the
- // computation of GetLanguageMode here. Also make the computation of
- // language mode not dependent on vector.
- Node* language_mode = GetLanguageMode(p->vector, p->slot);
-
TailCallRuntime(Runtime::kStoreCallbackProperty, p->context, p->receiver,
- holder, accessor_info, p->name, p->value, language_mode);
+ holder, accessor_info, p->name, p->value);
}
void AccessorAssembler::HandleStoreICHandlerCase(
@@ -1087,6 +1163,11 @@ void AccessorAssembler::CheckFieldType(TNode<DescriptorArray> descriptors,
BIND(&all_fine);
}
+TNode<BoolT> AccessorAssembler::IsPropertyDetailsConst(Node* 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, Node* value, Label* slow,
@@ -1103,15 +1184,6 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
BIND(&if_field);
{
- if (FLAG_track_constant_fields && !do_transitioning_store) {
- // TODO(ishell): Taking the slow path is not necessary if new and old
- // values are identical.
- GotoIf(Word32Equal(
- DecodeWord32<PropertyDetails::ConstnessField>(details),
- Int32Constant(static_cast<int32_t>(VariableMode::kConst))),
- slow);
- }
-
Node* representation =
DecodeWord32<PropertyDetails::RepresentationField>(details);
@@ -1141,6 +1213,13 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
if (FLAG_unbox_double_fields) {
if (do_transitioning_store) {
StoreMap(object, object_map);
+ } else if (FLAG_track_constant_fields) {
+ Label if_mutable(this);
+ GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
+ Node* current_value =
+ LoadObjectField(object, field_offset, MachineType::Float64());
+ Branch(Float64Equal(current_value, double_value), &done, slow);
+ BIND(&if_mutable);
}
StoreObjectFieldNoWriteBarrier(object, field_offset, double_value,
MachineRepresentation::kFloat64);
@@ -1152,6 +1231,13 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
StoreObjectField(object, field_offset, mutable_heap_number);
} else {
Node* mutable_heap_number = LoadObjectField(object, field_offset);
+ if (FLAG_track_constant_fields) {
+ Label if_mutable(this);
+ GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
+ Node* current_value = LoadHeapNumberValue(mutable_heap_number);
+ Branch(Float64Equal(current_value, double_value), &done, slow);
+ BIND(&if_mutable);
+ }
StoreHeapNumberValue(mutable_heap_number, double_value);
}
}
@@ -1162,6 +1248,13 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
{
if (do_transitioning_store) {
StoreMap(object, object_map);
+ } else if (FLAG_track_constant_fields) {
+ Label if_mutable(this);
+ GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
+ Node* current_value =
+ LoadObjectField(object, field_offset, MachineType::AnyTagged());
+ Branch(WordEqual(current_value, value), &done, slow);
+ BIND(&if_mutable);
}
StoreObjectField(object, field_offset, value);
Goto(&done);
@@ -1211,11 +1304,26 @@ void AccessorAssembler::OverwriteExistingFastDataProperty(
Node* mutable_heap_number =
LoadPropertyArrayElement(properties, backing_store_index);
Node* double_value = ChangeNumberToFloat64(value);
+ if (FLAG_track_constant_fields) {
+ Label if_mutable(this);
+ GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
+ Node* current_value = LoadHeapNumberValue(mutable_heap_number);
+ Branch(Float64Equal(current_value, double_value), &done, slow);
+ BIND(&if_mutable);
+ }
StoreHeapNumberValue(mutable_heap_number, double_value);
Goto(&done);
}
BIND(&tagged_rep);
{
+ if (FLAG_track_constant_fields) {
+ Label if_mutable(this);
+ GotoIfNot(IsPropertyDetailsConst(details), &if_mutable);
+ Node* current_value =
+ LoadPropertyArrayElement(properties, backing_store_index);
+ Branch(WordEqual(current_value, value), &done, slow);
+ BIND(&if_mutable);
+ }
StorePropertyArrayElement(properties, backing_store_index, value);
Goto(&done);
}
@@ -1422,7 +1530,7 @@ void AccessorAssembler::HandleStoreICProtoHandler(
BIND(&store);
Callable callable = CodeFactory::CallApiCallback(isolate());
TNode<IntPtrT> argc = IntPtrConstant(1);
- Return(CallStub(callable, nullptr, context, callback, argc, data,
+ Return(CallStub(callable, context, callback, argc, data,
api_holder.value(), p->receiver, p->value));
}
@@ -1434,17 +1542,6 @@ void AccessorAssembler::HandleStoreICProtoHandler(
}
}
-Node* AccessorAssembler::GetLanguageMode(Node* vector, Node* slot) {
- VARIABLE(var_language_mode, MachineRepresentation::kTaggedSigned,
- SmiConstant(LanguageMode::kStrict));
- Label language_mode_determined(this);
- BranchIfStrictMode(vector, slot, &language_mode_determined);
- var_language_mode.Bind(SmiConstant(LanguageMode::kSloppy));
- Goto(&language_mode_determined);
- BIND(&language_mode_determined);
- return var_language_mode.value();
-}
-
void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
Node* proxy, Label* miss,
ElementSupport support_elements) {
@@ -1454,18 +1551,13 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
Label if_index(this), if_unique_name(this),
to_name_failed(this, Label::kDeferred);
- // TODO(8580): Get the language mode lazily when required to avoid the
- // computation of GetLanguageMode here. Also make the computation of
- // language mode not dependent on vector.
- Node* language_mode = GetLanguageMode(p->vector, p->slot);
-
if (support_elements == kSupportElements) {
TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
&to_name_failed);
BIND(&if_unique_name);
CallBuiltin(Builtins::kProxySetProperty, p->context, proxy,
- var_unique.value(), p->value, p->receiver, language_mode);
+ var_unique.value(), p->value, p->receiver);
Return(p->value);
// The index case is handled earlier by the runtime.
@@ -1476,11 +1568,11 @@ void AccessorAssembler::HandleStoreToProxy(const StoreICParameters* p,
BIND(&to_name_failed);
TailCallRuntime(Runtime::kSetPropertyWithReceiver, p->context, proxy,
- p->name, p->value, p->receiver, language_mode);
+ p->name, p->value, p->receiver);
} else {
Node* name = CallBuiltin(Builtins::kToName, p->context, p->name);
TailCallBuiltin(Builtins::kProxySetProperty, p->context, proxy, name,
- p->value, p->receiver, language_mode);
+ p->value, p->receiver);
}
}
@@ -1789,7 +1881,7 @@ void AccessorAssembler::EmitElementLoad(
SloppyTNode<IntPtrT> intptr_index, Node* is_jsarray_condition,
Label* if_hole, Label* rebox_double, Variable* var_double_value,
Label* unimplemented_elements_kind, Label* out_of_bounds, Label* miss,
- ExitPoint* exit_point) {
+ ExitPoint* exit_point, LoadAccessMode access_mode) {
Label if_typed_array(this), if_fast_packed(this), if_fast_holey(this),
if_fast_double(this), if_fast_holey_double(this), if_nonfast(this),
if_dictionary(this);
@@ -1821,23 +1913,31 @@ void AccessorAssembler::EmitElementLoad(
BIND(&if_fast_packed);
{
Comment("fast packed elements");
- exit_point->Return(LoadFixedArrayElement(CAST(elements), intptr_index));
+ exit_point->Return(
+ access_mode == LoadAccessMode::kHas
+ ? TrueConstant()
+ : UnsafeLoadFixedArrayElement(CAST(elements), intptr_index));
}
BIND(&if_fast_holey);
{
Comment("fast holey elements");
- Node* element = LoadFixedArrayElement(CAST(elements), intptr_index);
+ Node* element = UnsafeLoadFixedArrayElement(CAST(elements), intptr_index);
GotoIf(WordEqual(element, TheHoleConstant()), if_hole);
- exit_point->Return(element);
+ exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
+ : element);
}
BIND(&if_fast_double);
{
Comment("packed double elements");
- var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
- MachineType::Float64()));
- Goto(rebox_double);
+ if (access_mode == LoadAccessMode::kHas) {
+ exit_point->Return(TrueConstant());
+ } else {
+ var_double_value->Bind(LoadFixedDoubleArrayElement(
+ elements, intptr_index, MachineType::Float64()));
+ Goto(rebox_double);
+ }
}
BIND(&if_fast_holey_double);
@@ -1846,8 +1946,12 @@ void AccessorAssembler::EmitElementLoad(
Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
MachineType::Float64(), 0,
INTPTR_PARAMETERS, if_hole);
- var_double_value->Bind(value);
- Goto(rebox_double);
+ if (access_mode == LoadAccessMode::kHas) {
+ exit_point->Return(TrueConstant());
+ } else {
+ var_double_value->Bind(value);
+ Goto(rebox_double);
+ }
}
BIND(&if_nonfast);
@@ -1869,7 +1973,8 @@ void AccessorAssembler::EmitElementLoad(
TNode<Object> value = BasicLoadNumberDictionaryElement(
CAST(elements), intptr_index, miss, if_hole);
- exit_point->Return(value);
+ exit_point->Return(access_mode == LoadAccessMode::kHas ? TrueConstant()
+ : value);
}
BIND(&if_typed_array);
@@ -1882,97 +1987,101 @@ void AccessorAssembler::EmitElementLoad(
// Bounds check.
Node* length = SmiUntag(LoadJSTypedArrayLength(CAST(object)));
GotoIfNot(UintPtrLessThan(intptr_index, length), out_of_bounds);
-
- Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements));
-
- Label uint8_elements(this), int8_elements(this), uint16_elements(this),
- int16_elements(this), uint32_elements(this), int32_elements(this),
- float32_elements(this), float64_elements(this), bigint64_elements(this),
- biguint64_elements(this);
- Label* elements_kind_labels[] = {
- &uint8_elements, &uint8_elements, &int8_elements,
- &uint16_elements, &int16_elements, &uint32_elements,
- &int32_elements, &float32_elements, &float64_elements,
- &bigint64_elements, &biguint64_elements};
- int32_t elements_kinds[] = {
- UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
- UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
- INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS,
- BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS};
- const size_t kTypedElementsKindCount =
- LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
- FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
- DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
- DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
- Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
- kTypedElementsKindCount);
- BIND(&uint8_elements);
- {
- Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
- Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
- exit_point->Return(SmiFromInt32(element));
- }
- BIND(&int8_elements);
- {
- Comment("INT8_ELEMENTS");
- Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
- exit_point->Return(SmiFromInt32(element));
- }
- BIND(&uint16_elements);
- {
- Comment("UINT16_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(1));
- Node* element = Load(MachineType::Uint16(), backing_store, index);
- exit_point->Return(SmiFromInt32(element));
- }
- BIND(&int16_elements);
- {
- Comment("INT16_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(1));
- Node* element = Load(MachineType::Int16(), backing_store, index);
- exit_point->Return(SmiFromInt32(element));
- }
- BIND(&uint32_elements);
- {
- Comment("UINT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Uint32(), backing_store, index);
- exit_point->Return(ChangeUint32ToTagged(element));
- }
- BIND(&int32_elements);
- {
- Comment("INT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Int32(), backing_store, index);
- exit_point->Return(ChangeInt32ToTagged(element));
- }
- BIND(&float32_elements);
- {
- Comment("FLOAT32_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(2));
- Node* element = Load(MachineType::Float32(), backing_store, index);
- var_double_value->Bind(ChangeFloat32ToFloat64(element));
- Goto(rebox_double);
- }
- BIND(&float64_elements);
- {
- Comment("FLOAT64_ELEMENTS");
- Node* index = WordShl(intptr_index, IntPtrConstant(3));
- Node* element = Load(MachineType::Float64(), backing_store, index);
- var_double_value->Bind(element);
- Goto(rebox_double);
- }
- BIND(&bigint64_elements);
- {
- Comment("BIGINT64_ELEMENTS");
- exit_point->Return(LoadFixedTypedArrayElementAsTagged(
- backing_store, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
- }
- BIND(&biguint64_elements);
- {
- Comment("BIGUINT64_ELEMENTS");
- exit_point->Return(LoadFixedTypedArrayElementAsTagged(
- backing_store, intptr_index, BIGUINT64_ELEMENTS, INTPTR_PARAMETERS));
+ if (access_mode == LoadAccessMode::kHas) {
+ exit_point->Return(TrueConstant());
+ } else {
+ Node* backing_store = LoadFixedTypedArrayBackingStore(CAST(elements));
+
+ Label uint8_elements(this), int8_elements(this), uint16_elements(this),
+ int16_elements(this), uint32_elements(this), int32_elements(this),
+ float32_elements(this), float64_elements(this),
+ bigint64_elements(this), biguint64_elements(this);
+ Label* elements_kind_labels[] = {
+ &uint8_elements, &uint8_elements, &int8_elements,
+ &uint16_elements, &int16_elements, &uint32_elements,
+ &int32_elements, &float32_elements, &float64_elements,
+ &bigint64_elements, &biguint64_elements};
+ int32_t elements_kinds[] = {
+ UINT8_ELEMENTS, UINT8_CLAMPED_ELEMENTS, INT8_ELEMENTS,
+ UINT16_ELEMENTS, INT16_ELEMENTS, UINT32_ELEMENTS,
+ INT32_ELEMENTS, FLOAT32_ELEMENTS, FLOAT64_ELEMENTS,
+ BIGINT64_ELEMENTS, BIGUINT64_ELEMENTS};
+ const size_t kTypedElementsKindCount =
+ LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND -
+ FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND + 1;
+ DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kinds));
+ DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
+ Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
+ kTypedElementsKindCount);
+ BIND(&uint8_elements);
+ {
+ Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
+ Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
+ exit_point->Return(SmiFromInt32(element));
+ }
+ BIND(&int8_elements);
+ {
+ Comment("INT8_ELEMENTS");
+ Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
+ exit_point->Return(SmiFromInt32(element));
+ }
+ BIND(&uint16_elements);
+ {
+ Comment("UINT16_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(1));
+ Node* element = Load(MachineType::Uint16(), backing_store, index);
+ exit_point->Return(SmiFromInt32(element));
+ }
+ BIND(&int16_elements);
+ {
+ Comment("INT16_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(1));
+ Node* element = Load(MachineType::Int16(), backing_store, index);
+ exit_point->Return(SmiFromInt32(element));
+ }
+ BIND(&uint32_elements);
+ {
+ Comment("UINT32_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ Node* element = Load(MachineType::Uint32(), backing_store, index);
+ exit_point->Return(ChangeUint32ToTagged(element));
+ }
+ BIND(&int32_elements);
+ {
+ Comment("INT32_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ Node* element = Load(MachineType::Int32(), backing_store, index);
+ exit_point->Return(ChangeInt32ToTagged(element));
+ }
+ BIND(&float32_elements);
+ {
+ Comment("FLOAT32_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(2));
+ Node* element = Load(MachineType::Float32(), backing_store, index);
+ var_double_value->Bind(ChangeFloat32ToFloat64(element));
+ Goto(rebox_double);
+ }
+ BIND(&float64_elements);
+ {
+ Comment("FLOAT64_ELEMENTS");
+ Node* index = WordShl(intptr_index, IntPtrConstant(3));
+ Node* element = Load(MachineType::Float64(), backing_store, index);
+ var_double_value->Bind(element);
+ Goto(rebox_double);
+ }
+ BIND(&bigint64_elements);
+ {
+ Comment("BIGINT64_ELEMENTS");
+ exit_point->Return(LoadFixedTypedArrayElementAsTagged(
+ backing_store, intptr_index, BIGINT64_ELEMENTS, INTPTR_PARAMETERS));
+ }
+ BIND(&biguint64_elements);
+ {
+ Comment("BIGUINT64_ELEMENTS");
+ exit_point->Return(LoadFixedTypedArrayElementAsTagged(
+ backing_store, intptr_index, BIGUINT64_ELEMENTS,
+ INTPTR_PARAMETERS));
+ }
}
}
}
@@ -1990,43 +2099,6 @@ void AccessorAssembler::NameDictionaryNegativeLookup(Node* object,
BIND(&done);
}
-void AccessorAssembler::BranchIfStrictMode(Node* vector, Node* slot,
- Label* if_strict) {
- Node* sfi =
- LoadObjectField(vector, FeedbackVector::kSharedFunctionInfoOffset);
- TNode<FeedbackMetadata> metadata = CAST(LoadObjectField(
- sfi, SharedFunctionInfo::kOuterScopeInfoOrFeedbackMetadataOffset));
- Node* slot_int = SmiToInt32(slot);
-
- // See VectorICComputer::index().
- const int kItemsPerWord = FeedbackMetadata::VectorICComputer::kItemsPerWord;
- Node* word_index = Int32Div(slot_int, Int32Constant(kItemsPerWord));
- Node* word_offset = Int32Mod(slot_int, Int32Constant(kItemsPerWord));
-
- int32_t first_item = FeedbackMetadata::kHeaderSize - kHeapObjectTag;
- Node* offset =
- ElementOffsetFromIndex(ChangeInt32ToIntPtr(word_index), UINT32_ELEMENTS,
- INTPTR_PARAMETERS, first_item);
-
- Node* data = Load(MachineType::Int32(), metadata, offset);
-
- // See VectorICComputer::decode().
- const int kBitsPerItem = FeedbackMetadata::kFeedbackSlotKindBits;
- Node* shift = Int32Mul(word_offset, Int32Constant(kBitsPerItem));
- const int kMask = FeedbackMetadata::VectorICComputer::kMask;
- Node* kind = Word32And(Word32Shr(data, shift), Int32Constant(kMask));
-
- STATIC_ASSERT(FeedbackSlotKind::kStoreGlobalSloppy <=
- FeedbackSlotKind::kLastSloppyKind);
- STATIC_ASSERT(FeedbackSlotKind::kStoreKeyedSloppy <=
- FeedbackSlotKind::kLastSloppyKind);
- STATIC_ASSERT(FeedbackSlotKind::kStoreNamedSloppy <=
- FeedbackSlotKind::kLastSloppyKind);
- GotoIfNot(Int32LessThanOrEqual(kind, Int32Constant(static_cast<int>(
- FeedbackSlotKind::kLastSloppyKind))),
- if_strict);
-}
-
void AccessorAssembler::InvalidateValidityCellIfPrototype(Node* map,
Node* bitfield2) {
Label is_prototype(this), cont(this);
@@ -2141,10 +2213,10 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
// for a handler in the stub cache.
TNode<DescriptorArray> descriptors = LoadMapDescriptors(receiver_map);
- Label if_descriptor_found(this), stub_cache(this);
+ Label if_descriptor_found(this), try_stub_cache(this);
TVARIABLE(IntPtrT, var_name_index);
- Label* notfound =
- use_stub_cache == kUseStubCache ? &stub_cache : &lookup_prototype_chain;
+ Label* notfound = use_stub_cache == kUseStubCache ? &try_stub_cache
+ : &lookup_prototype_chain;
DescriptorLookup(p->name, descriptors, bitfield3, &if_descriptor_found,
&var_name_index, notfound);
@@ -2157,6 +2229,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
}
if (use_stub_cache == kUseStubCache) {
+ Label stub_cache(this);
+ BIND(&try_stub_cache);
+ // When there is no feedback vector don't use stub cache.
+ GotoIfNot(IsUndefined(p->vector), &stub_cache);
+ // Fall back to the slow path for private symbols.
+ Branch(IsPrivateSymbol(p->name), slow, &lookup_prototype_chain);
+
BIND(&stub_cache);
Comment("stub cache probe for fast property load");
TVARIABLE(MaybeObject, var_handler);
@@ -2288,7 +2367,10 @@ Node* AccessorAssembler::StubCachePrimaryOffset(Node* name, Node* map) {
// Using only the low bits in 64-bit mode is unlikely to increase the
// risk of collision even if the heap is spread over an area larger than
// 4Gb (and not at all if it isn't).
- Node* map32 = TruncateIntPtrToInt32(BitcastTaggedToWord(map));
+ Node* map_word = BitcastTaggedToWord(map);
+
+ Node* map32 = TruncateIntPtrToInt32(UncheckedCast<IntPtrT>(
+ WordXor(map_word, WordShr(map_word, StubCache::kMapKeyShift))));
// Base the offset on a simple combination of name and map.
Node* hash = Int32Add(hash_field, map32);
uint32_t mask = (StubCache::kPrimaryTableSize - 1)
@@ -2391,17 +2473,18 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
// changes in control flow and logic. We currently have no way of ensuring
// that no frame is constructed, so it's easy to break this optimization by
// accident.
- Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
+ Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred),
+ no_feedback(this, Label::kDeferred);
- GotoIf(IsUndefined(p->vector), &miss);
+ Node* recv_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsDeprecatedMap(recv_map), &miss);
+
+ GotoIf(IsUndefined(p->vector), &no_feedback);
// Inlined fast path.
{
Comment("LoadIC_BytecodeHandler_fast");
- Node* recv_map = LoadReceiverMap(p->receiver);
- GotoIf(IsDeprecatedMap(recv_map), &miss);
-
TVARIABLE(MaybeObject, var_handler);
Label try_polymorphic(this), if_handler(this, &var_handler);
@@ -2418,7 +2501,7 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
GetHeapObjectIfStrong(feedback, &miss);
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &stub_call);
HandlePolymorphicCase(recv_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
}
@@ -2434,6 +2517,15 @@ void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
p->receiver, p->name, p->slot, p->vector);
}
+ BIND(&no_feedback);
+ {
+ Comment("LoadIC_BytecodeHandler_nofeedback");
+ // Call into the stub that implements the non-inlined parts of LoadIC.
+ exit_point->ReturnCallStub(
+ Builtins::CallableFor(isolate(), Builtins::kLoadIC_Uninitialized),
+ p->context, p->receiver, p->name, p->slot, p->vector);
+ }
+
BIND(&miss);
{
Comment("LoadIC_BytecodeHandler_miss");
@@ -2469,7 +2561,7 @@ void AccessorAssembler::LoadIC(const LoadICParameters* p) {
Comment("LoadIC_try_polymorphic");
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &non_inlined);
HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&non_inlined);
@@ -2518,20 +2610,61 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
}
}
+// TODO(8860): This check is only required so we can make prototypes fast on
+// the first load. This is not really useful when there is no feedback vector
+// and may not be important when lazily allocating feedback vectors. Once lazy
+// allocation of feedback vectors has landed try to eliminate this check.
+void AccessorAssembler::BranchIfPrototypeShouldbeFast(Node* receiver_map,
+ Label* prototype_not_fast,
+ Label* prototype_fast) {
+ VARIABLE(var_map, MachineRepresentation::kTagged);
+ var_map.Bind(receiver_map);
+ Label loop_body(this, &var_map);
+ Goto(&loop_body);
+
+ BIND(&loop_body);
+ {
+ Node* map = var_map.value();
+ Node* prototype = LoadMapPrototype(map);
+ GotoIf(IsNull(prototype), prototype_fast);
+ TNode<PrototypeInfo> proto_info =
+ LoadMapPrototypeInfo(receiver_map, prototype_not_fast);
+ GotoIf(IsNull(prototype), prototype_not_fast);
+ TNode<Uint32T> flags =
+ LoadObjectField<Uint32T>(proto_info, PrototypeInfo::kBitFieldOffset);
+ GotoIf(Word32Equal(flags, Uint32Constant(0)), prototype_not_fast);
+
+ Node* prototype_map = LoadMap(prototype);
+ var_map.Bind(prototype_map);
+ Goto(&loop_body);
+ }
+}
+
void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
- Label miss(this, Label::kDeferred);
+ Label miss(this, Label::kDeferred),
+ check_if_fast_prototype(this, Label::kDeferred),
+ check_function_prototype(this);
Node* receiver = p->receiver;
GotoIf(TaggedIsSmi(receiver), &miss);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
+ GotoIf(IsUndefined(p->vector), &check_if_fast_prototype);
// Optimistically write the state transition to the vector.
StoreFeedbackVectorSlot(p->vector, p->slot,
LoadRoot(RootIndex::kpremonomorphic_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
StoreWeakReferenceInFeedbackVector(p->vector, p->slot, receiver_map,
kTaggedSize, SMI_PARAMETERS);
+ Goto(&check_function_prototype);
+ BIND(&check_if_fast_prototype);
+ {
+ BranchIfPrototypeShouldbeFast(receiver_map, &miss,
+ &check_function_prototype);
+ }
+
+ BIND(&check_function_prototype);
{
// Special case for Function.prototype load, because it's very common
// for ICs that are only executed once (MyFunc.prototype.foo = ...).
@@ -2551,28 +2684,34 @@ void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
BIND(&miss);
{
+ Label call_runtime(this, Label::kDeferred);
+ GotoIf(IsUndefined(p->vector), &call_runtime);
// Undo the optimistic state transition.
StoreFeedbackVectorSlot(p->vector, p->slot,
LoadRoot(RootIndex::kuninitialized_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+ Goto(&call_runtime);
+ BIND(&call_runtime);
TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
p->slot, p->vector);
}
}
-void AccessorAssembler::LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
+void AccessorAssembler::LoadGlobalIC(Node* vector, Node* slot,
const LazyNode<Context>& lazy_context,
const LazyNode<Name>& lazy_name,
TypeofMode typeof_mode,
ExitPoint* exit_point,
ParameterMode slot_mode) {
Label try_handler(this, Label::kDeferred), miss(this, Label::kDeferred);
- LoadGlobalIC_TryPropertyCellCase(vector, slot, lazy_context, exit_point,
+ GotoIf(IsUndefined(vector), &miss);
+
+ LoadGlobalIC_TryPropertyCellCase(CAST(vector), slot, lazy_context, exit_point,
&try_handler, &miss, slot_mode);
BIND(&try_handler);
- LoadGlobalIC_TryHandlerCase(vector, slot, lazy_context, lazy_name,
+ LoadGlobalIC_TryHandlerCase(CAST(vector), slot, lazy_context, lazy_name,
typeof_mode, exit_point, &miss, slot_mode);
BIND(&miss);
@@ -2655,27 +2794,30 @@ void AccessorAssembler::LoadGlobalIC_TryHandlerCase(
on_nonexistent);
}
-void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
+void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p,
+ LoadAccessMode access_mode) {
ExitPoint direct_exit(this);
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred),
try_polymorphic_name(this, Label::kDeferred),
- miss(this, Label::kDeferred);
+ miss(this, Label::kDeferred), generic(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
GotoIf(IsDeprecatedMap(receiver_map), &miss);
+ GotoIf(IsUndefined(p->vector), &generic);
+
// Check monomorphic case.
TNode<MaybeObject> feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
BIND(&if_handler);
{
- HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
- ICMode::kNonGlobalIC,
- OnNonExistent::kReturnUndefined, kSupportElements);
+ HandleLoadICHandlerCase(
+ p, CAST(var_handler.value()), &miss, &direct_exit, ICMode::kNonGlobalIC,
+ OnNonExistent::kReturnUndefined, kSupportElements, access_mode);
}
BIND(&try_polymorphic);
@@ -2685,20 +2827,26 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
Comment("KeyedLoadIC_try_polymorphic");
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&try_megamorphic);
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
- GotoIfNot(
- WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &try_polymorphic_name);
+ Branch(WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
+ &generic, &try_polymorphic_name);
+ }
+
+ BIND(&generic);
+ {
// TODO(jkummerow): Inline this? Or some of it?
- TailCallBuiltin(Builtins::kKeyedLoadIC_Megamorphic, p->context, p->receiver,
- p->name, p->slot, p->vector);
+ TailCallBuiltin(access_mode == LoadAccessMode::kLoad
+ ? Builtins::kKeyedLoadIC_Megamorphic
+ : Builtins::kKeyedHasIC_Megamorphic,
+ p->context, p->receiver, p->name, p->slot, p->vector);
}
+
BIND(&try_polymorphic_name);
{
// We might have a name in feedback, and a weak fixed array in the next
@@ -2742,16 +2890,20 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
// If the name comparison succeeded, we know we have a weak fixed array
// with at least one map/handler pair.
Node* name = var_name.value();
- TailCallBuiltin(Builtins::kKeyedLoadIC_PolymorphicName, p->context,
- p->receiver, name, p->slot, p->vector);
+ TailCallBuiltin(access_mode == LoadAccessMode::kLoad
+ ? Builtins::kKeyedLoadIC_PolymorphicName
+ : Builtins::kKeyedHasIC_PolymorphicName,
+ p->context, p->receiver, name, p->slot, p->vector);
}
}
BIND(&miss);
{
Comment("KeyedLoadIC_miss");
- TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
- p->name, p->slot, p->vector);
+ TailCallRuntime(access_mode == LoadAccessMode::kLoad
+ ? Runtime::kKeyedLoadIC_Miss
+ : Runtime::kKeyedHasIC_Miss,
+ p->context, p->receiver, p->name, p->slot, p->vector);
}
}
@@ -2834,7 +2986,8 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
-void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p) {
+void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p,
+ LoadAccessMode access_mode) {
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
@@ -2857,22 +3010,23 @@ void AccessorAssembler::KeyedLoadICPolymorphicName(const LoadICParameters* p) {
TNode<MaybeObject> feedback_element =
LoadFeedbackVectorSlot(vector, slot, kTaggedSize, SMI_PARAMETERS);
TNode<WeakFixedArray> array = CAST(feedback_element);
- HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
- 1);
+ HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss);
BIND(&if_handler);
{
ExitPoint direct_exit(this);
- HandleLoadICHandlerCase(p, CAST(var_handler.value()), &miss, &direct_exit,
- ICMode::kNonGlobalIC,
- OnNonExistent::kReturnUndefined, kOnlyProperties);
+ HandleLoadICHandlerCase(
+ p, CAST(var_handler.value()), &miss, &direct_exit, ICMode::kNonGlobalIC,
+ OnNonExistent::kReturnUndefined, kOnlyProperties, access_mode);
}
BIND(&miss);
{
Comment("KeyedLoadIC_miss");
- TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, name, slot,
- vector);
+ TailCallRuntime(access_mode == LoadAccessMode::kLoad
+ ? Runtime::kKeyedLoadIC_Miss
+ : Runtime::kKeyedHasIC_Miss,
+ context, receiver, name, slot, vector);
}
}
@@ -2884,11 +3038,14 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
if_handler_from_stub_cache(this, &var_handler, Label::kDeferred),
try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred),
- try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred);
+ try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred),
+ no_feedback(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
GotoIf(IsDeprecatedMap(receiver_map), &miss);
+ GotoIf(IsUndefined(p->vector), &no_feedback);
+
// Check monomorphic case.
TNode<MaybeObject> feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
@@ -2907,7 +3064,7 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
Comment("StoreIC_try_polymorphic");
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&try_megamorphic);
@@ -2923,12 +3080,17 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
BIND(&try_uninitialized);
{
// Check uninitialized case.
- GotoIfNot(
+ Branch(
WordEqual(strong_feedback, LoadRoot(RootIndex::kuninitialized_symbol)),
- &miss);
+ &no_feedback, &miss);
+ }
+
+ BIND(&no_feedback);
+ {
TailCallBuiltin(Builtins::kStoreIC_Uninitialized, p->context, p->receiver,
p->name, p->value, p->slot, p->vector);
}
+
BIND(&miss);
{
TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
@@ -2937,14 +3099,18 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
}
void AccessorAssembler::StoreGlobalIC(const StoreICParameters* pp) {
- Label if_lexical_var(this), if_property_cell(this);
+ Label if_lexical_var(this), if_heapobject(this);
TNode<MaybeObject> maybe_weak_ref =
LoadFeedbackVectorSlot(pp->vector, pp->slot, 0, SMI_PARAMETERS);
- Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_property_cell);
+ Branch(TaggedIsSmi(maybe_weak_ref), &if_lexical_var, &if_heapobject);
- BIND(&if_property_cell);
+ BIND(&if_heapobject);
{
Label try_handler(this), miss(this, Label::kDeferred);
+ GotoIf(
+ WordEqual(maybe_weak_ref, LoadRoot(RootIndex::kpremonomorphic_symbol)),
+ &miss);
+
CSA_ASSERT(this, IsWeakOrCleared(maybe_weak_ref));
TNode<PropertyCell> property_cell =
CAST(GetHeapObjectAssumeWeak(maybe_weak_ref, &try_handler));
@@ -3065,11 +3231,14 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
Label if_handler(this, &var_handler),
try_polymorphic(this, Label::kDeferred),
try_megamorphic(this, Label::kDeferred),
+ no_feedback(this, Label::kDeferred),
try_polymorphic_name(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
GotoIf(IsDeprecatedMap(receiver_map), &miss);
+ GotoIf(IsUndefined(p->vector), &no_feedback);
+
// Check monomorphic case.
TNode<MaybeObject> feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
@@ -3089,18 +3258,22 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
&try_megamorphic);
HandlePolymorphicCase(receiver_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&try_megamorphic);
{
// Check megamorphic case.
Comment("KeyedStoreIC_try_megamorphic");
- GotoIfNot(
+ Branch(
WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
- &try_polymorphic_name);
+ &no_feedback, &try_polymorphic_name);
+ }
+
+ BIND(&no_feedback);
+ {
TailCallBuiltin(Builtins::kKeyedStoreIC_Megamorphic, p->context,
- p->receiver, p->name, p->value, p->slot, p->vector);
+ p->receiver, p->name, p->value, p->slot);
}
BIND(&try_polymorphic_name);
@@ -3114,7 +3287,7 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p) {
p->vector, p->slot, kTaggedSize, SMI_PARAMETERS);
TNode<WeakFixedArray> array = CAST(feedback_element);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
- &miss, 1);
+ &miss);
}
}
BIND(&miss);
@@ -3136,6 +3309,9 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
Node* array_map = LoadReceiverMap(p->receiver);
GotoIf(IsDeprecatedMap(array_map), &miss);
+
+ GotoIf(IsUndefined(p->vector), &miss);
+
TNode<MaybeObject> feedback =
TryMonomorphicCase(p->slot, p->vector, array_map, &if_handler,
&var_handler, &try_polymorphic);
@@ -3172,7 +3348,7 @@ void AccessorAssembler::StoreInArrayLiteralIC(const StoreICParameters* p) {
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)),
&try_megamorphic);
HandlePolymorphicCase(array_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&try_megamorphic);
@@ -3316,11 +3492,12 @@ void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
Node* context = Parameter(Descriptor::kContext);
ExitPoint direct_exit(this);
- LoadGlobalIC(CAST(vector), slot,
- // lazy_context
- [=] { return CAST(context); },
- // lazy_name
- [=] { return CAST(name); }, typeof_mode, &direct_exit);
+ LoadGlobalIC(
+ vector, slot,
+ // lazy_context
+ [=] { return CAST(context); },
+ // lazy_name
+ [=] { return CAST(name); }, typeof_mode, &direct_exit);
}
void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
@@ -3346,7 +3523,7 @@ void AccessorAssembler::GenerateKeyedLoadIC() {
Node* context = Parameter(Descriptor::kContext);
LoadICParameters p(context, receiver, name, slot, vector);
- KeyedLoadIC(&p);
+ KeyedLoadIC(&p, LoadAccessMode::kLoad);
}
void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
@@ -3398,7 +3575,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_PolymorphicName() {
Node* context = Parameter(Descriptor::kContext);
LoadICParameters p(context, receiver, name, slot, vector);
- KeyedLoadICPolymorphicName(&p);
+ KeyedLoadICPolymorphicName(&p, LoadAccessMode::kLoad);
}
void AccessorAssembler::GenerateStoreGlobalIC() {
@@ -3541,6 +3718,7 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() {
{
Label cont(this);
GotoIf(IsJSObjectInstanceType(type), &cont);
+ GotoIf(InstanceTypeEqual(type, JS_PROXY_TYPE), &call_runtime);
GotoIfNot(IsStringInstanceType(type), &done);
Branch(SmiEqual(LoadStringLengthAsSmi(CAST(source)), SmiConstant(0)), &done,
&call_runtime);
@@ -3549,12 +3727,12 @@ void AccessorAssembler::GenerateCloneObjectIC_Slow() {
GotoIfNot(IsEmptyFixedArray(LoadElements(CAST(source))), &call_runtime);
- ForEachEnumerableOwnProperty(context, map, CAST(source),
- [=](TNode<Name> key, TNode<Object> value) {
- SetPropertyInLiteral(context, result, key,
- value);
- },
- &call_runtime);
+ ForEachEnumerableOwnProperty(
+ context, map, CAST(source), kPropertyAdditionOrder,
+ [=](TNode<Name> key, TNode<Object> value) {
+ SetPropertyInLiteral(context, result, key, value);
+ },
+ &call_runtime);
Goto(&done);
BIND(&call_runtime);
@@ -3575,10 +3753,13 @@ void AccessorAssembler::GenerateCloneObjectIC() {
TVARIABLE(MaybeObject, var_handler);
Label if_handler(this, &var_handler);
Label miss(this, Label::kDeferred), try_polymorphic(this, Label::kDeferred),
- try_megamorphic(this, Label::kDeferred);
+ try_megamorphic(this, Label::kDeferred), slow(this, Label::kDeferred);
TNode<Map> source_map = LoadMap(UncheckedCast<HeapObject>(source));
GotoIf(IsDeprecatedMap(source_map), &miss);
+
+ GotoIf(IsUndefined(vector), &slow);
+
TNode<MaybeObject> feedback = TryMonomorphicCase(
slot, vector, source_map, &if_handler, &var_handler, &try_polymorphic);
@@ -3681,7 +3862,7 @@ void AccessorAssembler::GenerateCloneObjectIC() {
Comment("CloneObjectIC_try_polymorphic");
GotoIfNot(IsWeakFixedArrayMap(LoadMap(strong_feedback)), &try_megamorphic);
HandlePolymorphicCase(source_map, CAST(strong_feedback), &if_handler,
- &var_handler, &miss, 2);
+ &var_handler, &miss);
}
BIND(&try_megamorphic);
@@ -3695,6 +3876,11 @@ void AccessorAssembler::GenerateCloneObjectIC() {
GotoIfNot(
WordEqual(strong_feedback, LoadRoot(RootIndex::kmegamorphic_symbol)),
&miss);
+ Goto(&slow);
+ }
+
+ BIND(&slow);
+ {
TailCallBuiltin(Builtins::kCloneObjectIC_Slow, context, source, flags, slot,
vector);
}
@@ -3711,5 +3897,42 @@ void AccessorAssembler::GenerateCloneObjectIC() {
}
}
+void AccessorAssembler::GenerateKeyedHasIC() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ KeyedLoadIC(&p, LoadAccessMode::kHas);
+}
+
+void AccessorAssembler::GenerateKeyedHasIC_Megamorphic() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* context = Parameter(Descriptor::kContext);
+ // TODO(magardn): implement HasProperty handling in KeyedLoadICGeneric
+ Return(HasProperty(context, receiver, name,
+ HasPropertyLookupMode::kHasProperty));
+}
+
+void AccessorAssembler::GenerateKeyedHasIC_PolymorphicName() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ KeyedLoadICPolymorphicName(&p, LoadAccessMode::kHas);
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h
index 1022d0f160..beed6f655f 100644
--- a/deps/v8/src/ic/accessor-assembler.h
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -44,6 +44,9 @@ class AccessorAssembler : public CodeStubAssembler {
void GenerateStoreGlobalICTrampoline();
void GenerateCloneObjectIC();
void GenerateCloneObjectIC_Slow();
+ void GenerateKeyedHasIC();
+ void GenerateKeyedHasIC_Megamorphic();
+ void GenerateKeyedHasIC_PolymorphicName();
void GenerateLoadGlobalIC(TypeofMode typeof_mode);
void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
@@ -82,7 +85,7 @@ class AccessorAssembler : public CodeStubAssembler {
Node* holder;
};
- void LoadGlobalIC(TNode<FeedbackVector> vector, Node* slot,
+ void LoadGlobalIC(Node* vector, Node* slot,
const LazyNode<Context>& lazy_context,
const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
ExitPoint* exit_point,
@@ -105,6 +108,7 @@ class AccessorAssembler : public CodeStubAssembler {
SloppyTNode<Object> value;
};
+ enum class LoadAccessMode { kLoad, kHas };
enum class ICMode { kNonGlobalIC, kGlobalIC };
enum ElementSupport { kOnlyProperties, kSupportElements };
void HandleStoreICHandlerCase(
@@ -123,8 +127,6 @@ class AccessorAssembler : public CodeStubAssembler {
void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
- void BranchIfStrictMode(Node* vector, Node* slot, Label* if_strict);
-
void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
@@ -155,9 +157,10 @@ class AccessorAssembler : public CodeStubAssembler {
void LoadIC_Uninitialized(const LoadICParameters* p);
- void KeyedLoadIC(const LoadICParameters* p);
+ void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
void KeyedLoadICGeneric(const LoadICParameters* p);
- void KeyedLoadICPolymorphicName(const LoadICParameters* p);
+ void KeyedLoadICPolymorphicName(const LoadICParameters* p,
+ LoadAccessMode access_mode);
void StoreIC(const StoreICParameters* p);
void StoreGlobalIC(const StoreICParameters* p);
void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
@@ -175,26 +178,29 @@ class AccessorAssembler : public CodeStubAssembler {
void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
Label* if_handler,
TVariable<MaybeObject>* var_handler,
- Label* if_miss, int min_feedback_capacity);
+ Label* if_miss);
// LoadIC implementation.
void HandleLoadICHandlerCase(
const LoadICParameters* p, TNode<Object> handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
- ElementSupport support_elements = kOnlyProperties);
+ ElementSupport support_elements = kOnlyProperties,
+ LoadAccessMode access_mode = LoadAccessMode::kLoad);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
SloppyTNode<Smi> smi_handler,
SloppyTNode<Object> handler, Label* miss,
ExitPoint* exit_point,
OnNonExistent on_nonexistent,
- ElementSupport support_elements);
+ ElementSupport support_elements,
+ LoadAccessMode access_mode);
void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
Variable* var_holder, Variable* var_smi_handler,
Label* if_smi_handler, Label* miss,
- ExitPoint* exit_point, ICMode ic_mode);
+ ExitPoint* exit_point, ICMode ic_mode,
+ LoadAccessMode access_mode);
void HandleLoadCallbackProperty(const LoadICParameters* p,
TNode<JSObject> holder,
@@ -213,6 +219,18 @@ class AccessorAssembler : public CodeStubAssembler {
void EmitAccessCheck(Node* expected_native_context, Node* context,
Node* receiver, Label* can_access, Label* miss);
+ void HandleLoadICSmiHandlerLoadNamedCase(
+ const LoadICParameters* 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);
+
+ void HandleLoadICSmiHandlerHasNamedCase(const LoadICParameters* p,
+ Node* holder,
+ TNode<IntPtrT> handler_kind,
+ Label* miss, ExitPoint* exit_point);
+
// LoadGlobalIC implementation.
void LoadGlobalIC_TryPropertyCellCase(
@@ -274,12 +292,14 @@ class AccessorAssembler : public CodeStubAssembler {
const OnFoundOnReceiver& on_found_on_receiver,
Label* miss, ICMode ic_mode);
- Node* GetLanguageMode(Node* vector, Node* slot);
-
Node* PrepareValueForStore(Node* handler_word, Node* holder,
Representation representation, Node* value,
Label* bailout);
+ void BranchIfPrototypeShouldbeFast(Node* receiver_map,
+ Label* prototype_not_fast,
+ Label* prototype_fast);
+
// Extends properties backing store by JSObject::kFieldsAdded elements,
// returns updated properties backing store.
Node* ExtendPropertiesBackingStore(Node* object, Node* index);
@@ -296,9 +316,11 @@ class AccessorAssembler : public CodeStubAssembler {
Label* if_hole, Label* rebox_double,
Variable* var_double_value,
Label* unimplemented_elements_kind, Label* out_of_bounds,
- Label* miss, ExitPoint* exit_point);
+ Label* miss, ExitPoint* exit_point,
+ LoadAccessMode access_mode = LoadAccessMode::kLoad);
void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
Label* miss);
+ TNode<BoolT> IsPropertyDetailsConst(Node* details);
// Stub cache access helpers.
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index 1d9658e118..19ca5a9c6d 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -180,7 +180,7 @@ class LoadHandler final : public DataHandler {
// Decodes the KeyedAccessLoadMode from a {handler}.
static KeyedAccessLoadMode GetKeyedAccessLoadMode(MaybeObject handler);
- OBJECT_CONSTRUCTORS(LoadHandler, DataHandler)
+ OBJECT_CONSTRUCTORS(LoadHandler, DataHandler);
};
// A set of bit fields representing Smi handlers for stores and a HeapObject
@@ -301,7 +301,7 @@ class StoreHandler final : public DataHandler {
int descriptor, FieldIndex field_index,
Representation representation);
- OBJECT_CONSTRUCTORS(StoreHandler, DataHandler)
+ OBJECT_CONSTRUCTORS(StoreHandler, DataHandler);
};
} // namespace internal
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index c607679a2a..b050513adb 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -88,7 +88,7 @@ const char* GetModifier(KeyedAccessStoreMode mode) {
void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_ic_stats) {
if (AddressIsDeoptimizedCode()) return;
- State new_state = nexus()->StateFromFeedback();
+ State new_state = nexus()->ic_state();
TraceIC(type, name, state(), new_state);
}
}
@@ -200,7 +200,7 @@ IC::IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
}
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
DCHECK_IMPLIES(!vector.is_null(), kind_ == nexus_.kind());
- state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.StateFromFeedback();
+ state_ = (vector.is_null()) ? NO_FEEDBACK : nexus_.ic_state();
old_state_ = state_;
}
@@ -216,7 +216,7 @@ JSFunction IC::GetHostFunction() const {
return frame->function();
}
-static void LookupForRead(Isolate* isolate, LookupIterator* it) {
+static void LookupForRead(LookupIterator* it, bool is_has_property) {
for (; it->IsFound(); it->Next()) {
switch (it->state()) {
case LookupIterator::NOT_FOUND:
@@ -227,7 +227,13 @@ static void LookupForRead(Isolate* isolate, LookupIterator* it) {
case LookupIterator::INTERCEPTOR: {
// If there is a getter, return; otherwise loop to perform the lookup.
Handle<JSObject> holder = it->GetHolder<JSObject>();
- if (!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate)) {
+ if (!holder->GetNamedInterceptor()->getter()->IsUndefined(
+ it->isolate())) {
+ return;
+ }
+ if (is_has_property &&
+ !holder->GetNamedInterceptor()->query()->IsUndefined(
+ it->isolate())) {
return;
}
break;
@@ -277,14 +283,13 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) {
if (is_keyed()) {
// Determine whether the failure is due to a name failure.
if (!name->IsName()) return false;
- Name stub_name = nexus()->FindFirstName();
+ Name stub_name = nexus()->GetName();
if (*name != stub_name) return false;
}
return true;
}
-
void IC::UpdateState(Handle<Object> receiver, Handle<Object> name) {
if (state() == NO_FEEDBACK) return;
update_receiver_map(receiver);
@@ -306,7 +311,6 @@ MaybeHandle<Object> IC::TypeError(MessageTemplate index, Handle<Object> object,
THROW_NEW_ERROR(isolate(), NewTypeError(index, key, object), Object);
}
-
MaybeHandle<Object> IC::ReferenceError(Handle<Name> name) {
HandleScope scope(isolate());
THROW_NEW_ERROR(
@@ -429,7 +433,8 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// If the object is undefined or null it's illegal to try to get any
// of its properties; throw a TypeError in that case.
- if (object->IsNullOrUndefined(isolate())) {
+ if (IsAnyHas() ? !object->IsJSReceiver()
+ : object->IsNullOrUndefined(isolate())) {
if (use_ic && state() != PREMONOMORPHIC) {
// Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
@@ -441,7 +446,9 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
if (*name == ReadOnlyRoots(isolate()).iterator_symbol()) {
return Runtime::ThrowIteratorError(isolate(), object);
}
- return TypeError(MessageTemplate::kNonObjectPropertyLoad, object, name);
+ return TypeError(IsAnyHas() ? MessageTemplate::kInvalidInOperatorUse
+ : MessageTemplate::kNonObjectPropertyLoad,
+ object, name);
}
if (MigrateDeprecated(object)) use_ic = false;
@@ -450,9 +457,11 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
JSObject::MakePrototypesFast(object, kStartAtReceiver, isolate());
update_receiver_map(object);
}
- // Named lookup in the object.
+
LookupIterator it(isolate(), object, name);
- LookupForRead(isolate(), &it);
+
+ // Named lookup in the object.
+ LookupForRead(&it, IsAnyHas());
if (name->IsPrivate()) {
if (name->IsPrivateName() && !it.IsFound()) {
@@ -473,6 +482,14 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// Update inline cache and stub cache.
if (use_ic) UpdateCaches(&it);
+ if (IsAnyHas()) {
+ // Named lookup in the object.
+ Maybe<bool> maybe = JSReceiver::HasProperty(&it);
+ if (maybe.IsNothing()) return MaybeHandle<Object>();
+ return maybe.FromJust() ? ReadOnlyRoots(isolate()).true_value_handle()
+ : ReadOnlyRoots(isolate()).false_value_handle();
+ }
+
// Get the property.
Handle<Object> result;
@@ -498,7 +515,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
global->native_context()->script_context_table(), isolate());
ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
+ if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
&lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate(), script_contexts, lookup_result.context_index);
@@ -514,8 +531,9 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
if (use_ic) {
- if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
- lookup_result.slot_index)) {
+ if (nexus()->ConfigureLexicalVarMode(
+ lookup_result.context_index, lookup_result.slot_index,
+ lookup_result.mode == VariableMode::kConst)) {
TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_LoadScriptContextField);
} else {
// Given combination of indices can't be encoded, so use slow stub.
@@ -546,7 +564,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
const MaybeObjectHandle& handler) {
DCHECK(IsHandler(*handler));
if (is_keyed() && state() != RECOMPUTE_HANDLER) {
- if (nexus()->FindFirstName() != *name) return false;
+ if (nexus()->GetName() != *name) return false;
}
Handle<Map> map = receiver_map();
MapHandles maps;
@@ -586,7 +604,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
int number_of_valid_maps =
number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
- if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
+ if (number_of_valid_maps >= FLAG_max_polymorphic_map_count) return false;
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
return false;
}
@@ -595,7 +613,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name,
if (number_of_valid_maps == 1) {
ConfigureVectorState(name, receiver_map(), handler);
} else {
- if (is_keyed() && nexus()->FindFirstName() != *name) return false;
+ if (is_keyed() && nexus()->GetName() != *name) return false;
if (handler_to_overwrite >= 0) {
handlers[handler_to_overwrite] = handler;
if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
@@ -618,7 +636,6 @@ void IC::UpdateMonomorphicIC(const MaybeObjectHandle& handler,
ConfigureVectorState(name, receiver_map(), handler);
}
-
void IC::CopyICToMegamorphicCache(Handle<Name> name) {
MapHandles maps;
MaybeObjectHandles handlers;
@@ -653,7 +670,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
void IC::PatchCache(Handle<Name> name, const MaybeObjectHandle& handler) {
DCHECK(IsHandler(*handler));
// Currently only load and store ICs support non-code handlers.
- DCHECK(IsAnyLoad() || IsAnyStore());
+ DCHECK(IsAnyLoad() || IsAnyStore() || IsAnyHas());
switch (state()) {
case NO_FEEDBACK:
break;
@@ -727,6 +744,7 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
}
StubCache* IC::stub_cache() {
+ DCHECK(!IsAnyHas());
if (IsAnyLoad()) {
return isolate()->load_stub_cache();
} else {
@@ -737,13 +755,15 @@ StubCache* IC::stub_cache() {
void IC::UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
const MaybeObjectHandle& handler) {
- stub_cache()->Set(*name, *map, *handler);
+ if (!IsAnyHas()) {
+ stub_cache()->Set(*name, *map, *handler);
+ }
}
void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
if (V8_LIKELY(!FLAG_runtime_stats)) return;
- if (IsAnyLoad()) {
+ if (IsAnyLoad() || IsAnyHas()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
} else {
DCHECK(IsAnyStore());
@@ -754,22 +774,29 @@ void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
Handle<Object> receiver = lookup->GetReceiver();
ReadOnlyRoots roots(isolate());
- if (receiver->IsString() && *lookup->name() == roots.length_string()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
- return BUILTIN_CODE(isolate(), LoadIC_StringLength);
- }
- if (receiver->IsStringWrapper() && *lookup->name() == roots.length_string()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
- return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
- }
+ // `in` cannot be called on strings, and will always return true for string
+ // wrapper length and function prototypes. The latter two cases are given
+ // LoadHandler::LoadNativeDataProperty below.
+ if (!IsAnyHas()) {
+ if (receiver->IsString() && *lookup->name() == roots.length_string()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_StringLength);
+ return BUILTIN_CODE(isolate(), LoadIC_StringLength);
+ }
+
+ if (receiver->IsStringWrapper() &&
+ *lookup->name() == roots.length_string()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_StringWrapperLength);
+ return BUILTIN_CODE(isolate(), LoadIC_StringWrapperLength);
+ }
- // Use specialized code for getting prototype of functions.
- if (receiver->IsJSFunction() && *lookup->name() == roots.prototype_string() &&
- !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
- Handle<Code> stub;
- TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
- return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
+ // Use specialized code for getting prototype of functions.
+ if (receiver->IsJSFunction() &&
+ *lookup->name() == roots.prototype_string() &&
+ !JSFunction::cast(*receiver)->PrototypeRequiresRuntimeLookup()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_FunctionPrototypeStub);
+ return BUILTIN_CODE(isolate(), LoadIC_FunctionPrototype);
+ }
}
Handle<Map> map = receiver_map();
@@ -1081,24 +1108,66 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver,
}
}
+namespace {
+
+bool AllowConvertHoleElementToUndefined(Isolate* isolate,
+ Handle<Map> receiver_map) {
+ if (receiver_map->IsJSTypedArrayMap()) {
+ // For JSTypedArray we never lookup elements in the prototype chain.
+ return true;
+ }
+
+ // For other {receiver}s we need to check the "no elements" protector.
+ if (isolate->IsNoElementsProtectorIntact()) {
+ if (receiver_map->IsStringMap()) {
+ return true;
+ }
+ if (receiver_map->IsJSObjectMap()) {
+ // For other JSObjects (including JSArrays) we can only continue if
+ // the {receiver}s prototype is either the initial Object.prototype
+ // or the initial Array.prototype, which are both guarded by the
+ // "no elements" protector checked above.
+ Handle<Object> receiver_prototype(receiver_map->prototype(), isolate);
+
+ if (isolate->IsInAnyContext(*receiver_prototype,
+ Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
+ isolate->IsInAnyContext(*receiver_prototype,
+ Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+} // namespace
+
Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
KeyedAccessLoadMode load_mode) {
+ // Has a getter interceptor, or is any has and has a query interceptor.
if (receiver_map->has_indexed_interceptor() &&
- !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
- isolate()) &&
+ (!receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
+ isolate()) ||
+ (IsAnyHas() &&
+ !receiver_map->GetIndexedInterceptor()->query()->IsUndefined(
+ isolate()))) &&
!receiver_map->GetIndexedInterceptor()->non_masking()) {
// TODO(jgruber): Update counter name.
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
- return BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
+ return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIndexedInterceptorIC)
+ : BUILTIN_CODE(isolate(), LoadIndexedInterceptorIC);
}
+
InstanceType instance_type = receiver_map->instance_type();
if (instance_type < FIRST_NONSTRING_TYPE) {
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringDH);
+ if (IsAnyHas()) return BUILTIN_CODE(isolate(), HasIC_Slow);
return LoadHandler::LoadIndexedString(isolate(), load_mode);
}
if (instance_type < FIRST_JS_RECEIVER_TYPE) {
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
- return BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
+ return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow)
+ : BUILTIN_CODE(isolate(), KeyedLoadIC_Slow);
}
if (instance_type == JS_PROXY_TYPE) {
return LoadHandler::LoadProxy(isolate());
@@ -1108,7 +1177,8 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
if (IsSloppyArgumentsElementsKind(elements_kind)) {
// TODO(jgruber): Update counter name.
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
- return BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
+ return IsAnyHas() ? BUILTIN_CODE(isolate(), KeyedHasIC_SloppyArguments)
+ : BUILTIN_CODE(isolate(), KeyedLoadIC_SloppyArguments);
}
bool is_js_array = instance_type == JS_ARRAY_TYPE;
if (elements_kind == DICTIONARY_ELEMENTS) {
@@ -1118,11 +1188,10 @@ Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map,
}
DCHECK(IsFastElementsKind(elements_kind) ||
IsFixedTypedArrayElementsKind(elements_kind));
- // TODO(jkummerow): Use IsHoleyOrDictionaryElementsKind(elements_kind).
bool convert_hole_to_undefined =
- is_js_array && elements_kind == HOLEY_ELEMENTS &&
- *receiver_map ==
- isolate()->raw_native_context()->GetInitialJSArrayMap(elements_kind);
+ (elements_kind == HOLEY_SMI_ELEMENTS ||
+ elements_kind == HOLEY_ELEMENTS) &&
+ AllowConvertHoleElementToUndefined(isolate(), receiver_map);
TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
return LoadHandler::LoadElement(isolate(), elements_kind,
convert_hole_to_undefined, is_js_array,
@@ -1198,46 +1267,39 @@ bool IsOutOfBoundsAccess(Handle<Object> receiver, uint32_t index) {
KeyedAccessLoadMode GetLoadMode(Isolate* isolate, Handle<Object> receiver,
uint32_t index) {
if (IsOutOfBoundsAccess(receiver, index)) {
- if (receiver->IsJSTypedArray()) {
- // For JSTypedArray we never lookup elements in the prototype chain.
+ DCHECK(receiver->IsHeapObject());
+ Handle<Map> receiver_map(Handle<HeapObject>::cast(receiver)->map(),
+ isolate);
+ if (AllowConvertHoleElementToUndefined(isolate, receiver_map)) {
return LOAD_IGNORE_OUT_OF_BOUNDS;
}
-
- // For other {receiver}s we need to check the "no elements" protector.
- if (isolate->IsNoElementsProtectorIntact()) {
- if (receiver->IsString()) {
- // ToObject(receiver) will have the initial String.prototype.
- return LOAD_IGNORE_OUT_OF_BOUNDS;
- }
- if (receiver->IsJSObject()) {
- // For other JSObjects (including JSArrays) we can only continue if
- // the {receiver}s prototype is either the initial Object.prototype
- // or the initial Array.prototype, which are both guarded by the
- // "no elements" protector checked above.
- Handle<Object> receiver_prototype(
- JSObject::cast(*receiver)->map()->prototype(), isolate);
- if (isolate->IsInAnyContext(*receiver_prototype,
- Context::INITIAL_ARRAY_PROTOTYPE_INDEX) ||
- isolate->IsInAnyContext(*receiver_prototype,
- Context::INITIAL_OBJECT_PROTOTYPE_INDEX)) {
- return LOAD_IGNORE_OUT_OF_BOUNDS;
- }
- }
- }
}
return STANDARD_LOAD;
}
} // namespace
-MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
- Handle<Object> key) {
- if (MigrateDeprecated(object)) {
- Handle<Object> result;
+MaybeHandle<Object> KeyedLoadIC::RuntimeLoad(Handle<Object> object,
+ Handle<Object> key) {
+ Handle<Object> result;
+
+ if (IsKeyedLoadIC()) {
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result, Runtime::GetObjectProperty(isolate(), object, key),
Object);
- return result;
+ } else {
+ DCHECK(IsKeyedHasIC());
+ ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
+ Runtime::HasProperty(isolate(), object, key),
+ Object);
+ }
+ return result;
+}
+
+MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
+ Handle<Object> key) {
+ if (MigrateDeprecated(object)) {
+ return RuntimeLoad(object, key);
}
Handle<Object> load_handle;
@@ -1268,11 +1330,7 @@ MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
if (!load_handle.is_null()) return load_handle;
- Handle<Object> result;
- ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
- Runtime::GetObjectProperty(isolate(), object, key),
- Object);
- return result;
+ return RuntimeLoad(object, key);
}
bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
@@ -1357,7 +1415,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
global->native_context()->script_context_table(), isolate());
ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(isolate(), script_contexts, str_name,
+ if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
&lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate(), script_contexts, lookup_result.context_index);
@@ -1376,8 +1434,9 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
bool use_ic = (state() != NO_FEEDBACK) && FLAG_use_ic;
if (use_ic) {
- if (nexus()->ConfigureLexicalVarMode(lookup_result.context_index,
- lookup_result.slot_index)) {
+ if (nexus()->ConfigureLexicalVarMode(
+ lookup_result.context_index, lookup_result.slot_index,
+ lookup_result.mode == VariableMode::kConst)) {
TRACE_HANDLER_STATS(isolate(), StoreGlobalIC_StoreScriptContextField);
} else {
// Given combination of indices can't be encoded, so use slow stub.
@@ -1402,8 +1461,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
if (MigrateDeprecated(object)) {
Handle<Object> result;
ASSIGN_RETURN_ON_EXCEPTION(
- isolate(), result,
- Object::SetProperty(isolate(), object, name, value, language_mode()),
+ isolate(), result, Object::SetProperty(isolate(), object, name, value),
Object);
return result;
}
@@ -1443,8 +1501,7 @@ MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
}
if (use_ic) UpdateCaches(&it, value, store_origin);
- MAYBE_RETURN_NULL(
- Object::SetProperty(&it, value, language_mode(), store_origin));
+ MAYBE_RETURN_NULL(Object::SetProperty(&it, value, store_origin));
return value;
}
@@ -1473,6 +1530,24 @@ 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());
@@ -1814,7 +1889,6 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
}
-
Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
Handle<Map> map, KeyedAccessStoreMode store_mode) {
switch (store_mode) {
@@ -1952,7 +2026,6 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
}
}
-
static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
uint32_t index, Handle<Object> value) {
bool oob_access = IsOutOfBoundsAccess(receiver, index);
@@ -1997,7 +2070,6 @@ static KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
}
}
-
MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
Handle<Object> key,
Handle<Object> value) {
@@ -2008,7 +2080,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), result,
Runtime::SetObjectProperty(isolate(), object, key, value,
- language_mode(), StoreOrigin::kMaybeKeyed),
+ StoreOrigin::kMaybeKeyed),
Object);
return result;
}
@@ -2083,7 +2155,7 @@ MaybeHandle<Object> KeyedStoreIC::Store(Handle<Object> object,
Handle<JSArray>::cast(object)->elements()->IsCowArray();
ASSIGN_RETURN_ON_EXCEPTION(
isolate(), store_handle,
- Runtime::SetObjectProperty(isolate(), object, key, value, language_mode(),
+ Runtime::SetObjectProperty(isolate(), object, key, value,
StoreOrigin::kMaybeKeyed),
Object);
@@ -2129,8 +2201,8 @@ void StoreOwnElement(Isolate* isolate, Handle<JSArray> array,
isolate, array, index, &success, LookupIterator::OWN);
DCHECK(success);
- CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, NONE,
- kThrowOnError)
+ CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(
+ &it, value, NONE, Just(ShouldThrow::kThrowOnError))
.FromJust());
}
} // namespace
@@ -2176,20 +2248,6 @@ void StoreInArrayLiteralIC::Store(Handle<JSArray> array, Handle<Object> index,
// Static IC stub generators.
//
//
-namespace {
-
-// TODO(8580): Compute the language mode lazily to avoid the expensive
-// computation of language mode here.
-LanguageMode GetLanguageMode(Handle<FeedbackVector> vector, Context context) {
- LanguageMode language_mode = vector->shared_function_info()->language_mode();
- if (context->scope_info()->language_mode() > language_mode) {
- return context->scope_info()->language_mode();
- }
- return language_mode;
-}
-
-} // namespace
-
RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(4, args.length());
@@ -2274,7 +2332,7 @@ RUNTIME_FUNCTION(Runtime_LoadGlobalIC_Slow) {
native_context->script_context_table(), isolate);
ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(isolate, script_contexts, name,
+ if (ScriptContextTable::Lookup(isolate, *script_contexts, *name,
&lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate, script_contexts, lookup_result.context_index);
@@ -2334,51 +2392,27 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
- Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
+ Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
Handle<Object> receiver = args.at(3);
Handle<Name> key = args.at<Name>(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
- FeedbackSlotKind kind = vector->GetKind(vector_slot);
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
- if (IsStoreICKind(kind) || IsStoreOwnICKind(kind)) {
- StoreIC ic(isolate, vector, vector_slot, kind, language_mode);
- ic.UpdateState(receiver, key);
- RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
- } else if (IsStoreGlobalICKind(kind)) {
- DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
- receiver = isolate->global_object();
- StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
- ic.UpdateState(receiver, key);
- RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
- } else {
- DCHECK(IsKeyedStoreICKind(kind));
- KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
- ic.UpdateState(receiver, key);
- RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
+
+ // When there is no feedback vector it is OK to use the StoreNamedStrict as
+ // the feedback slot kind. We only need if it is StoreOwnICKind when
+ // installing the handler for storing const properties. This will happen only
+ // when feedback vector is available.
+ FeedbackSlotKind kind = FeedbackSlotKind::kStoreNamedStrict;
+ Handle<FeedbackVector> vector = Handle<FeedbackVector>();
+ if (!maybe_vector->IsUndefined()) {
+ DCHECK(maybe_vector->IsFeedbackVector());
+ vector = Handle<FeedbackVector>::cast(maybe_vector);
+ kind = vector->GetKind(vector_slot);
}
-}
-RUNTIME_FUNCTION(Runtime_StoreICNoFeedback_Miss) {
- HandleScope scope(isolate);
- DCHECK_EQ(5, args.length());
- Handle<Object> value = args.at(0);
- Handle<Object> receiver = args.at(1);
- Handle<Name> key = args.at<Name>(2);
- CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
- CONVERT_INT32_ARG_CHECKED(is_own_property_value, 4);
- NamedPropertyType property_type =
- static_cast<NamedPropertyType>(is_own_property_value);
-
- FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
- ? FeedbackSlotKind::kStoreNamedStrict
- : FeedbackSlotKind::kStoreNamedSloppy;
- if (property_type == NamedPropertyType::kOwn) {
- language_mode = LanguageMode::kStrict;
- kind = FeedbackSlotKind::kStoreOwnNamed;
- }
- StoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
- language_mode);
+ DCHECK(IsStoreICKind(kind) || IsStoreOwnICKind(kind));
+ StoreIC ic(isolate, vector, vector_slot, kind);
+ ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
}
@@ -2393,8 +2427,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind kind = vector->GetKind(vector_slot);
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
- StoreGlobalIC ic(isolate, vector, vector_slot, kind, language_mode);
+ StoreGlobalIC ic(isolate, vector, vector_slot, kind);
Handle<JSGlobalObject> global = isolate->global_object();
ic.UpdateState(global, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
@@ -2402,31 +2435,30 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Miss) {
RUNTIME_FUNCTION(Runtime_StoreGlobalICNoFeedback_Miss) {
HandleScope scope(isolate);
- DCHECK_EQ(3, args.length());
+ DCHECK_EQ(2, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Name> key = args.at<Name>(1);
- CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 2);
- FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
- ? FeedbackSlotKind::kStoreGlobalStrict
- : FeedbackSlotKind::kStoreGlobalSloppy;
- StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
- language_mode);
+ // TODO(mythria): Replace StoreGlobalStrict/Sloppy with StoreNamed.
+ StoreGlobalIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(),
+ FeedbackSlotKind::kStoreGlobalStrict);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(key, value));
}
+// TODO(mythria): Remove Feedback vector and slot. Since they are not used apart
+// from the DCHECK.
RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
- Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
CONVERT_ARG_HANDLE_CHECKED(String, name, 4);
#ifdef DEBUG
{
Handle<Smi> slot = args.at<Smi>(1);
+ Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
FeedbackSlotKind slot_kind = vector->GetKind(vector_slot);
DCHECK(IsStoreGlobalICKind(slot_kind));
@@ -2441,7 +2473,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
native_context->script_context_table(), isolate);
ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(isolate, script_contexts, name,
+ if (ScriptContextTable::Lookup(isolate, *script_contexts, *name,
&lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate, script_contexts, lookup_result.context_index);
@@ -2462,11 +2494,9 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
return *value;
}
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
RETURN_RESULT_OR_FAILURE(
- isolate,
- Runtime::SetObjectProperty(isolate, global, name, value, language_mode,
- StoreOrigin::kMaybeKeyed));
+ isolate, Runtime::SetObjectProperty(isolate, global, name, value,
+ StoreOrigin::kMaybeKeyed));
}
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
@@ -2475,18 +2505,29 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
Handle<Smi> slot = args.at<Smi>(1);
- Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
+ Handle<HeapObject> maybe_vector = args.at<HeapObject>(2);
Handle<Object> receiver = args.at(3);
Handle<Object> key = args.at(4);
-
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
- FeedbackSlotKind kind = vector->GetKind(vector_slot);
+
+ // When the feedback vector is not valid the slot can only be of type
+ // StoreKeyed. Storing in array literals falls back to
+ // StoreInArrayLiterIC_Miss. This function is also used from store handlers
+ // installed in feedback vectors. In such cases, we need to get the kind from
+ // feedback vector slot since the handlers are used for both for StoreKeyed
+ // and StoreInArrayLiteral kinds.
+ FeedbackSlotKind kind = FeedbackSlotKind::kStoreKeyedStrict;
+ Handle<FeedbackVector> vector = Handle<FeedbackVector>();
+ if (!maybe_vector->IsUndefined()) {
+ DCHECK(maybe_vector->IsFeedbackVector());
+ vector = Handle<FeedbackVector>::cast(maybe_vector);
+ kind = vector->GetKind(vector_slot);
+ }
// The elements store stubs miss into this function, but they are shared by
// different ICs.
if (IsKeyedStoreICKind(kind)) {
- KeyedStoreIC ic(isolate, vector, vector_slot, kind, language_mode);
+ KeyedStoreIC ic(isolate, vector, vector_slot, kind);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
@@ -2500,23 +2541,6 @@ RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Miss) {
}
}
-RUNTIME_FUNCTION(Runtime_KeyedStoreICNoFeedback_Miss) {
- HandleScope scope(isolate);
- DCHECK_EQ(4, args.length());
- // Runtime functions don't follow the IC's calling convention.
- Handle<Object> value = args.at(0);
- Handle<Object> receiver = args.at(1);
- Handle<Object> key = args.at(2);
- CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
-
- FeedbackSlotKind kind = (language_mode == LanguageMode::kStrict)
- ? FeedbackSlotKind::kStoreKeyedStrict
- : FeedbackSlotKind::kStoreKeyedSloppy;
- KeyedStoreIC ic(isolate, Handle<FeedbackVector>(), FeedbackSlot(), kind,
- language_mode);
- RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
-}
-
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
@@ -2541,17 +2565,14 @@ RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Miss) {
RUNTIME_FUNCTION(Runtime_KeyedStoreIC_Slow) {
HandleScope scope(isolate);
- DCHECK_EQ(5, args.length());
+ DCHECK_EQ(3, args.length());
// Runtime functions don't follow the IC's calling convention.
Handle<Object> value = args.at(0);
- Handle<FeedbackVector> vector = args.at<FeedbackVector>(2);
- Handle<Object> object = args.at(3);
- Handle<Object> key = args.at(4);
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
+ Handle<Object> object = args.at(1);
+ Handle<Object> key = args.at(2);
RETURN_RESULT_OR_FAILURE(
- isolate,
- Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
- StoreOrigin::kMaybeKeyed));
+ isolate, Runtime::SetObjectProperty(isolate, object, key, value,
+ StoreOrigin::kMaybeKeyed));
}
RUNTIME_FUNCTION(Runtime_StoreInArrayLiteralIC_Slow) {
@@ -2588,11 +2609,9 @@ RUNTIME_FUNCTION(Runtime_ElementsTransitionAndStoreIC_Miss) {
return *value;
} else {
DCHECK(IsKeyedStoreICKind(kind) || IsStoreICKind(kind));
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
RETURN_RESULT_OR_FAILURE(
- isolate,
- Runtime::SetObjectProperty(isolate, object, key, value, language_mode,
- StoreOrigin::kMaybeKeyed));
+ isolate, Runtime::SetObjectProperty(isolate, object, key, value,
+ StoreOrigin::kMaybeKeyed));
}
}
@@ -2734,22 +2753,18 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
Handle<AccessorInfo> info = args.at<AccessorInfo>(2);
Handle<Name> name = args.at<Name>(3);
Handle<Object> value = args.at(4);
- CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 5);
HandleScope scope(isolate);
if (V8_UNLIKELY(FLAG_runtime_stats)) {
RETURN_RESULT_OR_FAILURE(
- isolate,
- Runtime::SetObjectProperty(isolate, receiver, name, value,
- language_mode, StoreOrigin::kMaybeKeyed));
+ isolate, Runtime::SetObjectProperty(isolate, receiver, name, value,
+ StoreOrigin::kMaybeKeyed));
}
DCHECK(info->IsCompatibleReceiver(*receiver));
- ShouldThrow should_throw =
- is_sloppy(language_mode) ? kDontThrow : kThrowOnError;
PropertyCallbackArguments arguments(isolate, info->data(), *receiver, *holder,
- should_throw);
+ Nothing<ShouldThrow>());
arguments.CallAccessorSetter(info, name, value);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
return *value;
@@ -2765,7 +2780,7 @@ RUNTIME_FUNCTION(Runtime_LoadCallbackProperty) {
DCHECK(info->IsCompatibleReceiver(*receiver));
PropertyCallbackArguments custom_args(isolate, info->data(), *receiver,
- *holder, kThrowOnError);
+ *holder, Just(kThrowOnError));
Handle<Object> result = custom_args.CallAccessorGetter(info, name);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
if (result.is_null()) return ReadOnlyRoots(isolate).undefined_value();
@@ -2813,7 +2828,7 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
Handle<InterceptorInfo> interceptor(holder->GetNamedInterceptor(), isolate);
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
- *holder, kDontThrow);
+ *holder, Just(kDontThrow));
Handle<Object> result = arguments.CallNamedGetter(interceptor, name);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
@@ -2848,7 +2863,6 @@ RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
isolate, NewReferenceError(MessageTemplate::kNotDefined, it.name()));
}
-
RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
HandleScope scope(isolate);
DCHECK_EQ(5, args.length());
@@ -2859,7 +2873,6 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
Handle<JSObject> receiver = args.at<JSObject>(3);
Handle<Name> name = args.at<Name>(4);
FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
- LanguageMode language_mode = GetLanguageMode(vector, isolate->context());
// TODO(ishell): Cache interceptor_holder in the store handler like we do
// for LoadHandler::kInterceptor case.
@@ -2876,7 +2889,7 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
DCHECK(!interceptor->non_masking());
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
- *receiver, kDontThrow);
+ *receiver, Just(kDontThrow));
Handle<Object> result = arguments.CallNamedSetter(interceptor, name, value);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
@@ -2892,13 +2905,11 @@ RUNTIME_FUNCTION(Runtime_StorePropertyWithInterceptor) {
DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
it.Next();
- MAYBE_RETURN(
- Object::SetProperty(&it, value, language_mode, StoreOrigin::kNamed),
- ReadOnlyRoots(isolate).exception());
+ MAYBE_RETURN(Object::SetProperty(&it, value, StoreOrigin::kNamed),
+ ReadOnlyRoots(isolate).exception());
return *value;
}
-
RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
// TODO(verwaest): This should probably get the holder and receiver as input.
HandleScope scope(isolate);
@@ -2909,7 +2920,7 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
isolate);
PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
- *receiver, kDontThrow);
+ *receiver, Just(kDontThrow));
Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
@@ -2924,5 +2935,61 @@ RUNTIME_FUNCTION(Runtime_LoadElementWithInterceptor) {
return *result;
}
+
+RUNTIME_FUNCTION(Runtime_KeyedHasIC_Miss) {
+ HandleScope scope(isolate);
+ DCHECK_EQ(4, args.length());
+ // Runtime functions don't follow the IC's calling convention.
+ Handle<Object> receiver = args.at(0);
+ Handle<Object> key = args.at(1);
+ Handle<Smi> slot = args.at<Smi>(2);
+ Handle<HeapObject> maybe_vector = args.at<HeapObject>(3);
+
+ Handle<FeedbackVector> vector = Handle<FeedbackVector>();
+ if (!maybe_vector->IsUndefined()) {
+ DCHECK(maybe_vector->IsFeedbackVector());
+ vector = Handle<FeedbackVector>::cast(maybe_vector);
+ }
+ FeedbackSlot vector_slot = FeedbackVector::ToSlot(slot->value());
+ KeyedLoadIC ic(isolate, vector, vector_slot, FeedbackSlotKind::kHasKeyed);
+ ic.UpdateState(receiver, key);
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
+}
+
+RUNTIME_FUNCTION(Runtime_HasElementWithInterceptor) {
+ HandleScope scope(isolate);
+ Handle<JSObject> receiver = args.at<JSObject>(0);
+ DCHECK_GE(args.smi_at(1), 0);
+ uint32_t index = args.smi_at(1);
+
+ Handle<InterceptorInfo> interceptor(receiver->GetIndexedInterceptor(),
+ isolate);
+ PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
+ *receiver, Just(kDontThrow));
+
+ if (!interceptor->query()->IsUndefined(isolate)) {
+ Handle<Object> result = arguments.CallIndexedQuery(interceptor, index);
+ if (!result.is_null()) {
+ int32_t value;
+ CHECK(result->ToInt32(&value));
+ return value == ABSENT ? ReadOnlyRoots(isolate).false_value()
+ : ReadOnlyRoots(isolate).true_value();
+ }
+ } else if (!interceptor->getter()->IsUndefined(isolate)) {
+ Handle<Object> result = arguments.CallIndexedGetter(interceptor, index);
+ if (!result.is_null()) {
+ return ReadOnlyRoots(isolate).true_value();
+ }
+ }
+
+ LookupIterator it(isolate, receiver, index, receiver);
+ DCHECK_EQ(LookupIterator::INTERCEPTOR, it.state());
+ it.Next();
+ Maybe<bool> maybe = JSReceiver::HasProperty(&it);
+ if (maybe.IsNothing()) return ReadOnlyRoots(isolate).exception();
+ return maybe.FromJust() ? ReadOnlyRoots(isolate).true_value()
+ : ReadOnlyRoots(isolate).false_value();
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index 9ed469410f..aa6ccd9c76 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -31,10 +31,6 @@ class IC {
static constexpr int kMaxKeyedPolymorphism = 4;
- // A polymorphic IC can handle at most 4 distinct maps before transitioning
- // to megamorphic state.
- static constexpr int kMaxPolymorphicMapCount = 4;
-
// Construct the IC structure with the given number of extra
// JavaScript frames on the stack.
IC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
@@ -54,6 +50,7 @@ class IC {
state_ = RECOMPUTE_HANDLER;
}
+ bool IsAnyHas() const { return IsKeyedHasIC(); }
bool IsAnyLoad() const {
return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
}
@@ -134,9 +131,10 @@ class IC {
bool IsStoreIC() const { return IsStoreICKind(kind_); }
bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
+ bool IsKeyedHasIC() const { return IsKeyedHasICKind(kind_); }
bool is_keyed() const {
return IsKeyedLoadIC() || IsKeyedStoreIC() ||
- IsStoreInArrayLiteralICKind(kind_);
+ IsStoreInArrayLiteralICKind(kind_) || IsKeyedHasIC();
}
bool ShouldRecomputeHandler(Handle<String> name);
@@ -204,13 +202,12 @@ class IC {
DISALLOW_IMPLICIT_CONSTRUCTORS(IC);
};
-
class LoadIC : public IC {
public:
LoadIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
FeedbackSlotKind kind)
: IC(isolate, vector, slot, kind) {
- DCHECK(IsAnyLoad());
+ DCHECK(IsAnyLoad() || IsAnyHas());
}
static bool ShouldThrowReferenceError(FeedbackSlotKind kind) {
@@ -226,7 +223,8 @@ class LoadIC : public IC {
protected:
virtual Handle<Code> slow_stub() const {
- return BUILTIN_CODE(isolate(), LoadIC_Slow);
+ return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow)
+ : BUILTIN_CODE(isolate(), LoadIC_Slow);
}
// Update the inline cache and the global stub cache based on the
@@ -264,6 +262,9 @@ class KeyedLoadIC : public LoadIC {
Handle<Object> key);
protected:
+ V8_WARN_UNUSED_RESULT MaybeHandle<Object> RuntimeLoad(Handle<Object> object,
+ Handle<Object> key);
+
// receiver is HeapObject because it could be a String or a JSObject
void UpdateLoadElement(Handle<HeapObject> receiver,
KeyedAccessLoadMode load_mode);
@@ -284,17 +285,14 @@ class KeyedLoadIC : public LoadIC {
bool CanChangeToAllowOutOfBounds(Handle<Map> receiver_map);
};
-
class StoreIC : public IC {
public:
StoreIC(Isolate* isolate, Handle<FeedbackVector> vector, FeedbackSlot slot,
- FeedbackSlotKind kind, LanguageMode language_mode)
- : IC(isolate, vector, slot, kind), language_mode_(language_mode) {
+ FeedbackSlotKind kind)
+ : IC(isolate, vector, slot, kind) {
DCHECK(IsAnyStore());
}
- LanguageMode language_mode() const { return language_mode_; }
-
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(
Handle<Object> object, Handle<Name> name, Handle<Object> value,
StoreOrigin store_origin = StoreOrigin::kNamed);
@@ -314,11 +312,6 @@ class StoreIC : public IC {
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
StoreOrigin store_origin);
- // TODO(v8:8580): Instead of storing the language mode, compute it lazily
- // from the closure and context when needed. We only need it when throwing
- // exceptions, so it is OK to be slow.
- LanguageMode language_mode_;
-
private:
MaybeObjectHandle ComputeHandler(LookupIterator* lookup);
@@ -328,9 +321,8 @@ class StoreIC : public IC {
class StoreGlobalIC : public StoreIC {
public:
StoreGlobalIC(Isolate* isolate, Handle<FeedbackVector> vector,
- FeedbackSlot slot, FeedbackSlotKind kind,
- LanguageMode language_mode)
- : StoreIC(isolate, vector, slot, kind, language_mode) {}
+ FeedbackSlot slot, FeedbackSlotKind kind)
+ : StoreIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Name> name,
Handle<Object> value);
@@ -343,10 +335,8 @@ class StoreGlobalIC : public StoreIC {
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
-
enum KeyedStoreIncrementLength { kDontIncrementLength, kIncrementLength };
-
class KeyedStoreIC : public StoreIC {
public:
KeyedAccessStoreMode GetKeyedAccessStoreMode() {
@@ -354,9 +344,8 @@ class KeyedStoreIC : public StoreIC {
}
KeyedStoreIC(Isolate* isolate, Handle<FeedbackVector> vector,
- FeedbackSlot slot, FeedbackSlotKind kind,
- LanguageMode language_mode)
- : StoreIC(isolate, vector, slot, kind, language_mode) {}
+ FeedbackSlot slot, FeedbackSlotKind kind)
+ : StoreIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Store(Handle<Object> object,
Handle<Object> name,
@@ -390,8 +379,7 @@ class StoreInArrayLiteralIC : public KeyedStoreIC {
StoreInArrayLiteralIC(Isolate* isolate, Handle<FeedbackVector> vector,
FeedbackSlot slot)
: KeyedStoreIC(isolate, vector, slot,
- FeedbackSlotKind::kStoreInArrayLiteral,
- LanguageMode::kStrict) {
+ FeedbackSlotKind::kStoreInArrayLiteral) {
DCHECK(IsStoreInArrayLiteralICKind(kind()));
}
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index 2a8bd37130..650007ab1d 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -60,8 +60,7 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
// Helper that is used by the public KeyedStoreGeneric and by SetProperty.
void KeyedStoreGeneric(TNode<Context> context, TNode<Object> receiver,
TNode<Object> key, TNode<Object> value,
- Maybe<LanguageMode> language_mode, TNode<Smi> slot,
- TNode<FeedbackVector> vector);
+ Maybe<LanguageMode> language_mode);
void EmitGenericElementStore(Node* receiver, Node* receiver_map,
Node* instance_type, Node* intptr_index,
@@ -912,29 +911,21 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
BIND(&not_callable);
{
- bool handle_strict = true;
- Label strict(this);
LanguageMode language_mode;
if (maybe_language_mode.To(&language_mode)) {
if (language_mode == LanguageMode::kStrict) {
- Goto(&strict);
- } else {
- handle_strict = false;
- exit_point->Return(p->value);
- }
- } else {
- BranchIfStrictMode(p->vector, p->slot, &strict);
- exit_point->Return(p->value);
- }
-
- if (handle_strict) {
- BIND(&strict);
- {
exit_point->ReturnCallRuntime(
Runtime::kThrowTypeError, p->context,
SmiConstant(MessageTemplate::kNoSetterInCallback), p->name,
var_accessor_holder.value());
+ } else {
+ exit_point->Return(p->value);
}
+ } else {
+ CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
+ SmiConstant(MessageTemplate::kNoSetterInCallback),
+ p->name, var_accessor_holder.value());
+ exit_point->Return(p->value);
}
}
}
@@ -943,28 +934,21 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
if (!ShouldReconfigureExisting()) {
BIND(&readonly);
{
- bool handle_strict = true;
- Label strict(this);
LanguageMode language_mode;
if (maybe_language_mode.To(&language_mode)) {
if (language_mode == LanguageMode::kStrict) {
- Goto(&strict);
+ Node* type = Typeof(p->receiver);
+ ThrowTypeError(p->context, MessageTemplate::kStrictReadOnlyProperty,
+ p->name, type, p->receiver);
} else {
- handle_strict = false;
exit_point->Return(p->value);
}
} else {
- BranchIfStrictMode(p->vector, p->slot, &strict);
+ CallRuntime(Runtime::kThrowTypeErrorIfStrict, p->context,
+ SmiConstant(MessageTemplate::kStrictReadOnlyProperty),
+ p->name, Typeof(p->receiver), p->receiver);
exit_point->Return(p->value);
}
- if (handle_strict) {
- BIND(&strict);
- {
- Node* type = Typeof(p->receiver);
- ThrowTypeError(p->context, MessageTemplate::kStrictReadOnlyProperty,
- p->name, type, p->receiver);
- }
- }
}
}
}
@@ -972,8 +956,7 @@ 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<Object> value, Maybe<LanguageMode> language_mode, TNode<Smi> slot,
- TNode<FeedbackVector> vector) {
+ TNode<Object> value, Maybe<LanguageMode> language_mode) {
TVARIABLE(IntPtrT, var_index);
TVARIABLE(Object, var_unique, key);
Label if_index(this), if_unique_name(this), not_internalized(this),
@@ -999,8 +982,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
BIND(&if_unique_name);
{
Comment("key is unique name");
- StoreICParameters p(context, receiver, var_unique.value(), value, slot,
- vector);
+ StoreICParameters p(context, receiver, var_unique.value(), value, nullptr,
+ nullptr);
ExitPoint direct_exit(this);
EmitGenericPropertyStore(CAST(receiver), receiver_map, &p, &direct_exit,
&slow, language_mode);
@@ -1020,19 +1003,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
{
if (IsKeyedStore()) {
Comment("KeyedStoreGeneric_slow");
- if (language_mode.IsJust()) {
- TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
- value, SmiConstant(language_mode.FromJust()));
- } else {
- TVARIABLE(Smi, var_language_mode, SmiConstant(LanguageMode::kStrict));
- Label call_runtime(this);
- BranchIfStrictMode(vector, slot, &call_runtime);
- var_language_mode = SmiConstant(LanguageMode::kSloppy);
- Goto(&call_runtime);
- BIND(&call_runtime);
- TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
- value, var_language_mode.value());
- }
+ TailCallRuntime(Runtime::kSetKeyedProperty, context, receiver, key,
+ value);
} else {
DCHECK(IsStoreInLiteral());
TailCallRuntime(Runtime::kStoreDataPropertyInLiteral, context, receiver,
@@ -1042,17 +1014,14 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(
}
void KeyedStoreGenericAssembler::KeyedStoreGeneric() {
- typedef StoreWithVectorDescriptor Descriptor;
+ typedef StoreDescriptor Descriptor;
TNode<Object> receiver = CAST(Parameter(Descriptor::kReceiver));
TNode<Object> name = CAST(Parameter(Descriptor::kName));
TNode<Object> value = CAST(Parameter(Descriptor::kValue));
- TNode<Smi> slot = CAST(Parameter(Descriptor::kSlot));
- TNode<FeedbackVector> vector = CAST(Parameter(Descriptor::kVector));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
- KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>(),
- slot, vector);
+ KeyedStoreGeneric(context, receiver, name, value, Nothing<LanguageMode>());
}
void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
@@ -1060,8 +1029,7 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
TNode<Object> key,
TNode<Object> value,
LanguageMode language_mode) {
- KeyedStoreGeneric(context, receiver, key, value, Just(language_mode),
- TNode<Smi>(), TNode<FeedbackVector>());
+ KeyedStoreGeneric(context, receiver, key, value, Just(language_mode));
}
void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
@@ -1074,7 +1042,7 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
- Label miss(this);
+ Label miss(this, Label::kDeferred), store_property(this);
GotoIf(TaggedIsSmi(receiver), &miss);
Node* receiver_map = LoadMap(receiver);
@@ -1084,19 +1052,29 @@ void KeyedStoreGenericAssembler::StoreIC_Uninitialized() {
GotoIf(IsSpecialReceiverInstanceType(instance_type), &miss);
// Optimistically write the state transition to the vector.
+ GotoIf(IsUndefined(vector), &store_property);
StoreFeedbackVectorSlot(vector, slot,
LoadRoot(RootIndex::kpremonomorphic_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+ Goto(&store_property);
- StoreICParameters p(context, receiver, name, value, slot, vector);
- EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
+ BIND(&store_property);
+ {
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ EmitGenericPropertyStore(receiver, receiver_map, &p, &miss);
+ }
BIND(&miss);
{
+ Label call_runtime(this);
// Undo the optimistic state transition.
+ GotoIf(IsUndefined(vector), &call_runtime);
StoreFeedbackVectorSlot(vector, slot,
LoadRoot(RootIndex::kuninitialized_symbol),
SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+ Goto(&call_runtime);
+
+ BIND(&call_runtime);
TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
receiver, name);
}
@@ -1127,7 +1105,7 @@ void KeyedStoreGenericAssembler::SetProperty(TNode<Context> context,
unique_name, value);
} else {
CallRuntime(Runtime::kSetKeyedProperty, context, receiver, unique_name,
- value, SmiConstant(language_mode));
+ value);
}
Goto(&done);
}
diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc
index 8567799f3f..89a34ef80c 100644
--- a/deps/v8/src/ic/stub-cache.cc
+++ b/deps/v8/src/ic/stub-cache.cc
@@ -7,7 +7,7 @@
#include "src/ast/ast.h"
#include "src/base/bits.h"
#include "src/counters.h"
-#include "src/heap/heap.h"
+#include "src/heap/heap-inl.h" // For InYoungGeneration().
#include "src/ic/ic-inl.h"
namespace v8 {
@@ -36,7 +36,8 @@ int StubCache::PrimaryOffset(Name name, Map map) {
// Using only the low bits in 64-bit mode is unlikely to increase the
// risk of collision even if the heap is spread over an area larger than
// 4Gb (and not at all if it isn't).
- uint32_t map_low32bits = static_cast<uint32_t>(map.ptr());
+ uint32_t map_low32bits =
+ static_cast<uint32_t>(map.ptr() ^ (map.ptr() >> kMapKeyShift));
// Base the offset on a simple combination of name and map.
uint32_t key = map_low32bits + field;
return key & ((kPrimaryTableSize - 1) << kCacheIndexShift);
@@ -67,8 +68,8 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name name, Map map,
MaybeObject handler) {
// Validate that the name and handler do not move on scavenge, and that we
// can use identity checks instead of structural equality checks.
- DCHECK(!Heap::InNewSpace(name));
- DCHECK(!Heap::InNewSpace(handler));
+ DCHECK(!Heap::InYoungGeneration(name));
+ DCHECK(!Heap::InYoungGeneration(handler));
DCHECK(name->IsUniqueName());
DCHECK(name->HasHashCode());
if (handler->ptr() != kNullAddress) DCHECK(IC::IsHandler(handler));
diff --git a/deps/v8/src/ic/stub-cache.h b/deps/v8/src/ic/stub-cache.h
index 0b6f9d43d1..7eaa31bd95 100644
--- a/deps/v8/src/ic/stub-cache.h
+++ b/deps/v8/src/ic/stub-cache.h
@@ -89,6 +89,10 @@ class StubCache {
static const int kSecondaryTableBits = 9;
static const int kSecondaryTableSize = (1 << kSecondaryTableBits);
+ // We compute the hash code for a map as follows:
+ // <code> = <address> ^ (<address> >> kMapKeyShift)
+ static const int kMapKeyShift = kPrimaryTableBits + kCacheIndexShift;
+
// Some magic number used in the secondary hash computation.
static const int kSecondaryMagic = 0xb16ca6e5;